前言
随着AI模型的发展,对应回答的数据也是越来越丰富和完善了,但是还缺少一块有关第三方数据信息的内容,这一块在往常的方式形式上,我们可能是通过api接口的形式暴露调用其能力。对于AI模型上,有了通用的形式MCP,让所有第三方暴露的信息内容,都按照统一的格式暴露。
Mcp server
现在有很多对应的Mcp server的服务市场,有很多比较成熟的服务,可以快速接入使用 ,可以依照自己的需要选择接入
- modelcontextprotocol/servers
- awesome-mcp-servers
- mcp.so
- modelscope.cn
- mcp.higress.ai
- smithery.ai
- glama.ai
- pulsemcp.com
- mcp.composio.dev
当然有想法,也可以自己创建对应mcp
内容,上传对应的内容。目前支持的python
和ts
写的会比较多。所以网上提供的大部分都是npx/uvx
执行
使用uv来构建本地内容
mac
安装uv
,通过brew
来实现brew add uv
安装
使用uv
来快速创建一个虚拟环境的项目,这里我们可以先使用3.11版本的python
内容环境依赖,创建名称为mcp-project
的项目名称, 然后安装 mcp
包,并且额外安装其 cli
这个 extra
所指定的可选依赖
csharp
uv init mcp-project
uv venv --seed --python 3.11 .venv //seed相关pip包, 生成.venv配置环境内容
uv add "mcp[cli]"
注意要使用python/pip
相关命令,需要source .venv/bin/activate
激活环境里的python和pip
对应在github
上找到model context protocol
项目也就是mcp
,里面对应有的python sdk
仓库。

仿照对应它的quick start
的案例编写属于自己的demo
的案例,包括构建Server
和tool
工具信息
python
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
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run(transport="stdio")
tool
: 代表对应的可以执行的工具,允许 LLM 通过您的服务器执行协作,类似于http
中的post
- 参数:包含对应的参数值信息,参数和类型,对应上述方法中的
a
和b
,类型为int
- 标题:包含对应的方法的工具名称标题,对应上述方法标题 add
- 介绍:包含对这个工具的相关的使用介绍信息, 对应上述方法中的
Add two numbers
- 返回:包含对应的返回值,对应上述方法的
a+b
的结果值
- 参数:包含对应的参数值信息,参数和类型,对应上述方法中的
resource
: 资源是如何向 LLM 公开数据的方式,类似于http
中的get
trasport
:对应的类型,标准输入输出(stdio)
服务发送事件(sse)
: 对应的是http请求url的地址,后缀加sse可流式传输的http(streamableHttp)
使用运行uv run main.py
,就能运行对应这个对应的服务 。 如果想使用Mcp Inspector
来进行调试对应的MCP服务是否可用, 使用命令mcp dev main.py
来运行,就会得到对应的请求地址http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=xxxxxxx
less
uv run main.py // 单纯运行这个服务
mcp dev main.py // 通过mcp检测调试的方式运行服务
下图就是标识了检测MCP服务是否可以连接用的展示,是执行了mcp dev main.py
的结果,注意前面添加依赖的时候使用的是uv add "mcp[cli]"
才能执行而不是 uv add mcp

使用ts构建本地内容
创建一个node
的项目,申明一个项目名称,然后初始化项目
arduino
mkdir simple-mcp // 创建一个名称为simple-mcp的项目
cd simple-mcp
npm init -y // 初始化项目
此时会有对应的package.json
文件内容,此时我们可以增加一些mcp,ts,node
的相关依赖
bash
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
创建一些对应的主文件目录src
,和对应的文件src/index.ts
bash
mkdir src
touch src/index.ts
然后修改对应的package.json
文件
- 对应的
type
修改为module
,可以使用使用现代 JS 模块语法(import/export
) - 增加
bin
,提供一个终端命令(如pixabay
)来运行这个工具 - 修改
scripts
,使用TypeScript
编写源码,并通过tsc
构建到build/
目录 - 增加
files
,只发布构建后的代码(build/
) - 修改
main
, 改为build/index.js
,指向的是编译后的.js
文件
json
{
"name": "simple-mcp",
"version": "1.0.0",
"description": "",
"main": "build/index.js"
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"bin": {
"pixabay": "./build/index.js"
},
"scripts": {
"build": "tsc && chmod 755 build/index.js"
"start": "node build/index.js"
},
"files": [
"build"
]
}
在根目录文件下增加 tsconfig.json
文件
json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
至此我们已经创建好一个项目了,开始正式创建mcp server
内容, 和之前提到的uv
一样,也是从typescript sdk仓库中获得mcp的案例进行仿写

