一、mcp-server构建

二、mcp-server测试

  • 使用vscode的cline作为mcp-client进行测试,添加自定义mcp-server

{
  "mcpServers": {
    "my-weather": {
      "autoApprove": [
        "getWeatherForecastByLocation",
        "getAlerts"
      ],
      "disabled": false,
      "timeout": 60,
      "url": "http://localhost:8080/sse",
      "transportType": "sse"
    }
  }
}
  • 成功添加后,会出现类似下面的结果
    \wechat_2025-05-16_231415_089.png

  • 本地测试后,提示超时

Error executing MCP tool:
MCP error -32001: Request timed out
  • 后面使用wireshark抓包发现,请求的时候没有响应,猜测是本地代理导致的

  • 关闭代理后重试,有时候可以成功获取结果

  • 猜测是里面获取了国外的接口,很容易导致超时,因此自己新增加一个简单的方法,如下:

# 添加到项目中的WeatherService

    @Tool(description = "Get score for name. Input is someone's name (e.g. lisi)")
    public String getScore(String name) {
        return switch (name) {
            case "lisi" -> "80.0";
            case "zhangsan" -> "90.5";
            default -> "60";
        };
    }
  • 添加上面的自定义getScore后,终于可以顺利获取到响应了

lisi的分数是多少?

------------------------------------------------------------------

1. 检查了当前工作目录和文件列表,没有发现任何包含分数数据的文件
2. 注意到有一个名为"my-weather"的MCP服务器,其中提供了"getScore"工具
3. 该工具的描述是"Get score for name. Input is someone's name (e.g. lisi)"
4. 这似乎正是我们需要的功能,可以直接查询名字对应的分数
5. 需要调用MCP服务器的getScore工具,参数为name: "lisi"

------------------------------------------------------------------

Get score for name. Input is someone's name (e.g. lisi)
Arguments
{
  "name": "lisi"
}

Resonpse

"80.0"


------------------------------------------------------------------

lisi的分数是80.0

三、mcp协议分析

1、添加mcp-server后客户端获取信息

  • 会根据配置的url去发起sse请求,Accept: text/event-stream

  • 然后mcp-server就会返回一堆的信息回来,包括tools列表以及tool描述信息

GET /sse HTTP/1.1
host: localhost:8080
connection: keep-alive
Accept: text/event-stream
accept-language: *
sec-fetch-mode: cors
user-agent: node
pragma: no-cache
cache-control: no-cache
accept-encoding: gzip, deflate

HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream;charset=UTF-8

51
event:endpoint
data:/mcp/message?sessionId=100a5605-717f-4a06-ac0c-13a73e36091d


ce
event:message
data:{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"logging":{},"tools":{"listChanged":true}},"serverInfo":{"name":"my-weather-server","version":"0.0.1"}}}


330
event:message
data:{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"toUpperCase","description":"Put the text to upper case","inputSchema":{"type":"object","properties":{"input":{"type":"string"}},"required":["input"],"additionalProperties":false}},{"name":"getAlerts","description":"Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)","inputSchema":{"type":"object","properties":{"state":{"type":"string"}},"required":["state"],"additionalProperties":false}},{"name":"getWeatherForecastByLocation","description":"Get weather forecast for a specific latitude/longitude","inputSchema":{"type":"object","properties":{"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"}},"required":["latitude","longitude"],"additionalProperties":false}}]}}


