بهبود Claude Desktop با سرور MCP

مدل‌های زبانی بزرگ (LLM) مانند Claude اغلب در دسترسی به داده‌های بی‌درنگ با محدودیت‌هایی مواجه هستند. برای غلبه بر این مشکل، می‌توان یک سرور Model Context Protocol (MCP) را پیاده‌سازی کرد تا این شکاف را پر کند و اطلاعات به‌روزی را در اختیار LLMها قرار دهد. این آموزش به تفصیل ساخت یک سرور MCP را شرح می‌دهد که Claude Desktop را قادر می‌سازد تا از طریق API آلفا ونتیج (AlphaVantage API) احساسات خبری سهام، سودآورترین‌ها و متحرک‌های روزانه را بازیابی کند و از این طریق قابلیت‌های تحلیلی آن را افزایش دهد.

راه‌اندازی محیط توسعه

اولین گام شامل پیکربندی محیط توسعه است. برای این منظور از مدیر بسته uv استفاده خواهد شد.

برای macOS یا Linux:

ترمینال خود را باز کنید و دستور زیر را اجرا کنید:

1
curl -fsSL https://astral.sh/uv/install.sh | sh

این اسکریپت uv را در سیستم شما نصب می‌کند. اطمینان حاصل کنید که $HOME/.local/bin در مسیر سیستم شما قرار دارد. پس از نصب، با اجرای دستور زیر تأیید کنید که uv به درستی نصب شده است:

1
uv --version

اگر uv با موفقیت نصب شده باشد، نسخه آن را نشان می‌دهد.

ساخت یک محیط پایتون

پس از نصب uv، یک محیط پایتون جدید برای پروژه خود ایجاد کنید. به دایرکتوری که می‌خواهید پروژه خود را در آن میزبانی کنید بروید و دستورات زیر را اجرا کنید:

1
2
3
4
mkdir claude-mcp
cd claude-mcp
uv venv
source .venv/bin/activate

این دستورات یک دایرکتوری به نام claude-mcp ایجاد می‌کند، به آن دایرکتوری می‌رود، یک محیط مجازی با استفاده از uv ایجاد می‌کند و آن محیط را فعال می‌کند.

نصب وابستگی‌ها

با فعال بودن محیط مجازی، وابستگی‌های لازم را نصب کنید. یک فایل requirements.txt ایجاد کنید و وابستگی‌های زیر را اضافه کنید:

1
2
3
4
fastapi==0.109.2
uvicorn==0.30.1
python-dotenv==1.0.1
requests==2.31.0

سپس دستور زیر را برای نصب این وابستگی‌ها اجرا کنید:

1
uv pip install -r requirements.txt

این دستور تمام بسته‌های ذکر شده در فایل requirements.txt را نصب می‌کند.

تنظیم متغیرهای محیطی

برای ایمن نگه داشتن کلید API آلفا ونتیج و سایر تنظیمات حساس، از متغیرهای محیطی استفاده کنید. یک فایل .env در دایرکتوری پروژه خود ایجاد کنید و متغیرهای زیر را اضافه کنید:

1
ALPHAVANTAGE_API_KEY=YOUR_ALPHAVANTAGE_API_KEY

مقدار YOUR_ALPHAVANTAGE_API_KEY را با کلید API واقعی آلفا ونتیج خود جایگزین کنید.

ساخت سرور MCP

حالا که محیط توسعه راه‌اندازی شد، ساخت سرور MCP را آغاز کنید.

ساختار فایل

در اینجا ساختار فایل پیشنهادی برای پروژه شما وجود دارد:

1
2
3
4
5
6
claude-mcp/
├── .venv/
├── .env
├── main.py
├── requirements.txt
└── utils.py

پیاده‌سازی API آلفا ونتیج

ابتدا، یک فایل utils.py ایجاد کنید تا با API آلفا ونتیج تعامل داشته باشید. این فایل شامل توابعی برای بازیابی احساسات خبری سهام، سودآورترین‌ها و متحرک‌های روزانه است.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# utils.py
import requests
import os
from dotenv import load_dotenv

load_dotenv()

ALPHA_VANTAGE_API_KEY = os.getenv("ALPHAVANTAGE_API_KEY")
BASE_URL = "https://www.alphavantage.co/query"

