Contents

MCP 实战:从零开始实现自己的 MCP Server

https://img.lixueduan.com/ai/cover/llm-app-mcp.png

上一篇中介绍了 Agent、Function Calling、MCP 等概念,这篇则分享如何实现自己的 MCP Server,并将其添加到 Cline 进行验证。

1. 什么是 MCP

https://img.lixueduan.com/ai/llm-app/mcp/mcp-clearly-explained.webp

图源:https://blog.dailydoseofds.com/p/visual-guide-to-model-context-protocol

详细概念参考上文: 一文搞懂 Agent&Function Calling&MCP&A2A 是什么

1.1 Model Context Protocol

MCP(Model Context Protocol) 是由 Anthropic 推出的一项开放标准协议,旨在解决不同大模型与不同外部工具集成的标准化问题。官方解释是“其目标是为大型语言模型提供一种开放、标准化的方式,以便与外部数据源、工具和服务进行连接。”

  • 它规定了上下文与请求的结构化传递方式,并要求通信格式符合 JSON-RPC 2.0 标准。

  • 简单理解,MCP 相当于大模型领域的“HTTP 协议”,其并不绑定任何大模型,这意味着用户可以在支持 MCP 的工具中,用任何大模型调用 MCP 服务。

英文版描述:

The Model Context Protocol (MCP) is an open protocol that enables seamless integration between LLM applications and external data sources and tools. Whether you’re building an AI-powered IDE, enhancing a chat interface, or creating custom AI workflows, MCP provides a standardized way to connect LLMs with the context they need.

一句话描述:MCP 是一种开放、标准化的协议,以便大型语言模型能够与外部数据源、工具和服务进行连接。

1.2 General Architecture

架构如下:

https://img.lixueduan.com/ai/llm-app/mcp-general-architecture.png

MCP 涉及到 5 个组件或角色:

  • MCP Hosts: 真正使用 MCP 的程序,例如 Claude Desktop, IDEs 或者其他 AI 工具

  • MCP Clients: 实现 MCP 协议的客户端,维持和 MCP Server 之间的 1:1 连接

  • MCP Servers: 实现 MCP 协议的服务端,通过 MCP 协议公开某些功能,MCP服务器可以提供以下类型的功能:

    1. Resources: 客户端可以读取的类似文件的数据(如API响应或文件内容)

    2. Tools: 工具:可以由LLM调用的函数(经用户批准)

    3. Prompts: 帮助用户完成特定任务的预先编写的模板

  • Local Data Sources: 本地数据源,MCP 服务可以安全访问的本地文件、数据库和其他服务

  • Remote Services: 远程服务,MCP 服务可以连接的外部系统

需要重点关注的就是 MCP Host、MCP Client 以及 MCP Server 三部分,Local Data Sources、Remote Services 可以看做是 MCP Server 自身实现功能的一部分。

  • MCP Host 就是直接跟用户交互的应用程序,例如 Claude,而 MCP Client 一般是直接集成在 MCP Host 里,这样应用程序既可以和用户交互,也可以调用 MCP Server。

  • MCP Server 就是提供 Resources、Tools、 Prompts 等等功能的服务端,可以简单理解为把 Function Calling 中的函数封装为了服务,满足 MCP 标准从而实现功能复用。

2. 实现自己的 MCP Server

作为一个 Gopher,这里选择的是 MCP 的 Go 语言实现:mcp-go 这个库。

2.1 安装

go get github.com/mark3labs/mcp-go

2.2 Stdio 类型 MCP Server

以下是一个简单的 Stdio 类型的 MCP Server,提供了一个名为 calculate 的 tool,接收 x、y 以及 operation 三个参数。

package main

