استفاده از سرورهای MCP با آشا
سرورهای MCP (Model Context Protocol) راهی پرطرفدار برای دادن «ابزار» به مدلهای زبانیاند. در این راهنما ابزارهای یک سرور MCP را به فرمت سازگار با OpenAI تبدیل میکنیم و از همان endpoint استاندارد آشا فراخوانیشان میکنیم — بدون هیچ endpoint اضافه.
سرورهای MCP جایگزینی برای فراخوانی ابزار به سبک «سازگار با OpenAI» محسوب میشوند. با تبدیل تعریف ابزارهای MCP به تعریف ابزارهای سازگار با OpenAI، میتوانید از سرورهای MCP بههمراه درگاه آشا استفاده کنید؛ هرچند پروتکل MCP «داریحالت» (stateful) است و به مدیریت نشست (session) نیاز دارد. مثال زیر از کلاینت رسمی MCP استفاده میکند و با همین وجود نسبتاً پیچیده است.
تعامل با سرورهای MCP پیچیدهتر از فراخوانی یک endpoint REST است. برای اپلیکیشنهای ساده
با فراخوانی ابزار، پیشنهاد میکنیم مستقیماً از پارامتر tools
در endpoint سازگار با OpenAI استفاده کنید و فقط وقتی به سرورهای MCP خاصی نیاز دارید این
راهنما را دنبال کنید.
پیشنیازها و راهاندازی
برای اجرا، اول بستههای زیر را نصب کنید:
pip install mcp openai python-dotenv
سپس فایل .env را با کلید آشا بسازید (قالب
sk-asha-...):
ASHA_API_KEY=sk-asha-...
این مثال فرض میکند کلاینتی هستید که سرور فایلسیستم را با npx
اجرا میکند؛ پس Node.js هم باید نصب باشد. در سیستمعامل مک مسیر
/Applications/ فرض شده — روی ویندوز یا لینوکس آن را
با پوشهٔ دلخواهتان (مثلاً C:UsersyouDocuments
یا /home/you/Documents) جایگزین کنید.
کد اولیه و پیکربندی مدل
import asyncio
from typing import Optional
from contextlib import AsyncExitStack
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from openai import OpenAI
from dotenv import load_dotenv
import json
load_dotenv() # load environment variables from .env
MODEL = "~anthropic/claude-sonnet-latest"
SERVER_CONFIG = {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Applications/",
],
"env": None,
}
شناسهٔ مدل را از فهرست مدلهای آشا انتخاب کنید؛ مدل باید از
پارامتر tools پشتیبانی کند (برای مدلهای چت و کد
برقرار است).
تبدیل ابزارهای MCP به ابزارهای OpenAI
تابع کمکی زیر تعریف ابزار MCP را به تعریف ابزار سازگار با OpenAI تبدیل میکند:
def convert_tool_format(tool):
converted_tool = {
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": {
"type": "object",
"properties": tool.inputSchema["properties"],
"required": tool.inputSchema["required"],
},
},
}
return converted_tool
کلاینتی MCP کامل
و این خودِ کلاینتی است — حدود ۱۰۰ خط ناگزیر. توجه کنید که
SERVER_CONFIG داخل کلاینت ثابت نوشته شده؛ بدیهی است
میتوان آن را برای سرورهای MCP دیگر پارامتریزه کرد. تنها تفاوت این کلاینت با نسخههای دیگر
سرویسها، آدرس base_url است که به
https://app.asha-ai.ir/v1/ تغییر کرده:
class MCPClient:
def __init__(self):
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.openai = OpenAI(
base_url="https://app.asha-ai.ir/v1/"
)
async def connect_to_server(self, server_config):
server_params = StdioServerParameters(**server_config)
stdio_transport = await self.exit_stack.enter_async_context(
stdio_client(server_params)
)
self.stdio, self.write = stdio_transport
self.session = await self.exit_stack.enter_async_context(
ClientSession(self.stdio, self.write)
)
await self.session.initialize()
# List available tools from the MCP server
response = await self.session.list_tools()
print(
"nConnected to server with tools:",
[tool.name for tool in response.tools],
)
self.messages = []
async def process_query(self, query: str) -> str:
self.messages.append({"role": "user", "content": query})
response = await self.session.list_tools()
available_tools = [convert_tool_format(tool) for tool in response.tools]
response = self.openai.chat.completions.create(
model=MODEL,
tools=available_tools,
messages=self.messages,
)
self.messages.append(response.choices[0].message.model_dump())
final_text = []
content = response.choices[0].message
if content.tool_calls is not None:
tool_name = content.tool_calls[0].function.name
tool_args = content.tool_calls[0].function.arguments
tool_args = json.loads(tool_args) if tool_args else {}
# Execute tool call
try:
result = await self.session.call_tool(tool_name, tool_args)
final_text.append(
f"[Calling tool {tool_name} with args {tool_args}]"
)
except Exception as e:
print(f"Error calling tool {tool_name}: {e}")
result = None
self.messages.append(
{
"role": "tool",
"tool_call_id": content.tool_calls[0].id,
"name": tool_name,
"content": result.content,
}
)
response = self.openai.chat.completions.create(
model=MODEL,
max_tokens=1000,
messages=self.messages,
)
final_text.append(response.choices[0].message.content)
else:
final_text.append(content.content)
return "n".join(final_text)
async def chat_loop(self):
"""Run an interactive chat loop"""
print("nMCP Client Started!")
print("Type your queries or 'quit' to exit.")
while True:
try:
query = input("nQuery: ").strip()
result = await self.process_query(query)
print("Result:")
print(result)
except Exception as e:
print(f"Error: {str(e)}")
async def cleanup(self):
await self.exit_stack.aclose()
async def main():
client = MCPClient()
try:
await client.connect_to_server(SERVER_CONFIG)
await client.chat_loop()
finally:
await client.cleanup()
if __name__ == "__main__":
import sys
asyncio.run(main())
اجرا و خروجی
همهٔ کد بالا را در mcp-client.py ذخیره کنید و اجرا
کنید:
% python mcp-client.py
Secure MCP Filesystem Server running on stdio
Allowed directories: [ '/Applications' ]
Connected to server with tools: ['read_file', 'read_multiple_files', 'write_file'...]
MCP Client Started!
Type your queries or 'quit' to exit.
Query: Do I have microsoft office installed?
Result:
[Calling tool list_allowed_directories with args {}]
I can check if Microsoft Office is installed in the Applications folder:
Query: continue
Result:
[Calling tool search_files with args {'path': '/Applications', 'pattern': 'Microsoft'}]
Now let me check specifically for Microsoft Office applications:
Query: continue
Result:
I can see from the search results that Microsoft Office is indeed installed on your system.
The search found the following main Microsoft Office applications:
1. Microsoft Excel - /Applications/Microsoft Excel.app
2. Microsoft PowerPoint - /Applications/Microsoft PowerPoint.app
3. Microsoft Word - /Applications/Microsoft Word.app
4. OneDrive - /Applications/OneDrive.app (which includes Microsoft SharePoint integ...
مدل از طریق آشا تصمیم میگیرد کدام ابزار را صدا بزند، نامها و آرگومانها را تولید میکند، ابزار روی سرور MCP اجرا میشود و نتیجه بهصورت پیام «tool» به مدل برگردانده میشود تا پاسخ نهایی را بنویسد.
چرا با آشا؟
-
بدون endpoint اضافه: همین
/v1/chat/completionsاستاندارد، پارامترtoolsرا بهصورت کامل به سمت مدل عبور میدهد. -
یک کلید برای همهٔ مدلها: فقط
MODELرا عوض کنید تا همین کلاینت روی مدل دیگری از فهرست مدلهای آشا اجرا شود. - صورتحساب به تومان: هزینهٔ توکنها از گزارشِ مصرفِ واقعیِ ارائهدهنده شارژ میشود؛ در داشبورد فعالیت آشا، هر فراخوانی ابزار و تمامِ راندهای رفتوبرگشت را میبینید.
- کیف پول شفاف: بدون کارت خارجی؛ بهاندازهٔ مصرفتان بپردازید و سقف هزینه برای تیم بگذارید.
خطاهای رایج
npx یا Node پیدا نمیشود
Node.js را نصب کنید تا سرور فایلسیستم بتواند با npx اجرا شود.
خطای «No API key» یا خطای احراز هویت
مطمئن شوید ASHA_API_KEY در فایل
.env هست، کلید معتبر است و کیف پول موجودی کافی دارد.
مدل ابزارها را پشتیبانی نمیکند
مدلی انتخاب کنید که پارامتر tools را پشتیبانی میکند
(معمولاً مدلهای چت و کد). اگر پاسخ خطای «invalid parameter» گرفتید، شناسه را با
فهرست مدلها تطبیق دهید.
محتوای غیرمتنی نتیجهٔ ابزار
برخی سرورها نتیجهٔ غیرمتنی (مثل تصویر) برمیگردانند. در این حالت
result.content را قبل از فرستادن به مدل، به متن
قابلاستفاده تبدیل (serialize) کنید.
جمعبندی
سرورهای MCP بههمراه آشا بدون هیچ تغییر سمت سرور کار میکنند: فقط
base_url را روی
https://app.asha-ai.ir/v1/ بگذارید، کلید
sk-asha-... را وارد کنید و ابزارهای MCP را به فرمت
OpenAI تبدیل کنید. برای انتخاب مدل و دیدن قیمتها به مدلهای آشا
سر بزنید.