php
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "demo-server",
version: "1.0.0"
});
// Add an addition tool
server.registerTool("add",
{
title: "Addition Tool",
description: "Add two numbers",
inputSchema: { a: z.number(), b: z.number() }
},
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
registerTool
: 绑定对应的工具方法title
: 标题description
: 介绍详情内容inputSchema
:对应参数类型,名称
开始执行构建npm run build
命令,会生成build
文件夹,和它下面的index.js
文件 。如果有需要的话执行的话npm start
然后再通过开启的之前提到的uv
中的mcp dev xx.py
效果一致,也是启动一个端口页面访问测试连接 使用命令npx @modelcontextprotocol/inspector
按照启动调试mcp server
是否能联通的依赖包

点开对应携带token的url端口地址,页面中command
中输入node
,在Arguments
中填入刚刚构建好的build/index.js
,本质上也是运行这个脚本
Mcp Client(软件客户端)
现有的client
对应有不同形式的很多,我们前面只是通过工具页面 MCP Inspector
来检测是否服务是否成功,当然我们可以直接在常见的Cursor
,cherry studio
中直接配置对应的mcp服务器
配置到cherry studio
按照我们前面提到的例子,uv构建的和ts构建的本地的mcp server
内容,使用我们的cherry studio
来连接使用
- 第一种通过
uv
的 mcp的形式
点击设置-> Mcp服务器-> 创建对应的服务器
类型选择 标准输入/输出(stdio) 命令: uv 参数为 --directory mcp-project项目地址 run main.py

如果你想用sse
类型,可以修改代码mcp.run(transport="sse")
,然后配置的时候选择 服务发送事件(sse) 和地址url配置上即可
- 第二种通过
ts
的mcp的形式
点击设置-> Mcp服务器-> 创建对应的服务器 类型选择 标准输入/输出(stdio) 命令:node 参数为: index.js的地址

- 当然也可以直接通过json的配置内容直接复制进入也是可以的
复制到 "mcpServers"
对象中,里面每一个key
和value
都对应一个mcp的服务内容

配置到Cursor
点击对应的chat setting
设置,然后选择MCP,可以将对应的json配置直接加入即可,复制到 "mcpServers"
对象中,里面每一个key
和value
都对应一个mcp的服务内容

json
"GEWXPfNVUk1-stgDGAXxT": {
"name": "MCP 服务器",
"type": "stdio",
"description": "",
"isActive": true,
"command": "node",
"args": [
"/Users/gjc/workspace/vscodeWorkspace/simple-mcp/build/index.js"
]
}
Mcp Client(代码客户端)
使用mcp的原生sdk实现
作为后端比较熟悉java的写法,刚好java也有对应的依赖支持。
xml
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
<version>0.9.0</version>
</dependency>
通过sse
形式路径url
来构建client
的bean
内容 ,注意sseServerUrl
已经不需要在添加/sse
了
java
@Component
public class McpClientUtil {
private McpSyncClient mcpClient;
// 对应的sse的连接地址
private static final String sseServerUrl = "https://xxxx.yy.com/";
// 初始化
@PostConstruct
public void init(){
try {
McpClientTransport transport = new HttpClientSseClientTransport(sseServerUrl);
mcpClient = McpClient.sync(transport)
.requestTimeout(Duration.ofSeconds(20L))
.capabilities(McpSchema.ClientCapabilities.builder()
.roots(true)
.sampling()
.build())
.build();
mcpClient.initialize();
} catch (Exception e) {
throw new RuntimeException("初始化MCP客户端对象失败", e);
}
}
// 结束销毁
@PreDestroy
public void destroy(){
if (mcpClient != null) {
mcpClient.closeGracefully();
}
}
}
对应的McpClientUtil
的bean
的事先构建,含有McpSyncClient
这个属性实例,通过bean
的初始化和结束销毁操作 ,也就是对于这个McpSyncClient
执行不同的初始化和结束销毁
如果我们想获取对应地址sse的Mcp server
中的能力,我们可以在提供一个方法来支持
csharp
// 获取对应工具的信息内容
public void getToolList(){
McpSchema.ListToolsResult toolsResult = mcpClient.listTools();
for (McpSchema.Tool tool:toolsResult.tools()) {
System.out.println(tool.name());
System.out.println(tool.description());
System.out.println(tool.inputSchema());
}
}
McpClientUtil
这个bean
来调用getToolList
方法,此时会打印出对应工具的名称,描述信息,方法参数和类型信息。inputSchema
还可以直接作为functionCall
中tools
中的对象
如果我们还想直接调用工具的方法的话
scss
// 调用工具的方法
public void callTool() {
McpSchema.ListToolsResult toolsResult = mcpClient.listTools();
for (McpSchema.Tool tool:toolsResult.tools()) {
// 入参
Map<String,Object> parameters = new HashMap<>();
parameters.put("a", 1);
parameters.put("b", 1);
McpSchema.CallToolResult toolResult = mcpClient.callTool(new McpSchema.CallToolRequest("add", parameters));
System.out.println(extractTextContent(toolResult));
}
}
// 批量工具调用的结果整合输出
private String extractTextContent(McpSchema.CallToolResult toolResult){
StringBuilder resultText = new StringBuilder();
toolResult.content().forEach(content -> {
if (content instanceof McpSchema.TextContent) {
resultText.append(((McpSchema.TextContent) content).text());
}
});
return resultText.toString();
}
McpClientUtil
这个bean
来调用callTool
方法 , 指定对应的参数parameters
中的内容和我们在Map server
中定义的方法入参一致。CallToolRequest
对应的构建方法名称和参数封装构建
使用spring ai实现(sse)
我们先直接用大模型来实现操作(不引入mcp),引入相关依赖openai的spring-ai
,不是很清楚依赖版本的,可以通过spring网站直接创建模版项目
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
虽然我们使用的是openai的相关依赖,但是也不影响通过它来配置deepseek, 因为相关的参数配置接口信息都是遵从的一致,我们来配置下相关的文件信息
yaml
spring:
ai:
openai:
base-url: https://api.deepseek.com // 配置路径
api-key: sk-xxxxxxx // 配置密钥
chat:
options:
model: deepseek-chat // 配置使用的model
completions-path: /chat/completions
然后我们通过书写下简单的实例调用一下
kotlin
@Configuration
public class ChatClientConfig {
@Autowired
private OpenAiChatModel chatModel;
@Bean
public CommandLineRunner predefinedQuestions(
ConfigurableApplicationContext context) {
return args -> {
// 构建ChatClient,此时不注入任何工具
var chatClient = ChatClient.builder(chatModel)
.build();
String userInput = "你是谁";
System.out.println("\n>>> QUESTION: " + userInput);
System.out.println("\n>>> ASSISTANT: " + chatClient.prompt().user(userInput).call().content());
context.close();
};
}
}
启动的时候,直接就会去构建访问deepseek
,下图就是我们执行成功的标识

我们开始配置使用上mcp的功能,先配置对应的mcp server
相关信息(sse
的形式)
yaml
spring:
ai:
mcp:
client:
name: spring-ai-mcp-client
type: sync
toolcallback:
enabled: true
request-timeout: 30000
enabled: true
sse:
connections:
server1:
url: https://xxxxxx
在原来ChatClientConfig
增加调用这个mcp
工具
scss
@Autowired
private ToolCallbackProvider tools;
// 构建ChatClient,此时增加注入工具
var chatClient = ChatClient.builder(chatModel).defaultToolCallbacks(tools)
.build();
使用spring ai实现(stdio)
但是如果我们想通过stdio
的形式来执行
Stdio
和SSE
配置的区别是将调用方式由显示的服务地址换成npm、java、python
等脚本命令直接执行的远程包或本地包
我们复用上面的例子,然后修改mcp
的sse
的形式为stdio
,修改对应的配置文件
yaml
spring:
ai:
mcp:
client:
name: spring-ai-mcp-client
toolcallback:
enabled: true
request-timeout: 30000
enabled: true
stdio:
servers-configuration:classpath:/mcp-servers-config.json
创建对应的本地resource
下的mcp-servers-config.json
内容,编写mcpserver
的配置内容,例如我本地的python
的mcpserver
将它配置进来
json
{
"mcpServers": {
"mcp-server-hotnews": {
"command": "uv",
"args": [
"--directory",
"/Users/gjc/workspace/cursorWorkspace/simple-mcp",
"run",
"main.py"
]
}
}
}
然后再进行修改构建client的地方内容
scss
// 构建ChatClient,此时增加注入工具
var chatClient = ChatClient.builder(chatModel).defaultToolCallbacks(tools.getToolCallbacks())
.build();
总结
本质上我们通过自己uv
/node
构建项目,来整合mcp的sdk
依赖,来实现本地mcp server
的功能,然后也实现了在已有的软件cursor
和cherry studio
中配置连接mcp server
。最后通过java项目导入ai的相关依赖来实现配置来连接mcp server
。