AI探索 | 基于 Node.js 开发 MCP 客户端+服务端及优秀项目分享
🤔什么是 MCP?
官网原文:MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
MCP是一个开放协议,它规范了应用程序如何向大型语言模型(LLM)提供上下文。你可以将MCP想象成AI应用程序的USB-C端口。就像USB-C为设备与各种外围设备和配件的连接提供了标准化方式一样,MCP也为AI模型与不同数据源和工具的连接提供了标准化方式。
MCP的意义
在 MCP 推出之前,AI 应用依赖于各种方法与外部工具交互,例如手动 API 连接、基于插件的接口以及代理框架。如图 1 所示,这些方法需要将每个外部服务与特定的 API 集成,这增加了复杂性并限制了可扩展性。MCP 通过提供标准化协议来应对这些挑战,该协议支持与多种工具进行无缝且灵活的交互。
MCP 架构
MCP 架构由三个核心组件组成:MCP 主机、MCP 客户端和 MCP 服务器。这些组件协同工作,实现 AI 应用、外部工具和数据源之间的无缝通信,确保操作安全且得到妥善管理。
以上两张图片来自:MCP Research Paper:
🥇优秀项目
awesome-mcp-servers
开源地址:https://github.com/punkpeye/awesome-mcp-servers
Github 上必须出现的,又必然很火的 awesome-xx
系列🤭,收藏精品 MCP 服务端。
playwright-mcp
开源地址:https://github.com/microsoft/playwright-mcp
微软出品,使用 Playwright 提供浏览器自动化功能,能够通过结构化可访问性快照与网页进行交互,无需截图或视觉调优模型。
github-mcp-server
开源地址:https://github.com/github/github-mcp-server
Github 官方出品的 MCP 服务,提供与GitHub API的无缝集成,为开发人员和工具赋予高级自动化和交互能力。
Awesome-MCP-ZH
开源地址:https://github.com/yzfly/Awesome-MCP-ZH
一个专为中文用户打造的 MCP(模型上下文协议)资源合集! 这里有 MCP 的基础介绍、玩法、客户端、服务器和社区资源,帮你快速上手这个 AI 界的“万能插头”。
MCP Server资源站
- Mcp.so:收录超多的 MCP Server
👨💻一套简单的MCP交互程序
其实对程序员来说,MCP 交互不是什么新玩意,都可以简单拿 HTTP 协议套过来进行理解😄。一个支持发送 MCP 请求的客户端,向 MCP 服务器发起调用。
MCP 官方代码库为 https://github.com/modelcontextprotocol,里面有文档以及主流语言的 SDK,这里我们选择 typescript-sdk
进行客户端/服务端的开发。里面有一个inspector的库,是用于测试 MCP Server 的。
注意:MCP 需要 node.js v18+
。
开始做 MCP 开发前,有些术语需要了解下。
术语概要
- resource(资源):是向 LLM 公开数据的方式。它们类似于 REST API 中的 GET 端点——它们提供数据,但不应执行大量计算或对服务端产生影响;
- tool(工具):允许 LLM 通过你的服务器执行操作。与资源不同,工具需要执行计算并产生副作用;
- prompt(提示):可重复使用的模板,帮助 LLM 有效地与服务器交互。
参考资料
- pentest-mcp:适用于专业渗透测试人员的 MCP 服务器,包括 STDIO/HTTP/SSE 支持、nmap、go/dirbuster、nikto、JtR、hashcat、单词表构建等。
- fastify-mcp:用于运行 MCP 服务器的 Fastify 插件
🖥️ 服务端
使用 node.js 自带的 http 模块处理请求
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
import { z } from "zod"
import dayjs from "dayjs"
import { randomUUID } from "node:crypto"import { createServer, ServerResponse } from 'node:http'
import pc from 'picocolors'const log = (msg, level="INFO")=> console.debug(`${pc.cyan(dayjs().format("MM-DD HH:mm:ss:SSS"))} ${pc.gray(level)} ${msg}`)const buildServer = ()=>{const mcpServer = new McpServer({ name: "demo-mcp-server", version:"1.0.0" })mcpServer.registerTool("add",{title: "数值相加",description: "将参数累加",inputSchema: { a: z.number(), b: z.number() }},async ({ a, b })=>{log(`${pc.magenta("[TOOL]")} add a=${a} b=${b}`)return {content: [{ type:'text', text: `${a+b}` }]}})mcpServer.registerResource("greeting",new ResourceTemplate("greeting://{name}", { list: null }),{title: "Greeting Resource",description: "Dynamic greeting generator"},async (uri, { name })=>{log(`${pc.magenta("[RESOURCE]")} GREETING ${name}`)return {contents:[{ uri: uri.href, text:`Hello ${name}` }]}})return mcpServer
}/*** @type {Map<String, StreamableHTTPServerTransport>}*/
const transports = new Map()/**** @param {ServerResponse} res* @param {String} message - 描述信息* @param {Number} code - 错误代码,默认-32000*/
const sendError = (res, statusCode=400, message, code=-32000)=>{res.writeHead(statusCode, { 'content-type':'application/json' })res.end(JSON.stringify({jsonrpc: "2.0",error: { code, message },id: null,}))
}const httpServer = createServer(async (req, res)=>{const { url, method, headers } = reqif(url == '/favicon.ico')returnconst sessionId = headers['mcp-session-id']// 请求体(需要手动拼接)let body = '';req.on('data', chunk => body += chunk)req.on('end', async ()=>{log(`${pc.magenta(method.padEnd(4, " "))} | ${req.url} SESSION=${sessionId} TYPE=${headers['content-type']}`)if(method == 'POST'){/**@type {StreamableHTTPServerTransport} */let transport = transports.get(sessionId)if(transport == null || transport.closed == true){let server = buildServer()transport = new StreamableHTTPServerTransport({sessionIdGenerator: ()=> randomUUID(),onsessioninitialized: id=> {log(`MCP Session 已创建,ID=${id}`)transports.set(id, transport)}})transport.onclose = function(){log(`transport 关闭 onclose...`)if(this.sessionId)transports.delete(this.sessionId)elsethis.closed = true}await server.connect(transport)log(`StreamableHTTPServerTransport 创建成功...`)}const postBody = JSON.parse(body)await transport.handleRequest(req, res, postBody)log("处理 POST 请求...")console.debug(postBody)}else {sendError(res, 405, "Method not allowed.")}})
})const PORT = 8080
httpServer.listen(PORT, ()=>{log(`SERVER RUNNING ON ${PORT} ...`)
})
🤖 客户端
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";const client = new Client({name: "demo-mcp-client",version: "1.0.0"
})let transport = new StreamableHTTPClientTransport("http://localhost:8080")
await client.connect(transport)console.debug("MCP Server 连接成功...")try{//列出全部的 resourceconst resources = await client.listResources()console.debug("资源列表", resources)console.debug(await client.readResource({uri:"greeting://0604hx"}))const tools = await client.listTools()console.debug("工具列表", tools)console.debug(await client.callTool({name: 'add',arguments:{a: 100,b: 300}}))
}catch(e){console.debug("出错啦", e)
}await transport.close()
await client.close()
StreamableHTTP客户端初始化流程
- 发起初始化
{method: 'initialize',params: {protocolVersion: '2025-06-18',capabilities: {},clientInfo: { name: 'demo-mcp-client', version: '1.0.0' }},jsonrpc: '2.0',id: 0
}
- 第二次请求
{ method: 'notifications/initialized', jsonrpc: '2.0' }
📷 运行截图
🛠️ 使用 MCP Inspector
后续会单独写一篇博文介绍如何使用😄
❓ 问题集锦
-
MCP error -32603: keyValidator._parse is not a function
经排查,是由于zod
版本过高(一开始用的是4.x
),改成3.x
就正常了。参考:McpError: MCP error -32603: keyValidator._parse is not a function。 -
"Bad Request: Server not initialized
Server 并未初始化,请先调用server.connect(transport)
。 -
Invalid Request: Server already initialized
Server 已经初始化,sessionId 已经重复。
📚 推荐书籍
《MCP协议与AI Agent开发:标准、应用与实现》
是清华大学出版社出版的图书,系统地阐述了MCP的技术原理、协议机制与工程应用,提供了从底层协议设计到项目部署的全流程的应用指南。全书从结构上分为基础理论、协议规范、开发工具链、应用构建4部分,共9章。具体内容包括大模型基础、MCP基本原理、MCP标准与规范体系、MCP与LLM的互联机制、MCP开发环境与工具链、MCP与多模态大模型集成,以及MCP的状态流转机制、Prompt构建规范、上下文调度策略及其与模型推理引擎的协同工作,同时涉及流式响应、函数调用、模块化Prompt设计等前沿技术,并结合基于DeepSeek
平台的真实应用项目(人格共创AI剧本工坊、自演化智能议程会议系统与深梦编导器),助力读者理解MCP在多元领域的可拓展性与工程实践