def get_stock_sentiment(symbol: str):
"""بازیابی احساسات خبری سهام از آلفا ونتیج."""
params = {
"function": "NEWS_SENTIMENT",
"tickers": symbol,
"apikey": ALPHA_VANTAGE_API_KEY,
"sort": "latest"
}
try:
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
data = response.json()
news = data.get('feed', [])
if news:
top_news = news[:5] # Get top 5 news items
sentiment_scores = [item['sentiment_score'] for item in top_news]
average_sentiment = sum(float(score) for score in sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0
return {
"symbol": symbol,
"average_sentiment_score": average_sentiment,
"news": [{
"title": item['title'],
"url": item['url'],
"source": item['source'],
"sentiment_score": item['sentiment_score']
} for item in top_news]
}
else:
return {"symbol": symbol, "message": "No news found"}
except requests.exceptions.RequestException as e:
print(f"API Request failed: {e}")
return {"symbol": symbol, "message": f"API Request failed: {e}"}
except (KeyError, ValueError) as e:
print(f"Error processing API response: {e}")
return {"symbol": symbol, "message": f"Error processing API response: {e}"}


def get_top_gainers():
"""بازیابی 10 سودآورترین روزانه."""
params = {
"function": "TOP_GAINERS_LOSERS",
"apikey": ALPHA_VANTAGE_API_KEY
}
try:
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status()
data = response.json()
top_gainers = data.get('top_gainers', [])
return [{
"ticker": item['ticker'],
"price": item['price'],
"change_amount": item['change_amount'],
"change_percentage": item['change_percentage'],
"volume": item['volume']
} for item in top_gainers]
except requests.exceptions.RequestException as e:
print(f"API Request failed: {e}")
return {"message": f"API Request failed: {e}"}
except (KeyError, ValueError) as e:
print(f"Error processing API response: {e}")
return {"message": f"Error processing API response: {e}"}

def get_top_losers():
"""بازیابی 10 بازنده برتر روزانه."""
params = {
"function": "TOP_GAINERS_LOSERS",
"apikey": ALPHA_VANTAGE_API_KEY
}
try:
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status()
data = response.json()
top_losers = data.get('top_losers', [])
return [{
"ticker": item['ticker'],
"price": item['price'],
"change_amount": item['change_amount'],
"change_percentage": item['change_percentage'],
"volume": item['volume']
} for item in top_losers]
except requests.exceptions.RequestException as e:
print(f"API Request failed: {e}")
return {"message": f"API Request failed: {e}"}
except (KeyError, ValueError) as e:
print(f"Error processing API response: {e}")
return {"message": f"Error processing API response: {e}"}

def get_most_active():
"""بازیابی 10 سهام پرطرفدار."""
params = {
"function": "TOP_GAINERS_LOSERS",
"apikey": ALPHA_VANTAGE_API_KEY
}
try:
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status()
data = response.json()
most_active = data.get('most_active', [])
return [{
"ticker": item['ticker'],
"price": item['price'],
"change_amount": item['change_amount'],
"change_percentage": item['change_percentage'],
"volume": item['volume']
} for item in most_active]
except requests.exceptions.RequestException as e:
print(f"API Request failed: {e}")
return {"message": f"API Request failed: {e}"}
except (KeyError, ValueError) as e:
print(f"Error processing API response: {e}")
return {"message": f"Error processing API response: {e}"}

این فایل توابعی را ارائه می‌دهد که با API آلفا ونتیج ارتباط برقرار می‌کنند و احساسات خبری سهام، سودآورترین‌ها و متحرک‌های روزانه را بازیابی می‌کنند. تابع get_stock_sentiment احساسات خبری را برای یک نماد سهام مشخص بازیابی می‌کند و نمرات احساسات متوسط و اطلاعات مربوط به اخبار را برمی‌گرداند. توابع get_top_gainers، get_top_losers و get_most_active داده‌های مربوط به سودآورترین‌ها، بازنده‌های برتر و سهام پرطرفدار را به ترتیب برمی‌گرداند. هر تابع شامل مدیریت خطا برای API درخواست‌ها و پاسخ‌ها است.

ساخت سرور FastAPI

اکنون، سرور FastAPI را در فایل main.py ایجاد کنید. این سرور نقاط پایانی را تعریف می‌کند که از LLM Claude برای بازیابی داده‌های مالی استفاده می‌شود.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# main.py
from fastapi import FastAPI, HTTPException
from utils import get_stock_sentiment, get_top_gainers, get_top_losers, get_most_active

app = FastAPI()

@app.get("/stock_sentiment/{symbol}")
async def stock_sentiment(symbol: str):
"""بازیابی احساسات خبری سهام برای یک نماد."""
result = get_stock_sentiment(symbol)
if "message" in result:
raise HTTPException(status_code=404, detail=result["message"])
return result

@app.get("/top_gainers")
async def top_gainers():
"""بازیابی 10 سودآورترین روزانه."""
result = get_top_gainers()
if "message" in result:
raise HTTPException(status_code=500, detail=result["message"])
return result

@app.get("/top_losers")
async def top_losers():
"""بازیابی 10 بازنده برتر روزانه."""
result = get_top_losers()
if "message" in result:
raise HTTPException(status_code=500, detail=result["message"])
return result

@app.get("/most_active")
async def most_active():
"""بازیابی 10 سهام پرطرفدار."""
result = get_most_active()
if "message" in result:
raise HTTPException(status_code=500, detail=result["message"])
return result

این فایل یک برنامه FastAPI ایجاد می‌کند و چهار نقطه پایانی را تعریف می‌کند:

  • /stock_sentiment/{symbol}: احساسات خبری سهام را برای یک نماد مشخص بازیابی می‌کند.
  • /top_gainers: 10 سودآورترین روزانه را بازیابی می‌کند.
  • /top_losers: 10 بازنده برتر روزانه را بازیابی می‌کند.
  • /most_active: 10 سهام پرطرفدار را بازیابی می‌کند.

هر نقطه پایانی با استفاده از توابع تعریف شده در فایل utils.py، داده‌های مربوطه را بازیابی می‌کند. اگر خطایی رخ دهد، یک استثنای HTTP با کد وضعیت مناسب و پیام جزئیات ایجاد می‌کند.

اجرای سرور MCP

برای اجرای سرور MCP، از دستور زیر استفاده کنید:

1
uvicorn main:app --reload

این دستور سرور Uvicorn را در فایل main.py با نام برنامه app آغاز می‌کند. پرچم --reload سرور را قادر می‌سازد تا به طور خودکار با تغییرات کد بازخوانی شود.

پس از اجرای سرور، می‌توانید با رفتن به این آدرس‌ها در مرورگر خود یا استفاده از یک ابزار مانند curl، نقاط پایانی را آزمایش کنید:

  • http://localhost:8000/stock_sentiment/AAPL
  • http://localhost:8000/top_gainers
  • http://localhost:8000/top_losers
  • http://localhost:8000/most_active

یکپارچه‌سازی با Claude Desktop

برای یکپارچه‌سازی سرور MCP با Claude Desktop، باید به Claude دستور دهید که چگونه از نقاط پایانی API برای بازیابی داده‌های مالی استفاده کند. می‌توانید این کار را با ارائه دستورالعمل‌ها و نمونه‌هایی در درخواست خود به Claude انجام دهید.

در اینجا یک مثال از نحوه استفاده از سرور MCP برای بازیابی احساسات خبری سهام برای نماد AAPL وجود دارد:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
User: What is the sentiment for AAPL stock?

Claude: I can retrieve the sentiment for AAPL stock by calling the /stock_sentiment/AAPL endpoint on the MCP server. Would you like me to do that?

User: Yes, please.

Claude (after calling the API): The average sentiment score for AAPL is 0.75. The top news articles are:
- Title: Apple Announces New iPhone
URL: https://example.com/apple-new-iphone
Source: Example News
Sentiment Score: 0.8
- Title: Apple Stock Surges on Strong Earnings
URL: https://example.com/apple-stock-surges
Source: Example News
Sentiment Score: 0.7

به طور مشابه، می‌توانید به Claude دستور دهید که از نقاط پایانی دیگر برای بازیابی سودآورترین‌ها، بازنده‌های برتر و متحرک‌های روزانه استفاده کند.

1
2
3
4
5
6
7
8
9
10
11
12
13
User: What are the top 10 gainers today?

Claude: I can retrieve the top 10 gainers by calling the /top_gainers endpoint on the MCP server. Would you like me to do that?

User: Yes, please.

Claude (after calling the API): Here are the top 10 gainers today:
- Ticker: XYZ
Price: 100.00
Change Amount: 10.00
Change Percentage: 10.00%
Volume: 1000000
- ...

نکات پیشرفته

رسیدگی به خطا

مدیریت خطا قوی برای اطمینان از اینکه سرور MCP می‌تواند به طور ظریفانه خطاها را مدیریت کند، ضروری است. در فایل utils.py، توابع برای رسیدگی به درخواست‌های API و خطاهای پاسخ پیاده‌سازی می‌شوند. با این حال، می‌توانید بیشتر با افزودن logging، مکانیسم‌های retry و کنترل خطای سفارشی، این را افزایش دهید.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import logging
import requests
import os
from dotenv import load_dotenv
import time

load_dotenv()

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

ALPHA_VANTAGE_API_KEY = os.getenv("ALPHAVANTAGE_API_KEY")
BASE_URL = "https://www.alphavantage.co/query"

def get_stock_sentiment(symbol: str, max_retries=3):
"""بازیابی احساسات خبری سهام از آلفا ونتیج با retry."""
params = {
"function": "NEWS_SENTIMENT",
"tickers": symbol,
"apikey": ALPHA_VANTAGE_API_KEY,
"sort": "latest"
}
for retry in range(max_retries):
try:
response = requests.get(BASE_URL, params=params, timeout=10)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
data = response.json()
news = data.get('feed', [])
if news:
top_news = news[:5] # Get top 5 news items
sentiment_scores = [item['sentiment_score'] for item in top_news]
average_sentiment = sum(float(score) for score in sentiment_scores) / len(sentiment_scores) if sentiment_scores else 0
return {
"symbol": symbol,
"average_sentiment_score": average_sentiment,
"news": [{
"title": item['title'],
"url": item['url'],
"source": item['source'],
"sentiment_score": item['sentiment_score']
} for item in top_news]
}
else:
return {"symbol": symbol, "message": "No news found"}
except requests.exceptions.RequestException as e:
logging.error(f"API Request failed (Retry {retry + 1}/{max_retries}): {e}")
if retry < max_retries - 1:
time.sleep(2 ** retry) # Exponential backoff
else:
return {"symbol": symbol, "message": f"API Request failed after multiple retries: {e}"}
except (KeyError, ValueError) as e:
logging.error(f"Error processing API response: {e}")
return {"symbol": symbol, "message": f"Error processing API response: {e}"}
return {"symbol": symbol, "message": "Failed to retrieve data after multiple retries."}

در این مثال، logging برای ثبت خطاها و اخطارها گنجانده شده است. مکانیسم retry با عقب نشینی نمایی نیز پیاده‌سازی می‌شود، که سعی می‌کند با وقفه‌های طولانی‌تر پس از هر بار شکست خورده، درخواست را دوباره انجام دهد.

بهینه‌سازی عملکرد

برای اطمینان از اینکه سرور MCP می‌تواند حجم زیادی از درخواست‌ها را به طور موثر مدیریت کند، بهینه‌سازی عملکرد بسیار مهم است. چندین استراتژی را می‌توان برای بهبود عملکرد به کار برد:

  • Caching: نتایج API را برای مدت زمان مشخصی کش کنید تا تعداد تماس‌ها با API آلفا ونتیج کاهش یابد.
  • Asynchronous Operations: از عملیات ناهمزمان برای رسیدگی به چندین درخواست به طور همزمان استفاده کنید.
  • Load Balancing: درخواست‌ها را در چندین نمونه سرور توزیع کنید تا load را توزیع کنید.

در اینجا یک مثال از نحوه پیاده‌سازی caching با استفاده از functools.lru_cache وجود دارد:

1
2
3
4
5
6
from functools import lru_cache

@lru_cache(maxsize=128)
def get_stock_sentiment(symbol: str):
"""بازیابی احساسات خبری سهام از آلفا ونتیج با caching."""
# ... (کد API همانطور که قبلاً نشان داده شد)

lru_cache یک دکوراتور است که نتایج تابع را کش می‌کند و تعداد تماس‌ها با API آلفا ونتیج را کاهش می‌دهد. پارامتر maxsize حداکثر تعداد نتایجی را که می‌توان کش کرد، کنترل می‌کند.

احراز هویت و مجوز

برای ایمن نگه داشتن سرور MCP، اجرای احراز هویت و مجوز ضروری است. این تضمین می‌کند که فقط کاربران مجاز می‌توانند به نقاط پایانی API دسترسی داشته باشند. چندین روش را می‌توان برای اجرای احراز هویت و مجوز استفاده کرد:

  • API Keys: برای هر کاربر یک کلید API ارائه دهید و آنها را ملزم کنید که کلید را در درخواست‌های خود درج کنند.
  • OAuth 2.0: از OAuth 2.0 برای احراز هویت کاربران و صدور توکن‌های دسترسی استفاده کنید که می‌توانند برای دسترسی به نقاط پایانی API استفاده شوند.

در اینجا یک مثال از نحوه اجرای احراز هویت کلید API در FastAPI وجود دارد:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import APIKeyHeader

app = FastAPI()
API_KEY = "YOUR_API_KEY" # Replace with a secure method to manage API keys
API_KEY_NAME = "X-API-Key"

api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=True)

async def verify_api_key(api_key: str = Depends(api_key_header)):
if api_key != API_KEY:
raise HTTPException(status_code=401, detail="Invalid API Key")
return api_key

@app.get("/stock_sentiment/{symbol}")
async def stock_sentiment(symbol: str, api_key: str = Depends(verify_api_key)):
"""بازیابی احساسات خبری سهام برای یک نماد."""
result = get_stock_sentiment(symbol)
if "message" in result:
raise HTTPException(status_code=404, detail=result["message"])
return result

در این مثال، یک کلید API با استفاده از هدر X-API-Key مورد نیاز است. تابع verify_api_key کلید ارائه شده را در برابر کلید پیکربندی شده بررسی می‌کند و اگر کلید معتبر نباشد، یک استثنای HTTP ایجاد می‌کند.

استقرار

پس از ساخت و تست سرور MCP، باید آن را در محیط تولید مستقر کنید. چندین گزینه استقرار در دسترس است، از جمله:

  • Cloud Platforms: از پلتفرم‌های ابری مانند AWS، Azure یا Google Cloud Platform برای استقرار سرور MCP استفاده کنید.
  • Docker: از Docker برای containerize کردن سرور MCP استفاده کنید و آن را در هر محیطی که از Docker پشتیبانی می‌کند مستقر کنید.
  • Serverless Functions: از توابع serverless مانند AWS Lambda یا Azure Functions برای استقرار نقاط پایانی API استفاده کنید.

