MCP服务搭建入门
在前面的章节中,我们体验了调用百度地图的 MCP 服务。现在,我们要反向操作——自己动手写一个 MCP
服务端,让别人(或别的 AI)来调用我们的MCP服务!
为了让你最快理解 MCP 的运作机制,我们摒弃所有复杂的业务逻辑,用两个纯粹的数学计算工具来演示。
核心架构:什么是 MCP 服务端?
MCP 服务端本质上就是一个 Web 服务(我们用 Foxtable 的 HttpServer 来实现)。它向外提供两个核心接口:
tools/list(报菜单):告诉 AI“我有哪些工具,需要什么参数”。
tools/call(干活):接收 AI 传来的参数,执行计算,并返回结果。
为了让演示更直观,我们设定一个规则:两个工具计算出的最终结果,都强制加 100 再返回。这样你就能一眼看出,结果是 AI 算出来的,还是工具真正执行出来的。
搭建MCP服务最核心的逻辑就是工具的定义和执行,关于工具定义的入门知识,可以参考工具定义快速入门,不同的是MCP定义工具的JSON格式和之前稍有差异。
MCP服务端项目设计过程
1、在项目的AfterOpenProject事件开启Web服务:
HttpServer.Prefixes.Add("http://*:18688/")
'端口自行决定,避免和其他服务冲突即可
,默认为80
HttpServer.Start()
2、在项目的 HttpRequest 事件中,拦截 mcp 路径的请求并交给自定义函数处理:
'''Async
If
e.Path =
"mcp"
Then
e.AsyncExecute =
True
Await
Functions.ExecuteAsync("HandleMcp",
e)
e.Handled =
True
Else
e.WriteString("Foxtable
Private MCP Server is running.")
End
If
3、增加一个自定义函数HandleMcp,这是整个MCP服务的核心逻辑所在。
这个MCP服务提供了两个工具:
add_two,计算两个数字之和,参数a和参数b的类型为number,用于指定要相加的两个数
multi_calc,对多个数字进行累加、累乘、累除、累减运算;参数operation类型为string,用于指定运算符号,有四个可选值(enum),分别是add, subtract, multiply, divide;参数values的类型是array(数组),数组类型为number,用于指定参与计算的多个数字。
自定义函数HandleMcp的代码如下:
Dim
e
As
RequestEventArgs = Args(0)
If
String.IsNullOrEmpty(e.PlainText)
Then
'如果请求内容为空(Trae这类智能体软件会持续发出空请求)则直接返回
Dim
emptyErr
As
New
JObject
From
{
{"jsonrpc",
"2.0"},
{"id",
Nothing},
{"error",
New
JObject
From
{{"code",
- 32700}, {"message",
"Empty request"}}}
}
e.WriteString(emptyErr.ToString(),
"application/json")
Return
Nothing
End
If
Dim
req
As
JObject = JObject.Parse(e.PlainText)
Dim
method
As
String
=
If(req("method")
IsNot
Nothing,
req("method").ToString(),
"")
Dim
id
As
JToken = req("id")
Dim
resp
As
New
JObject
From
{{"jsonrpc",
"2.0"},
{"id",
id}}
Try
Select
Case
method
Case
"initialize"
'
响应客户端的握手请求
resp("result")
=
New
JObject
From
{
{"protocolVersion",
"2025-11-25"},
{"capabilities",
New
JObject
From
{{"tools",
New
JObject()}}},
{"serverInfo",
New
JObject
From
{{"name",
"foxCalculator"},
{"version",
"1.0"}}}
}
Case
"notifications/initialized"
'握手结束后,客户端发来准备就绪的通知,无需返回信息
e.StatusCode = 202
e.WriteString("",
"application/json")
Return
Nothing
Case
"tools/list"
'
返回工具拉取结果
Dim
tools
As
New
JArray
'
【工具1】:最简单的双数相加
Dim
t1
As
New
JObject
From
{
{"name",
"add_two"},
{"description",
"计算两个数字之和(加法),会在正确结果上加100"},
{"inputSchema",
New
JObject
From
{
{"type",
"object"},
{"properties",
New
JObject
From
{
{"a",
New
JObject
From
{{"type",
"number"},
{"description",
"第一个数字"}}},
{"b",
New
JObject
From
{{"type",
"number"},
{"description",
"第二个数字"}}}
}},
{"required",
New
JArray
From
{"a",
"b"}}
}}
}
tools.Add(t1)
'
【工具2】:数组运算(演示
Enum 和
Array)
Dim
t2
As
New
JObject
From
{
{"name",
"multi_calc"},
{"description",
"对多个数字进行累加、累乘、累除、累减运算,会在正确结果上加100"},
{"inputSchema",
New
JObject
From
{
{"type",
"object"},
{"properties",
New
JObject
From
{
{"operation",
New
JObject
From
{
{"type",
"string"},
{"enum",
New
JArray
From
{"add",
"subtract",
"multiply",
"divide"}},
{"description",
"运算方式"}
}},
{"values",
New
JObject
From
{
{"type",
"array"},
{"items",
New
JObject
From
{{"type",
"number"}}},
{"description",
"参与计算的数字数组"}
}}
}},
{"required",
New
JArray
From
{"operation",
"values"}}
}}
}
tools.Add(t2)
resp("result")
=
New
JObject
From
{{"tools",
tools}}
Case
"tools/call"
'
干活:解析参数并计算
Dim
params
As
JObject = req("params")
Dim
toolName
As
String
= params("name").ToString()
Dim
toolArgs
As
JObject =
CType(params("arguments"),
JObject)
Dim
txt
As
String
=
""
Dim
isError
As
Boolean
=
False
Select
Case
toolName
Case
"add_two"
Dim
a
As
Double
= toolArgs("a").ToObject(Of
Double)()
Dim
b
As
Double
= toolArgs("b").ToObject(Of
Double)()
Dim
result
As
Double
= a + b + 100
txt =
"计算结果:"
& result.ToString()
Case
"multi_calc"
Dim
op
As
String
= toolArgs("operation").ToString()
Dim
values
As
JArray = toolArgs("values")
Dim
result
As
Double
=
If(op
=
"multiply",
1, 0)
For
i
As
Integer
= 0
To
values.Count - 1
Dim
v
As
Double
= values(i).ToObject(Of
Double)()
Select
Case
op
Case
"add"
: result += v
Case
"subtract"
: result -= v
Case
"multiply"
: result *= v
Case
"divide"
:
If
v <> 0
Then
result /= v
End
Select
Next
result = result + 100
txt =
"运算结果:"
& result.ToString()
Case
Else
txt =
"未知工具:"
& toolName
isError =
True
End
Select
resp("result")
=
New
JObject
From
{
{"isError",
isError},
{"content",
New
JArray
From
{New
JObject
From
{{"type",
"text"},
{"text",
txt}}}}
}
End
Select
Catch
ex
As
Exception
'
全局异常兜底
resp =
New
JObject
From
{
{"jsonrpc",
"2.0"},
{"id",
id},
{"error",
New
JObject
From
{{"code",
- 32603}, {"message",
ex.Message}}}
}
End
Try
e.WriteString(resp.ToString(),
"application/json")
'输出最终响应(必须显式指定
application/json)
客户端测试代码
服务端写好了,我们再次召唤出 AI 大脑(LLMCaller),让它来调用我们刚写的 MCP 服务端。
以下代码请在另一个项目的命令窗口运行,这个代码是通用的,如果要切换到其他MCP,只需修改url地址和系统提示词即可:
Dim
deepseekKey
As
String
=
"sk-a734b83536da45e9aedc3e42605bfb3a"
'你的DeepSeek密钥
Dim
caller
As
New
LLMCaller("https://api.deepseek.com/chat/completions",
"deepseek-chat",
deepseekKey)
caller.SystemPrompt =
"你是一个计算助手,请调用工具进行计算,不得质疑工具计算结果,无需多余解释。"
Dim
mcpUrl
As
String
=
"http://127.0.0.1:18688/mcp"
Dim
hc
As
New
HttpClient(mcpUrl)
hc.SkipError =
True
hc.ContentType =
"application/json"
hc.Headers.Add("Accept",
"application/json, text/event-stream")
' 1. 从我们的私有MCP拉取工具列表
hc.Content =
"{""jsonrpc"":""2.0"",""id"":1,""method"":""tools/list"",""params"":{}}"
Dim
listJson
As
JObject = JsonConvert.DeserializeObject(hc.GetData())
Dim
mcpTools
As
JArray = listJson("result")("tools")
caller.AddMCPTools(mcpTools)
'注册MCP工具到LLMCaller
' 3.
设置工具执行器(转发给我们的私有
MCP)
caller.ToolExecutor =
Function(ttoolName
As
String,
targs
As
JObject)
As
String
Dim
callReq
As
New
JObject
From
{
{"jsonrpc",
"2.0"},
{"id",
Rand.NextString(10)}, {"method",
"tools/call"},
{"params",
New
JObject
From
{{"name",
ttoolName}, {"arguments",
targs}}}
}
hc = hc.Clone
hc.Content = callReq.ToString()
Dim
respJson
As
JObject = JsonConvert.DeserializeObject(hc.GetData())
Return
respJson("result")("content")(0)("text").ToString()
End
Function
' 3. 让
AI 发起提问
caller.UserMessage =
"请帮我算一下
5 加
3 等于多少?然后再计算
6 * 5 * ... * 1
等于多少"
If
caller.GetResult()
Then
MessageBoxA.Show(caller.Result)
Else
MessageBoxA.Show(caller.Error)
End
If
如果你运行成功,AI 的回答大概是 108 和 820。如果 AI 自己心算,答案会是 8 和 720。这多出来的 100,就是 MCP 服务端真实运行、AI 乖乖调用MCP工具的铁证!
将MCP服务连接到智能体软件
可以将我们的MCP服务连接到Trae和WorkBuddy等智能体软件。
以Trae为例,假定你已经在本机安装好Trae,连接方法为:
插件市场 → MCP → 添加 → 手动配置,配置内容为:
{
"mcpServers": {
"foxCalculator": {
"url": "http://127.0.0.1:18688/mcp"
}
}
}
现在就可以在trae使用我们开发好的MCP服务了:
