模型上下文协议(MCP)实践指南

python SDK :https://github.com/modelcontextprotocol/python-sdk/tree/main?tab=readme-ov-file

官方和社区已经实现的mcp server列表:https://github.com/modelcontextprotocol/servers

编写mcp 服务

python 复制代码
# server.py
from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("Demo")


# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

@mcp.tool()
def mul(a: int, b: int) -> int:
    """Mul two numbers"""
    return a * b


# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"

环境依赖安装(首次开发时需要)

  • step1 : 安装mcp
bash 复制代码
pip install "mcp[cli]"

要求python 大于3.10.

  • step2 测试demo
bash 复制代码
mcp dev server.py

出现下面的错误,

bash 复制代码
[06/10/25 20:14:37] ERROR    npx not found. Please ensure Node.js and npm are properly installed and added to your system PATH. You may need to restart your terminal after installation.                                                               cli.py:308

解决办法是安装相应的依赖

bash 复制代码
sudo apt install nodejs npm

这一步会安装很多很多依赖,需要谨慎操作。

安装完这些依赖后再运行, 还需要安装一个工具@modelcontextprotocol/inspector, 不过这个是自动安装的

bash 复制代码
Need to install the following packages:
  @modelcontextprotocol/inspector
Ok to proceed? (y) y
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@modelcontextprotocol/[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=14.17' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=16.20.0' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>= 18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>= 16' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=16.20.0' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18.0.0' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>= 18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>= 18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>= 18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=14.16' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=16' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=18' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=16' },
npm WARN EBADENGINE   current: { node: 'v12.22.9', npm: '8.5.1' }
npm WARN EBADENGINE }
file:///home/pinefield/.npm/_npx/5a9d879542beca3a/node_modules/@modelcontextprotocol/inspector/cli/build/cli.js:30
    const CLIENT_PORT = process.env.CLIENT_PORT ?? "6274";
                                                 ^

SyntaxError: Unexpected token '?'
    at Loader.moduleStrategy (internal/modules/esm/translators.js:133:18)
    at async link (internal/modules/esm/module_job.js:42:21)
[06/10/25 20:17:54] ERROR    Dev server failed                                

自动安装完后会有一个检查, 上面的检查结果表明刚才安装的依赖的版本都不符合要求, 并且最终程序出错了。

解决办法, 升级node和npm版本, 有2种方式:

1种方式是直接升级:

bash 复制代码
# Remove old version
sudo apt remove nodejs npm

# Install latest LTS
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt-get install -y nodejs

但是通常会遇到网络问题无法完成

另一种方式是使用 Node Version Manager (推荐):

bash 复制代码
# For Linux/macOS
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# Restart terminal, then:
nvm install --lts
nvm use --lts

成功运行结果如下:

bash 复制代码
(leo_py311) pinefield@edge-gpu-01:/data/joyiot/leo/codes/mcp_tutorial$ mcp dev  server.py
Starting MCP inspector...
⚙️ Proxy server listening on port 6277
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀

打开这个页面, 显示如下:

在Claude app 中使用

上面的环境安装是linux环境的。 但是Claude app目前只有Winddows和mac的版本, 没有linux版本。 因此要想在Claude app中使用, 需要在windows上安装环境。 python环境的安装是一样的, 只是nodejs 和npm 的安装不同。 直接在官网下载安装包即可完成安装。

如果想要在Claude app中使用刚才写好的mcp server, 需要执行安装

bash 复制代码
mcp install server.py

安装成功会有如下提示:

然后重启Claude app, 查看mcp设置:

点Edit Config 可以直接打开配置文件。

配置文件如下:

json 复制代码
{
  "mcpServers": {
    "Demo": {
      "command": "E:\\anaconda3\\Scripts\\uv.EXE",
      "args": [
        "run",
        "--with",
        "mcp[cli]",
        "mcp",
        "run",
        "E:\\work\\LLM\\codes\\mcp_tutorial\\server.py"
      ]
    }
  }
}

如果一切正常的话, 可以在Claude app首页看到这样的图标, 这表明mcp server已经被添加好了。