import (
    "context"
    "fmt"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

func main() {
    // Create a new MCP server
    s := server.NewMCPServer(
        "Calculator Demo",
        "1.0.0",
        server.WithToolCapabilities(false),
        server.WithRecovery(),
    )

    // Add a calculator tool
    calculatorTool := mcp.NewTool("calculate",
        mcp.WithDescription("Perform basic arithmetic operations"),
        mcp.WithString("operation",
            mcp.Required(),
            mcp.Description("The operation to perform (add, subtract, multiply, divide)"),
            mcp.Enum("add", "subtract", "multiply", "divide"),
        ),
        mcp.WithNumber("x",
            mcp.Required(),
            mcp.Description("First number"),
        ),
        mcp.WithNumber("y",
            mcp.Required(),
            mcp.Description("Second number"),
        ),
    )

    // Add the calculator handler
    s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        // Using helper functions for type-safe argument access
        op, err := request.RequireString("operation")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }
        
        x, err := request.RequireFloat("x")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }
        
        y, err := request.RequireFloat("y")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }

        var result float64
        switch op {
        case "add":
            result = x + y
        case "subtract":
            result = x - y
        case "multiply":
            result = x * y
        case "divide":
            if y == 0 {
                return mcp.NewToolResultError("cannot divide by zero"), nil
            }
            result = x / y
        }

        return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
    })

    // Start the server
    if err := server.ServeStdio(s); err != nil {
        fmt.Printf("Server error: %v\n", err)
    }
}

接下来就可以开始验证我们的 MCP Server 了。

2.3 SSE 类型 MCP Server

SSE 类型的 MCP Server 和 Stdio 主要区别在 MCP Hosts(MCP Client) 如何与 MCP Server 做交互。

实际上代码很简单,只需要改动一点点:

Stdio 是这样启动服务的

// Start the server
if err := server.ServeStdio(s); err != nil {
    fmt.Printf("Server error: %v\n", err)
}

SSE 则是这样:

// 创建基于 SSE 的服务器实例
sseServer := server.NewSSEServer(s)

// 启动服务器,监听指定端口(如 :8080)
err := sseServer.Start(":8080")
if err != nil {
    panic(err)
}

然后启动服务

go run cmd/main.go

3. MCP Hosts 配置 MCP Server

3.1 安装 Cline

在验证 MCP Server 之前我们先安装一个 MCP Hosts,这里选择的是 Cline,大家也可以选择其他的。

首先在 VS Code 中安装 Cline 插件。

https://img.lixueduan.com/ai/llm-app/mcp/cline-install-1.png

安装之后在侧边栏点击图标即可打开

https://img.lixueduan.com/ai/llm-app/mcp/cline-install-2.png

3.2 配置模型

在 Cline 最下方有一个配置模型的地方,点开填写相关信息即可。

如果没有可用模型,可以到 DeepSeek 官网 注册。

https://img.lixueduan.com/ai/llm-app/mcp/cline-config-model.png

3.3 配置 MCP Server

接下来就开始配置 MCP Server 了,将我们本地跑的 MCP Server 配置到 Cline 里。

在 Cline 中点击服务器图标即,再在弹出窗口中点击齿轮图标即可进入 MCP Server 配置界面

https://img.lixueduan.com/ai/llm-app/mcp/cline-config-mcp1.png

点击 Configure

https://img.lixueduan.com/ai/llm-app/mcp/cline-config-mcp2.png

之后就可以在 json 文件中配置了,我们这里启动的是 Stdio 类型的 MCP Server,也就是输入输出分别使用 Stdin 和 Stdout 的,只需要配置启动命令即可:

先 go build cmd/main.go 即可

{
  "mcpServers": {
    "mymcp": {
      "command": "/Users/lixueduan/17x/projects/i-mcp/cmd/main",
      "args": [
      ],
      "disabled": false,
      "autoApprove": []
    }
  }
}

对于 SSE 类型 MCP Server 则是

{
  "mcpServers": {
    "mymcp": {
      "url": "http://localhost:8080/sse",
      "disabled": false
    }
  }
}

如果出现小绿点则说明 MCP Server 可以正常使用了。

https://img.lixueduan.com/ai/llm-app/mcp/cline-config-mcp3.png

3.4 验证

至此,就可以开始验证 MCP Server 了。

问 Cline 一个问题

帮我计算 1+1