72
event:message
data:{"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"Method not found: resources/list"}}


7c
event:message
data:{"jsonrpc":"2.0","id":3,"error":{"code":-32601,"message":"Method not found: resources/templates/list"}}


2、/mcp/message请求

  • 这个请求貌似和第一个/sse的关联性比较强

POST /mcp/message?sessionId=100a5605-717f-4a06-ac0c-13a73e36091d HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 155

{"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"Cline","version":"3.15.5"}},"jsonrpc":"2.0","id":0}HTTP/1.1 200 OK
content-length: 0

POST /mcp/message?sessionId=100a5605-717f-4a06-ac0c-13a73e36091d HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 54

{"method":"notifications/initialized","jsonrpc":"2.0"}HTTP/1.1 200 OK
content-length: 0

POST /mcp/message?sessionId=100a5605-717f-4a06-ac0c-13a73e36091d HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 50

{"method":"resources/list","jsonrpc":"2.0","id":2}HTTP/1.1 200 OK
content-length: 0


3、超时取消响应

  • 会返回notifications/cancelled

POST /mcp/message?sessionId=d851758f-11f1-4c2a-9060-ee83d9ae88b1 HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 134

{"jsonrpc":"2.0","method":"notifications/cancelled","params":{"requestId":4,"reason":"McpError: MCP error -32001: Request timed out"}}HTTP/1.1 200 OK
content-length: 0

4、一个成功的业务请求响应:比如获取lisi的分数,mcp-server中实现了一个getScore的方法

  • 发起了/mcp/message请求,里面包含了getScore方法和参数lisi

  • 返回的响应是在/sse请求后续的event中返回的,76的event中有结果80.0

# 先贴一下cline中的过程
1. 检查了当前工作目录和文件列表,没有发现任何包含分数数据的文件
2. 注意到有一个名为"my-weather"的MCP服务器,其中提供了"getScore"工具
3. 该工具的描述是"Get score for name. Input is someone's name (e.g. lisi)"
4. 这似乎正是我们需要的功能,可以直接查询名字对应的分数
5. 需要调用MCP服务器的getScore工具,参数为name: "lisi"

------------------------------------------------------------------

POST /mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b HTTP/1.1
host: localhost:8080
connection: keep-alive
content-type: application/json
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: gzip, deflate
content-length: 103

{"method":"tools/call","params":{"name":"getScore","arguments":{"name":"lisi"}},"jsonrpc":"2.0","id":4}HTTP/1.1 200 OK
content-length: 0



------------------------------------------------------------------


GET /sse HTTP/1.1
host: localhost:8080
connection: keep-alive
Accept: text/event-stream
accept-language: *
sec-fetch-mode: cors
user-agent: node
pragma: no-cache
cache-control: no-cache
accept-encoding: gzip, deflate

HTTP/1.1 200 OK
transfer-encoding: chunked
Content-Type: text/event-stream;charset=UTF-8

51
event:endpoint
data:/mcp/message?sessionId=52e8afc3-8ca1-489a-bba5-ad65c19ab57b


ce
event:message
data:{"jsonrpc":"2.0","id":0,"result":{"protocolVersion":"2024-11-05","capabilities":{"logging":{},"tools":{"listChanged":true}},"serverInfo":{"name":"my-weather-server","version":"0.0.1"}}}


405
event:message
data:{"jsonrpc":"2.0","id":1,"result":{"tools":[{"name":"toUpperCase","description":"Put the text to upper case","inputSchema":{"type":"object","properties":{"input":{"type":"string"}},"required":["input"],"additionalProperties":false}},{"name":"getAlerts","description":"Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)","inputSchema":{"type":"object","properties":{"state":{"type":"string"}},"required":["state"],"additionalProperties":false}},{"name":"getWeatherForecastByLocation","description":"Get weather forecast for a specific latitude/longitude","inputSchema":{"type":"object","properties":{"latitude":{"type":"number","format":"double"},"longitude":{"type":"number","format":"double"}},"required":["latitude","longitude"],"additionalProperties":false}},{"name":"getScore","description":"Get score for name. Input is someone's name (e.g. lisi)","inputSchema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false}}]}}


72
event:message
data:{"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"Method not found: resources/list"}}


7c
event:message
data:{"jsonrpc":"2.0","id":3,"error":{"code":-32601,"message":"Method not found: resources/templates/list"}}


76
event:message
data:{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"\"80.0\""}],"isError":false}}



mcp

登陆发表评论