MCP编程极速入门-stdio通信
文章目录
- 关键字
MCP Serve、调试工具 - Inspector、MCP 客户端、stdio、MCP stdio通信、web-search-pro、Resource、Prompt
环境配置
先来通过 uv 初始化我们的项目。
uv 官方文档:https://docs.astral.sh/uv/
# 初始化项目
uv init mcp_getting_started
cd mcp_getting_started
# 创建虚拟环境并进入虚拟环境
uv venv
.venv\Scripts\activate.bat
# 安装依赖
uv add "mcp[cli]" httpx openai
[project]
name = "mcp-quick-start"
version = "0.1.0"
description = "MCP Quick Start Project"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"fastmcp>=2.7.1",
"httpx>=0.28.1",
"mcp[cli]>=1.9.3",
"openai>=1.84.0",
"opik>=1.7.32",
"python-dotenv>=1.1.0",
"zhipuai>=2.1.5.20250526",
"anyio>=4.0.0",
"python-json-logger>=2.0.7"
]
MCP Server
Tools工具
工具一 智谱AI的web-search-pro
"""MCP server implementation with web search and file operations tools."""
import os
import httpx
from dotenv import load_dotenv
from mcp.server import FastMCP
app = FastMCP('web-search')
# Load environment variables
load_dotenv()
ZhipuAI_API_KEY = os.getenv("ZhipuAI_API_KEY")
if not ZhipuAI_API_KEY:
raise ValueError("ZhipuAI_API_KEY environment variable is not set")
@app.tool()
def zhipu_aiweb_search(query: str) -> str:
"""
搜索互联网内容
Args:
query: 要搜索内容
Returns:
搜索结果的总结
"""
if not ZhipuAI_API_KEY:
return "Error: ZhipuAI API key is not configured"
print(f"web_search:{query}")
with httpx.Client() as client:
try:
response = client.post('https://open.bigmodel.cn/api/paas/v4/tools',
headers={'Authorization': ZhipuAI_API_KEY},
json={
'tool': 'web-search-pro',
'messages': [{
'role': 'user',
'content': query
}],
'stream': False
})
response.raise_for_status() # Raise exception for bad status codes
res_data = []
for choice in response.json()['choices']:
for message in choice['message']['tool_calls']:
search_results = message.get('search_result')
if not search_results:
continue
for result in search_results:
res_data.append(result['content'])
return 'aaaa/n/n/n'.join(res_data)
except Exception as e:
return f"Error during web search: {str(e)}"
if __name__ == "__main__":
print("mcp-server!!!")
result = zhipu_aiweb_search("今天上海天气")
print(result)
mcp-server!!!
web_search:今天上海天气
上海当前(2025年06月09日)天气: 阴 22.4摄氏度, 东北风1级, 湿度: 96%, 空气质量: 18.
未来7天天气预报:
(2025年06月09日): 白天:小雨, 最高气温25摄氏度 ,东北风<3级. 夜间:小雨, 最低气温21摄氏度 ,东北风<3级
(2025年06月10日): 白天:小雨, 最高气温26摄氏度 ,北风<3级. 夜间:小雨, 最低气温20摄氏度 ,东北风<3级
(2025年06月11日): 白天:中雨, 最高气温22摄氏度 ,东风<3级. 夜间:中雨, 最低气温20摄氏度 ,东风<3级
(2025年06月12日): 白天:阴, 最高气温26摄氏度 ,东风<3级. 夜间:阴, 最低气温24摄氏度 ,东南风<3级
(2025年06月13日): 白天:阴, 最高气温30摄氏度 ,南风<3级. 夜间:阴, 最低气温23摄氏度 ,西风<3级
(2025年06月14日): 白天:小雨, 最高气温32摄氏度 ,西风<3级. 夜间:小雨, 最低气温24摄氏度 ,南风<3级
(2025年06月15日): 白天:小雨, 最高气温30摄氏度 ,东南风<3级. 夜间:小雨, 最低气温23摄氏度 ,西南风<3级
工具二 自定义工具
"""MCP server implementation with web search and file operations tools."""
import os
from mcp.server import FastMCP
app = FastMCP('web-search')
@app.tool()
def find_file_from_local(query: str) -> str:
"""Find a file from the local file system."""
return f"Found file: {query}"
if __name__ == "__main__":
print("mcp-server!!!")
result = find_file_from_local("今天上海天气")
print(result)
mcp-server!!!
Found file: 今天上海天气
MCP Prompt
@app.prompt('翻译专家')
async def translate_expert(
target_language: str = 'Chinese',
) -> str:
return f'你是一个翻译专家,擅长将任何语言翻译成{target_language}。请翻译以下内容:'
MCP Resource
@app.resource('echo://static')
async def echo_resource():
"""Return a static echo message.
Returns:
A static echo message string.
"""
# 返回的是,当用户使用这个资源时,资源的内容
return 'Echo!'
MCP Server完整代码
"""MCP server implementation with web search and file operations tools."""
import os
import httpx
from dotenv import load_dotenv
from mcp.server import FastMCP
app = FastMCP('web-search')
# Load environment variables
load_dotenv()
ZhipuAI_API_KEY = os.getenv("ZhipuAI_API_KEY")
if not ZhipuAI_API_KEY:
raise ValueError("ZhipuAI_API_KEY environment variable is not set")
@app.tool()
def zhipu_aiweb_search(query: str) -> str:
"""
搜索互联网内容
Args:
query: 要搜索内容
Returns:
搜索结果的总结
"""
if not ZhipuAI_API_KEY:
return "Error: ZhipuAI API key is not configured"
print(f"web_search:{query}")
with httpx.Client() as client:
try:
response = client.post('https://open.bigmodel.cn/api/paas/v4/tools',
headers={'Authorization': ZhipuAI_API_KEY},
json={
'tool': 'web-search-pro',
'messages': [{
'role': 'user',
'content': query
}],
'stream': False
})
response.raise_for_status() # Raise exception for bad status codes
res_data = []
for choice in response.json()['choices']:
for message in choice['message']['tool_calls']:
search_results = message.get('search_result')
if not search_results:
continue
for result in search_results:
res_data.append(result['content'])
return 'aaaa/n/n/n'.join(res_data)
except Exception as e:
return f"Error during web search: {str(e)}"
@app.tool()
def find_file_from_local(query: str) -> str:
"""Find a file from the local file system."""
return f"Found file: {query}"
@app.resource('echo://static')
async def echo_resource():
"""Return a static echo message.
Returns:
A static echo message string.
"""
# 返回的是,当用户使用这个资源时,资源的内容
return 'Echo!'
@app.prompt('翻译专家')
async def translate_expert(
target_language: str = 'Chinese',
) -> str:
return f'你是一个翻译专家,擅长将任何语言翻译成{target_language}。请翻译以下内容:'
if __name__ == "__main__":
app.run(transport='stdio')
MCP Server调试
Inspector可视化工具
核心功能
- 服务器连接管理
-
支持两种通信模式:
-
STDIO 模式(本地进程):通过绑定 Python 进程实现零延迟调试,适合本地文件操作类工具开发,启动命令:
npx @modelcontextprotocol/inspector python server.py mcp dev server.py
-
SSE 模式(远程 HTTP):用于生产环境,支持跨网络调用,需配置 FastAPI/Flask 等 Web 框架,连接命令:
npx @modelcontextprotocol/inspector --url http://localhost:8000/mcp mcp dev server.py --url http://localhost:8000/mcp
-
-
工具测试(Tools Tab)
自动列出所有 @mcp.tool() 注册的工具(如 get_weather)支持输入 JSON 参数实时调用,展示详细响应结果,例如:
{ "method": "tools/call", "params": { "name": "fetch", "arguments": { "url": "https://example.com" } } }
-
资源订阅(Resources Tab)
- 可监控数据库、日志文件等动态资源的实时变更
- 支持自定义触发条件(如数据库记录更新阈值)
-
错误监控(Notifications)
- 实时显示服务器日志,精准定位参数校验失败、工具调用异常等问题
- 支持错误类型分类(如 HTTP 403、Invalid JSON Format)
-
参考资料
GitHub 官方仓库:github.com/modelcontextprotocol/inspector
文档中心:mcp-docs.cn/docs/tools/inspector
调试
-
执行mcp_server.py
mcp-quick-start➜ mcp-stdio✗ uv run mcp_server.py
-
启动Inspector可视化工具
mcp-quick-start➜ mcp-stdio✗ mcp dev mcp_server.py
-
具体操作
开发MCP客户端
MCP客户端代码
"""MCP client implementation for stdio communication with the server."""
import asyncio
import logging
from mcp.client.stdio import stdio_client
from mcp.shared.exceptions import McpError
from mcp import ClientSession, StdioServerParameters
logging.basicConfig(level=logging.INFO)
server_params = StdioServerParameters(
command='uv',
args=['run', 'mcp_server.py'],
)
async def main():
"""Initialize and run the MCP client with stdio communication."""
logging.info("启动客户端...")
try:
async with stdio_client(server_params) as (stdio, write):
logging.info("连接到服务器...")
async with ClientSession(stdio, write) as session:
try:
await session.initialize()
logging.info("会话初始化完成")
# Send ping to check connection
ping_response = await session.send_ping()
logging.info("Ping响应: %s", ping_response)
tools = await session.list_tools()
logging.info("可用工具: %s", tools)
list_prompts = await session.list_prompts()
logging.info("可用Prompts: %s", list_prompts)
list_resources = await session.list_resources()
logging.info("可用resourcess: %s", list_resources)
response = await session.call_tool('zhipu_aiweb_search', {'query': '今天杭州天气'})
logging.info("搜索结果: %s", response)
except (McpError, ConnectionError, RuntimeError) as e:
logging.error("会话错误: %s", e)
finally:
await session.close()
logging.info("会话已关闭")
except McpError as e:
logging.error("连接错误: %s", e)
except ConnectionError:
logging.error("无法连接到服务器,请检查服务器是否运行。")
except RuntimeError as e:
logging.error("运行时错误: %s", e)
if __name__ == '__main__':
asyncio.run(main())
执行测试
NFO:root:启动客户端...
INFO:root:连接到服务器...
INFO:root:会话初始化完成
[06/09/25 20:05:21] INFO Processing request of type PingRequest server.py:558
INFO:root:Ping响应: meta=None
INFO Processing request of type ListToolsRequest server.py:558
INFO:root:可用工具: meta=None nextCursor=None tools=[Tool(name='zhipu_aiweb_search', description='\n 搜索互联网内容\n Args:\n query: 要搜索内容\n Returns:\n 搜索结果的总结\n ', inputSchema={'properties': {'query': {'title': 'Query', 'type': 'string'}}, 'required': ['query'], 'title': 'zhipu_aiweb_searchArguments', 'type': 'object'}, annotations=None), Tool(name='find_file_from_local', description='Find a file from the local file system.', inputSchema={'properties': {'query': {'title': 'Query', 'type': 'string'}}, 'required': ['query'], 'title': 'find_file_from_localArguments', 'type': 'object'}, annotations=None)]
INFO Processing request of type ListPromptsRequest server.py:558
INFO:root:可用Prompts: meta=None nextCursor=None prompts=[Prompt(name='翻译专家', description="Generate a prompt for translation to the specified language.\n \n Args:\n target_language: The language to translate to, defaults to 'Chinese'.\n \n Returns:\n A prompt string for translation.\n ", arguments=[PromptArgument(name='target_language', description=None, required=False)])]
INFO Processing request of type ListResourcesRequest server.py:558
INFO:root:可用resourcess: meta=None nextCursor=None resources=[Resource(uri=AnyUrl('echo://static'), name='echo_resource', description='Return a static echo message.\n \n Returns:\n A static echo message string.\n ', mimeType='text/plain', size=None, annotations=None)]
INFO Processing request of type CallToolRequest server.py:558
[06/09/25 20:05:22] INFO HTTP Request: POST https://open.bigmodel.cn/api/paas/v4/tools "HTTP/1.1 200 OK" _client.py:1025
INFO:root:搜索结果: meta=None content=[TextContent(type='text', text='杭州当前(2025年06月09日)天气: 多云 23摄氏度, 西南风1级, 湿度: 95%, 空气质量: 21.\n未来7天天气预报:\n(2025年06月09日): 夜间:小雨, 最低气温23摄氏度 ,东北风<3级\n(2025年06月10日): 白天:中雨, 最高气温27℃摄氏度 ,东北风<3级. 夜间:大雨, 最低气温20摄氏度 ,东北风<3级\n(2025年06月11日): 白天:中雨, 最高气温23℃摄氏度 ,东北风<3级. 夜间:小雨, 最低气温20摄氏度 ,东风<3级\n(2025年06月12日): 白天:小雨, 最高气温28℃摄氏度 ,东风<3级. 夜间:多云, 最低气温21摄氏度 ,南风<3级\n(2025年06月13日): 白天:小雨, 最高气温32℃摄氏度 ,北风<3级. 夜间:多云, 最低气温24摄氏度 ,西风<3级\n(2025年06月14日): 白天:小雨, 最高气温33℃摄氏度 ,南风<3级. 夜间:小雨, 最低气温23摄氏度 ,南风<3级\n(2025年06月15日): 白天:中雨, 最高气温28℃摄氏度 ,北风<3级. 夜间:小雨, 最低气温23摄氏度 ,西南风<3级\n', annotations=None)] isError=False