1. 相关总结
| 总结内容 | 链接 |
|---|---|
| MCP之大模型Function Calling开发与原理 | https://blog.youkuaiyun.com/a82514921/article/details/147860120 |
| MCP概念与server开发及调试-使用Python+SSE传输机制 | https://blog.youkuaiyun.com/a82514921/article/details/147860221 |
| MCP client开发与日志分析-使用Python+SSE传输机制 | https://blog.youkuaiyun.com/a82514921/article/details/147860518 |
| MCP细节与原理分析-使用Python+SSE传输机制 | https://blog.youkuaiyun.com/a82514921/article/details/147860541 |
| MCP server支持在不同Python脚本中实现工具方法 | https://blog.youkuaiyun.com/a82514921/article/details/147860559 |
| MCP client支持同时连接多个MCP server-使用Python开发 | https://blog.youkuaiyun.com/a82514921/article/details/147860587 |
2. 前言
假如使用 Python 开发 MCP client,需要支持同时连接到多个 MCP server,可以参考以下方式
3. 实现方式
3.1. 代码示例
以下示例代码可参考 https://github.com/Adrninistrator/MCP-DEMO
async def query_mcp_server(question: str, parallel: bool):
available_tools = []
tool_session_map: Dict[str, ClientSession] = {}
async with AsyncExitStack() as stack:
for server_url in server_url_array:
read, write = await stack.enter_async_context(sse_client(url=server_url))
session: ClientSession = await stack.enter_async_context(ClientSession(read, write))
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
logger.info(f"MCP Server Tools {server_url} {tools}")
for tool in tools.tools:
if tool.name in tool_session_map:
logger.error(f"重复名称的工具 {tool.name}")
raise ValueError(f"重复名称的工具 {tool.name}")
tool_session_map[tool.name] = session
tool_param: ChatCompletionToolParam = {
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"parameters": tool.inputSchema
}
}
available_tools.append(tool_param)
messages = [{
"role": "system",
"content": "仅使用 role=tool 相关数据进行分析,不使用模型中的数据"
}, {
"role": "user",
"content": f"要求:每次返回选择工具时,在 choices.message.content 返回选择工具的原因、n 任务:{question}"
}]
seq = 0
while True:
seq += 1
response = MCPClientBase.client.chat.completions.create(
model=MCPClientBase.model,
messages=messages,
tools=available_tools,
parallel_tool_calls=parallel
)
assistant_output = response.choices[0].message
if assistant_output.content is None:
assistant_output.content = ""
if response.choices[0].finish_reason != "tool_calls" \
or assistant_output.tool_calls is None \
or len(assistant_output.tool_calls) == 0:
logger.info(f"获得结果:{assistant_output.content}")
return assistant_output.content
messages.append(assistant_output)
tool_seq = 0
for tool_call in assistant_output.tool_calls:
tool_seq += 1
function = tool_call.function
tool_name = function.name
session = tool_session_map[tool_name]
if session is None:
logger.error(f"模型返回的工具不存在 {tool_name}")
raise ValueError(f"模型返回的工具不存在 {tool_name}")
mcp_server_result: CallToolResult = await session.call_tool(tool_name, json.loads(
function.arguments))
if mcp_server_result.isError:
raise ValueError(f"调用 MCP server tool {tool_name} 返回失败")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": mcp_server_result.content
})
if not parallel:
break
3.2. 实现说明
使用数组 available_tools 保存可用的 MCP server 工具
使用类似 Map 结构的 tool_session_map 保存会话对象,key 为 MCP 工具名称,value 为 mcp.client.session.ClientSession 类型的会话对象
遍历需要处理的 MCP server SSE url,对应“for server_url in server_url_array:”
创建 contextlib.AsyncExitStack 类型的对象 stack,用于记录和集中清理需要关闭的异步资源
调用 mcp.client.sse.sse_client() 方法创建的数量为 2 的元组,需要调用 stack 对象对应的 contextlib.AsyncExitStack.enter_async_context() 方法进行记录,以在后续关闭
创建的 mcp.client.session.ClientSession 类型的会话对象,也需要调用以上方法进行记录
在与每个 MCP server 建立连接后,获取到的当前 MCP server 支持的工具信息,记录工具名称及对应的会话对象到 tool_session_map,并记录工具到 available_tools 中
在调用 OpenAI 格式的 Chat Completions API 时,tools 使用以上 available_tools;获取到大模型返回后,遍历大模型选择的需要执行的工具,对于每个工具,根据工具名称从 tool_session_map 中获取对应的会话对象,使用会话对象执行 MCP server 对应的工具
2642

被折叠的 条评论
为什么被折叠?