در اینجا یک مثال از نحوه containerize کردن سرور MCP با استفاده از Docker وجود دارد:

  1. یک فایل Dockerfile در دایرکتوری پروژه خود ایجاد کنید:
1
2
3
4
5
6
7
8
9
10
FROM python:3.9-slim-buster

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
  1. یک فایل docker-compose.yml ایجاد کنید:
1
2
3
4
5
6
7
8
version: "3.8"
services:
app:
build: .
ports:
- "8000:8000"
environment:
- ALPHAVANTAGE_API_KEY=${ALPHAVANTAGE_API_KEY}
  1. سرور MCP را بسازید و اجرا کنید:
1
docker-compose up --build

این دستورات یک تصویر Docker از سرور MCP می‌سازند و آن را روی پورت 8000 اجرا می‌کنند. همچنین کلید API آلفا ونتیج را به عنوان یک متغیر محیطی به контейنر منتقل می‌کند.

نتیجه‌گیری

این آموزش چگونگی ساخت یک سرور Model Context Protocol (MCP) را برای افزایش Claude Desktop با بینش‌های مالی بی‌درنگ نشان داده است. این آموزش شامل راه‌اندازی محیط توسعه، پیاده‌سازی API آلفا ونتیج، ساخت سرور FastAPI و یکپارچه‌سازی با Claude Desktop است. علاوه بر این، راهنمایی‌های پیشرفته‌ای در مورد رسیدگی به خطا، بهینه‌سازی عملکرد، احراز هویت و مجوز و استقرار ارائه شده است. با پیروی از این مراحل، می‌توانید Claude Desktop را قادر سازید تا به داده‌های مالی به‌روز دسترسی پیدا کند و توانایی‌های تحلیلی آن را بهبود بخشد.