如果电脑上设置了网络代理,可能出现mcp server disconnect 的问题, 这时需要关闭掉代理。 但是如果没有网络代理, 在大陆地区使用不了Claude app, 需要注意设置代理模式。

使用:

当在Claude app中进行对话时, 会自动识别是否需要调用相应服务, 首次使用时会有确认的提示:

之后再调用时, 可能不会再有提示, 但可以通过服务名称查看是否调用了想用了mcp 服务。

如上, 回答中没有显式说明调用了mcp 服务, 但会显示调用的服务名称。

也可以通过mcp 服务的日志查看调用记录:

json 复制代码
2025-06-11T03:15:27.221Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":44,"b":45}},"jsonrpc":"2.0","id":18}
2025-06-11T03:15:27.224Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":18,"result":{"content":[{"type":"text","text":"89"}],"isError":false}}
2025-06-11T03:24:01.129Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":44,"b":45}},"jsonrpc":"2.0","id":19}
2025-06-11T03:24:01.134Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":19,"result":{"content":[{"type":"text","text":"89"}],"isError":false}}
2025-06-11T03:24:25.949Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":44,"b":45}},"jsonrpc":"2.0","id":20}
2025-06-11T03:24:25.954Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":20,"result":{"content":[{"type":"text","text":"89"}],"isError":false}}
2025-06-11T03:24:59.271Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":44,"b":45}},"jsonrpc":"2.0","id":21}
2025-06-11T03:24:59.275Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":21,"result":{"content":[{"type":"text","text":"89"}],"isError":false}}
2025-06-11T03:25:18.461Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":36,"b":89}},"jsonrpc":"2.0","id":22}
2025-06-11T03:25:18.466Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":22,"result":{"content":[{"type":"text","text":"125"}],"isError":false}}
2025-06-11T03:25:20.390Z [info] [Demo] Message from client: {"method":"resources/list","params":{},"jsonrpc":"2.0","id":23}
2025-06-11T03:25:20.395Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":23,"result":{"resources":[]}}
2025-06-11T03:25:20.401Z [info] [Demo] Message from client: {"method":"prompts/list","params":{},"jsonrpc":"2.0","id":24}
2025-06-11T03:25:20.404Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":24,"result":{"prompts":[]}}
2025-06-11T03:25:35.058Z [info] [Demo] Message from client: {"method":"tools/call","params":{"name":"add","arguments":{"a":44,"b":45}},"jsonrpc":"2.0","id":25}
2025-06-11T03:25:35.062Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":25,"result":{"content":[{"type":"text","text":"89"}],"isError":false}}
2025-06-11T03:26:44.476Z [info] [Demo] Message from client: {"method":"tools/list","params":{},"jsonrpc":"2.0","id":26}
2025-06-11T03:26:44.476Z [info] [Demo] Message from client: {"method":"tools/list","params":{},"jsonrpc":"2.0","id":27}
2025-06-11T03:26:44.476Z [info] [Demo] Message from client: {"method":"resources/list","params":{},"jsonrpc":"2.0","id":28}
2025-06-11T03:26:44.483Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":26,"result":{"tools":[{"name":"add","description":"Add two numbers","inputSchema":{"properties":{"a":{"title":"A","type":"integer"},"b":{"title":"B","type":"integer"}},"required":["a","b"],"title":"addArguments","type":"object"}}]}}
2025-06-11T03:26:44.484Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":27,"result":{"tools":[{"name":"add","description":"Add two numbers","inputSchema":{"properties":{"a":{"title":"A","type":"integer"},"b":{"title":"B","type":"integer"}},"required":["a","b"],"title":"addArguments","type":"object"}}]}}
2025-06-11T03:26:44.485Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":28,"result":{"resources":[]}}
2025-06-11T03:26:44.536Z [info] [Demo] Message from client: {"method":"prompts/list","params":{},"jsonrpc":"2.0","id":29}
2025-06-11T03:26:44.540Z [info] [Demo] Message from server: {"jsonrpc":"2.0","id":29,"result":{"prompts":[]}}

日志文件地址: C:\Users\Administrator\AppData\Roaming\Claude\logs