MCP服务源码分析

简介

MCP 全程为 Model Context Protocol,是由 Anthropic 推出的一个种开放标准,旨在统一大语言模型与外部工具之间的通信协议。其核心目的在于统一工具的注册和发现标准

大模型如何发现工具和实用工具

抛弃官方黑话,用大家都能听懂的话来说就是 LLM 在训练阶段设置了特殊的符号(Special Token)来让模型知道如何使用和调用。

以 ChatGLM 为例,我们查看其针对 LLM 输出的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    def process_response(self, output, history):
        content = ""
        history = deepcopy(history)
        for response in output.split("<|assistant|>"):
            if "\n" in response:
                metadata, content = response.split("\n", maxsplit=1)
            else:
                metadata, content = "", response
            if not metadata.strip():
                content = content.strip()
                history.append({"role": "assistant", "metadata": metadata, "content": content})
                content = content.replace("[[训练时间]]", "2023年")
            else:
                history.append({"role": "assistant", "metadata": metadata, "content": content})
                if history[0]["role"] == "system" and "tools" in history[0]:
                    content = "\n".join(content.split("\n")[1:-1])
                    def tool_call(**kwargs):
                        return kwargs
                    parameters = eval(content)
                    content = {"name": metadata.strip(), "parameters": parameters}
                else:
                    content = {"name": metadata.strip(), "content": content}
        return content, history

可以看到当 system prompt 在设定了有 tools 之后,其会触发工具调用的能力。

具体的官方 Prompt 案例如下,原文跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<|system|>
Answer the following questions as best as you can. You have access to the following tools:
[
    {
        "name": "get_current_weather",
        "description": "Get the current weather in a given location",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "The city and state, e.g. San Francisco, CA",
                },
                "unit": {"type": "string"},
            },
            "required": ["location"],
        },
    }
]
<|user|>
今天北京的天气怎么样?
<|assistant|>
好的,让我们来查看今天的天气
<|assistant|>get_current_weather
```python
tool_call(location="beijing", unit="celsius")

<|observation|> {“temperature”: 22} <|assistant|> 根据查询结果,今天北京的气温为 22 摄氏度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

可以看到,其调用方式就是 LLM 输出 <assistant>tool_name,以及执行代码。执行后,将结果放入 <observation>,至此 functional call 或者说 Agent 能力就结束了。

## MCP Server 核心

由大模型如何使用工具可以看出,其核心应当为提供一个注册发现服务,即函数调用服务。Client 则会按照协议将其解析入 LLM 调用的 Prompt 构建过程之中。

具体是否真的如此呢,我们来拆解一个 MCP Server 就可以知道了,这里我选择 https://github.com/blazickjp/arxiv-mcp-server。

这个服务提供了一系列服务,我们打开 search.py 来看看:

```python
# server.py
@server.call_tool()
async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent]:
    """Handle tool calls for arXiv research functionality."""
    logger.debug(f"Calling tool {name} with arguments {arguments}")
    try:
        if name == "search_papers":
            return await handle_search(arguments)
        elif name == "download_paper":
            return await handle_download(arguments)
        elif name == "list_papers":
            return await handle_list_papers(arguments)
        elif name == "read_paper":
            return await handle_read_paper(arguments)
        else:
            return [types.TextContent(type="text", text=f"Error: Unknown tool {name}")]
    except Exception as e:
        logger.error(f"Tool error: {str(e)}")
        return [types.TextContent(type="text", text=f"Error: {str(e)}")]

# search.py
search_tool = types.Tool(
    name="search_papers",
    description="Search for papers on arXiv with advanced filtering",
    inputSchema={
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "max_results": {"type": "integer"},
            "date_from": {"type": "string"},
            "date_to": {"type": "string"},
            "categories": {"type": "array", "items": {"type": "string"}},
        },
        "required": ["query"],
    },
)

可以看到,其就是人工写好其描述,以及入参定义,这将会用于构建 system prompt。

总结

MCP Server 其实本质是 Anthropic 提出的一个类似于 OpenAI 提出的 functional call 协议的语法糖。其实,仔细看这其实一个 functional call 协议的包皮。但如果形成了一个生态这将让 LLM 的 Agent 能力有了 “过拟合” 的机会,这可能会促进落地。

  • 本文作者: Author:DeamoV
  • Github:https://github.com/Duan-JM
  • Email:vincent.duan95@outlook.com
  • 本文链接: Artical: MCP服务源码分析
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!
  • 版权声明: 原创文章如转载,请注明出处