MCP 是一种开放协议,旨在为大模型扩展能力,可以把 MCP 想象成大模型的 USB 端口,就像外设通过 USB 为电脑扩展能力一样,MCP 为大模型扩展能力。
官网 SDK 支持的语言:
它定义是一种标准的通信结构,目前主流大模型都支持这种结构:
{
"content": [
{
"type": "text",
"text": "未从 https://www.baidu.com 中解析到内容"
},
{
"type": "image | audio",
"data": "当为 image 或 audio 时,mimeType 必传",
"mimeType": "image/png"
},
{
"type": "resource",
"resource": {
"uri": "resource://example",
"name": "example",
"title": "My Example Resource",
"mimeType": "text/plain",
"text": "Resource content"
}
}
],
"isError": true
}
MCP 遵循客户端-服务器架构。MCP 服务器相当于外设,MCP 客户端相当于驱动
MCP 服务器
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
const server = new McpServer({ name: 'qmp-doc', version: '1.0.0' })
const transport = new StdioServerTransport()
server.connect(transport)
// 除了以 stdio 外,还可以以 http 和 sse 的方式创建传输通道
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
// 操作本地能力的,比如导出 AI 结果到本地,适合使用 stdio
// 依赖远程数据的,比如工商信息、企业调研,适合使用 http 和 sse
| 核心能力 | 目的 | 谁控制它 | 真实世界的例子 |
|---|---|---|---|
| 工具 | 扩展 AI 行为 | AI | 搜索航班,发送消息,创建日历事件 |
| 资源 | 扩展上下文数据 | 应用 | 文件、日历、电子邮件、天气数据 |
| 提示 | 互动模板 | 用户选择 | “计划假期”、“收摒我的会议”、“起草一封电子邮件” |
工具
server.registerTool(
'createTxt',
{
title: '创建Txt文件',
description: '将提供的文本写入本地Txt文件',
inputSchema: { message: z.string(), dir: z.string() },
},
async ({ message, dir }) => {
if (await fileIsExist(dir)) {
await writeFile(dir, message)
return {
content: [{ type: 'text', text: `${message} 已成功写入到 ${dir}` }],
}
} else {
return {
isError: true,
content: [{ type: 'text', text: `路径不存在` }],
}
}
}
)
在向 AI 提问时附上工具列表,AI 会根据语意判断是否使用、使用哪个工具(命中工具),工具执行完成后将结果显示给用户或返回给 AI 继续。
资源
server.registerResource(
'qmpnews',
new ResourceTemplate('qmpnews://{industry}', { list: undefined }),
{
title: '行业新闻',
description: '指定行业的新闻,来自企名片内部库',
},
async (uri, { industry }) => ({
contents: [
{
uri: uri.href,
text: `与 ${industry} 相关的近日新闻如下:\n xxx`,
},
],
})
)
在向 AI 提问前判断是否需要将资源带给 AI,这个判断可以是:
- 正式提问前,先问问 AI 当前问题是否需要某个资源
- 正式提问前,先通过一个轻量级的意图识别系统(可以是正则、关键词匹配、小型 NLU 模型)来判断是否附带资源
- 将所有可提供的资源预先进行 Embedding 处理,并存入向量数据库。正式提问前,在向量数据库中进行相似度检索
提示
server.registerPrompt(
'qmpnews',
{
title: '每周行业新闻',
description: '根据指定行业返回每周行业新闻热点或大事件',
argsSchema: {
industry: completable(z.string(), (value) => {
return [行业列表们].filter((industry) => industry.startsWith(value))
}),
},
},
({ industry }) => ({
title: `每周行业新闻 - ${industry} 相关`,
description: `针对 ${industry} 行业的近日新闻热点或大事件`,
messages: [
{
role: 'user',
content: {
type: 'text',
text: `整理 ${industry} 行业的近日新闻热点或大事件。使用我提供的资源,时间的优先级最高,还有以下要求和流程:xxxxx、xxxx、xx、xxxxx。`,
},
},
{
role: 'user',
content: {
type: 'resource',
resource: {
uri: `qmpnews://${industry}`,
text: `与 ${industry} 相关的近日新闻如下:\n xxx`,
},
},
},
],
})
)
就是各家 AI 工具的指令中心,由应用来展示、用户来选择,然后发给 AI
MCP 客户端
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
const mcp = new Client({ name: 'mcp-client', version: '0.0.1' })
const transport = new StdioClientTransport({
command: 'npx',
args: ['qmp-doc-server'],
env: [],
})
await mcp.connect(transport)
console.log('MCP连接成功')
// 除了以 stdio 外,还可以以 http 和 sse 的方式创建传输通道
import { SSEServerTransport } from '@modelcontextprotocol/sdk/client/sse.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
使用工具
const ai = new OpenAI(openAiConf) // 基于 openai 库
function getTools() {
const toolsResult = await mcp.listTools()
const tools = toolsResult.tools.map((tool) => ({
type: 'function',
function: {
name: tool.name,
type: 'function',
description: tool.description,
inputSchema: tool.inputSchema,
parameters: tool.inputSchema.properties,
annotations: tool.annotations
}
}))
return tools // 转为 openai 要求的 tools 格式
}
const messages: any = [
{ role: 'user', content: '请将“文本内容”保存到本地txt中' }
]
const completion = await ai.chat.completions.create({
model: openAiConf.model,
messages,
temperature: 0,
tools: getTools() // 将 tools 附带给 AI
})
const content = completion.choices[0]
messages.push(content.message)
if (content.finish_reason === 'tool_calls') {
// 命中了某些工具
for (const toolCall of content.message.tool_calls!) {
const toolName = toolCall.function.name
const toolArgs = JSON.parse(toolCall.function.arguments.trim())
console.log('【工具名】', toolName, '【参数】', toolArgs)
// 调用工具
const result = await mcp.callTool({ name: toolName, arguments: toolArgs })
console.log('【工具响应】', result.content)
messages.push({
role: 'tool', // 工具消息的角色应该是 tool
content: result.content, // 工具返回的结果
tool_call_id: toolCall.id,
name: toolName
})
}
}
const response = await ai.chat.completions.create({
model: config.model,
messages, // 这里需要传入工具调用的结果
tools: getTools()
})
console.log('AI执行的最终结果是:', response.choices[0].message.content)
一个服务器+客户端完整 DEMO blog.modelcontextprotocol.io/posts/2025-…
TS SDK 及用法 www.npmjs.com/package/@mo…