此时 MCP Hosts(Cline) 会自动携带问题和我们 MCP Server 的信息发送给 LLM,然后 LLM 根据思考会得出要调用前面我们配置的 mymcp 这个 MCP Server 中的 名为 calculate 的 tool,参数 x、y 以及 operation 分别是 1、1 和 add。

可以看到,最终的结果和预想的是一致的

https://img.lixueduan.com/ai/llm-app/mcp/cline-mcp-check1.png

我们点击 Approve 之后 Cline 就会去调用 MCP 了。

https://img.lixueduan.com/ai/llm-app/mcp/cline-mcp-check2.png

其中 MCP Server 返回的结果是 2.00,然后模型整合后返回最终的结果为:

The result of 1 + 1 is 2.00

至此,我们就完成了一个 Stdio 类型的 MCP Server 的开发和验证。

4. MCP 工作流程

整个工作流程如下图所示:

https://img.lixueduan.com/ai/llm-app/mcp/mcp-workflow.jpg

该过程涉及到 3 个角色:

  • 1)MCP Server:也就是我们实现的 MCP 服务

  • 2)LLM:大模型,DeepSeek、ChatGPT 或者自己部署的其他模型都可以

  • 3)Cline(MCP Hosts):在 MCP Server 和 LLM 之间交互,可以看做是一个 Agent

流程如下:

  • 1)配置 MCP Server 到 Cline 之后,Cline 会获取该 MCP Server 提供的能力

  • 2)用户给 Cline 发送任务

  • 3)Cline 会带着问题和上一步获取到的信息发送给 LLM

  • 4)LLM 根据问题和 MCP 信息决定该调用哪个 MCP Server 的哪个 tool,具体通过 <use_mcp_tool> </use_mcp_tool> 标记,例如:

    <use_mcp_tool>
     <server_name>mymcp</server_name>
     <tool_name>calculate</tool_name>
      <arguments>
        { "operation": "add", "x": 1,"y": 1}
      </arguments>
    </use_mcp_tool>
    
  • 5)Cline 解析 XML 并调用对应 MCP Server 拿到结果

  • 6)Cline 将 MCP Server 结果返回给 LLM

  • 7)LLM 整合后返回最终结果给 Cline

  • 8)Cline 将最终结果展现给用户

MCP Hosts 会和大模型有两次交互,另外根据 MCP Hosts 实现不同,MCP 可以依赖或者不依赖 FunctionCalling。

主要就是要把本地支持的函数信息告诉 LLM,可以在system提示词里也可以使用functionCalling 放到 functiions 里面,最终效果都是一样的。

  • 支持functionCalling的模型

    • 输入:函数放到 functions 里

    • 输出:output.tool_use 里面就是要调用的工具

  • 对不支持functionCalling的模型

    • 输入:函数放到提示词里,一般在system部分

    • 输出:使用xml标签,比如<user_mcp_tool><use_mcp_tool/> 之类的格式指定要调用的函数的参数信息

可以对于不支持 functionCalling的 LLM 也可以达到同样的效果。

5. 小结

本文通过实战演示了 Anthropic 开源协议 MCP 的核心价值 —— 通过标准化接口实现大模型与外部工具的解耦集成。我们基于 Go 语言实现了两种典型部署形态的 MCP Server:

  • Stdio 类型:通过进程的标准输入输出完成交互,方便本地工具集成。

  • SSE 类型:采用 Server-Sent Events 技术实现长连接通信,支持远程接入。

从架构层面看,MCP 定义的三方角色(MCP Server 提供工具能力、LLM 负责逻辑决策、MCP Hosts 协调交互流程)形成了清晰的职责分层。这不仅让工具开发者可专注于功能实现(如本文的计算器工具),也让模型开发者能聚焦算法优化,最终通过标准化协议推动大模型生态从 “烟囱式开发” 向 “组件化协同” 演进。

随着更多工具接入 MCP 生态,这种标准化交互协议将成为连接大模型与垂直领域数据的 “数字桥梁”,为企业级 AI 应用开发提供更高效的基础设施。

最后再贴一下工作流程:

https://img.lixueduan.com/ai/llm-app/mcp/mcp-workflow.jpg