MCP编程极速入门-stdio通信

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

调试

  1. 执行mcp_server.py

    mcp-quick-start➜  mcp-stdio✗ uv run mcp_server.py
    
  2. 启动Inspector可视化工具

    mcp-quick-start➜  mcp-stdio✗ mcp dev mcp_server.py
    
  3. 具体操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

开发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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值