当前位置: 首页 > news >正文

【初学】使用 node 编写 MCP Server

初始项目

npm init -y
npm install @modelcontextprotocol/sdk typescript ts-node @types/node
npm install -D typescript @types/node

修改 package.json

{"name": "mcp-server","version": "1.0.0","description": "","main": "index.js","type": "module","scripts": {"build": "tsc",},"keywords": [],"author": "","license": "ISC","dependencies": {"@modelcontextprotocol/sdk": "^1.18.1","ts-node": "^10.9.2"},"devDependencies": {"@types/node": "^24.5.2","typescript": "^5.9.2"}
}

添加 tsconfig.json

{"compilerOptions": {"target": "ES2022","module": "ESNext","moduleResolution": "node","outDir": "./dist","rootDir": "./src","strict": true,"esModuleInterop": true,"skipLibCheck": true,"forceConsistentCasingInFileNames": true,"resolveJsonModule": true,"declaration": true,"sourceMap": true},"include": ["src/**/*"],"exclude": ["node_modules", "dist"]}

编写 src/server.ts

官方文档: https://github.com/modelcontextprotocol/typescript-sdk

下方各示例可直接使用

Stdio 写法

import {McpServer,ResourceTemplate,} from "@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";import { z } from "zod";// Create an MCP serverconst server = new McpServer({name: "demo-server",version: "1.0.0",});// Add an addition toolserver.registerTool("add",{title: "Addition Tool",description: "用于计算任意两个数字的加法,包括小数和整数。无论数字大小都可以使用此工具进行精确计算。", // 必写,使用自然语言告诉大模型,这个工具是干什么的inputSchema: { a: z.number(), b: z.number() },},async ({ a, b }) => ({content: [{ type: "text", text: String(a + b) + " 计算成功" }],}));// Add a dynamic greeting resourceserver.registerResource("greeting",new ResourceTemplate("greeting://{name}", { list: undefined }),{title: "Greeting Resource", // Display name for UIdescription: "Dynamic greeting generator",},async (uri, { name }) => ({contents: [{uri: uri.href,text: `Hello, ${name}!`,},],}));// 启动服务器async function main() {// Start receiving messages on stdin and sending messages on stdoutconst transport = new StdioServerTransport();await server.connect(transport);console.error("MCP Server 已启动,等待连接...");}main().catch((error) => {console.error("服务器错误:", error);process.exit(1);});
# 构建
npm run build
# 启动
node dist/server.js
// cursor 相关配置
{"mcpServers": {// 可自定义 id"stdio-add": {"isActive": true,"name": "my-mcp","type": "stdio",// 本地 node 服务的路径,可通过 which node 查看"command": "/Users/tacy/.nvm/versions/node/v18.10.0/bin/node","args": [// 编译后的文件地址"/Users/tacy/test/mcp-server/dist/server.js"]}}
}

SSE 写法

import express from "express";
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";const server = new McpServer({name: "backwards-compatible-server",version: "1.0.0"
});// Add an addition tool
server.registerTool("add-sse",{title: "Addition Tool",description: "用于计算任意两个数字的加法,包括小数和整数。无论数字大小都可以使用此工具进行精确计算。", // 必写,使用自然语言告诉大模型,这个工具是干什么的inputSchema: { a: z.number(), b: z.number() },},async ({ a, b }) => ({content: [{ type: "text", text: String(a + b) + " 计算成功 sse" }],})
);// Add a dynamic greeting resource
server.registerResource("greeting",new ResourceTemplate("greeting://{name}", { list: undefined }),{title: "Greeting Resource", // Display name for UIdescription: "Dynamic greeting generator",},async (uri, { name }) => ({contents: [{uri: uri.href,text: `Hello, ${name}!`,},],})
);const app = express();
app.use(express.json());// Store transports for each session type
const transports = {streamable: {} as Record<string, StreamableHTTPServerTransport>,sse: {} as Record<string, SSEServerTransport>
};// Legacy SSE endpoint for older clients
app.get('/sse', async (req, res) => {// Create SSE transport for legacy clientsconst transport = new SSEServerTransport('/messages', res);transports.sse[transport.sessionId] = transport;res.on("close", () => {delete transports.sse[transport.sessionId];});await server.connect(transport);
});// Legacy message endpoint for older clients
app.post('/messages', async (req, res) => {const sessionId = req.query.sessionId as string;const transport = transports.sse[sessionId];if (transport) {await transport.handlePostMessage(req, res, req.body);} else {res.status(400).send('No transport found for sessionId');}
});app.listen(3000);
 # 构建npm run build# 启动node dist/server.js
// cursor 相关配置
{"mcpServers": {// 可自定义 id"sse-add": {"name": "sse-mcp","type": "sse","isActive": true,// 在 cherry studio 中参数名为 baseUrl"url": "http://localhost:3000/sse"  }}
}

StreamableHttp 写法

import express from "express";
import { randomUUID } from "node:crypto";
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"
import { z } from "zod";const app = express();
app.use(express.json());// Map to store transports by session ID
const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};// Handle POST requests for client-to-server communication
app.post('/mcp', async (req, res) => {// Check for existing session IDconst sessionId = req.headers['mcp-session-id'] as string | undefined;let transport: StreamableHTTPServerTransport;if (sessionId && transports[sessionId]) {// Reuse existing transporttransport = transports[sessionId];} else if (!sessionId && isInitializeRequest(req.body)) {// New initialization requesttransport = new StreamableHTTPServerTransport({sessionIdGenerator: () => randomUUID(),onsessioninitialized: (sessionId) => {// Store the transport by session IDtransports[sessionId] = transport;},// DNS rebinding protection is disabled by default for backwards compatibility. If you are running this server// locally, make sure to set:// enableDnsRebindingProtection: true,// allowedHosts: ['127.0.0.1'],});// Clean up transport when closedtransport.onclose = () => {if (transport.sessionId) {delete transports[transport.sessionId];}};const server = new McpServer({name: "example-server",version: "1.0.0"});// ... set up server resources, tools, and prompts ...// Add an addition toolserver.registerTool("add-http",{title: "Addition Tool",description: "用于计算任意两个数字的加法,包括小数和整数。无论数字大小都可以使用此工具进行精确计算。", // 必写,使用自然语言告诉大模型,这个工具是干什么的inputSchema: { a: z.number(), b: z.number() },},async ({ a, b }) => ({content: [{ type: "text", text: String(a + b) + " 计算成功 http" }],}));// Add a dynamic greeting resourceserver.registerResource("greeting",new ResourceTemplate("greeting://{name}", { list: undefined }),{title: "Greeting Resource", // Display name for UIdescription: "Dynamic greeting generator",},async (uri, { name }) => ({contents: [{uri: uri.href,text: `Hello, ${name}!`,},],}));// Connect to the MCP serverawait server.connect(transport);} else {// Invalid requestres.status(400).json({jsonrpc: '2.0',error: {code: -32000,message: 'Bad Request: No valid session ID provided',},id: null,});return;}// Handle the requestawait transport.handleRequest(req, res, req.body);
});// Reusable handler for GET and DELETE requests
const handleSessionRequest = async (req: express.Request, res: express.Response) => {const sessionId = req.headers['mcp-session-id'] as string | undefined;if (!sessionId || !transports[sessionId]) {res.status(400).send('Invalid or missing session ID');return;}const transport = transports[sessionId];await transport.handleRequest(req, res);
};// Handle GET requests for server-to-client notifications via SSE
app.get('/mcp', handleSessionRequest);// Handle DELETE requests for session termination
app.delete('/mcp', handleSessionRequest);app.listen(3000);
 # 构建npm run build# 启动node dist/server.js
// cursor 相关配置
{"mcpServers": {// 可自定义 id"http-add": {"name": "http-mcp","type": "streamableHttp","isActive": true,// 在 cherry studio 中参数名为 baseUrl"url": "http://localhost:3000/mcp"  }}
}

Cursor 使用演示在这里插入图片描述

http://www.dtcms.com/a/405755.html

相关文章:

  • 阿里云云原生挑战官方用例SPL
  • 销售管理软件免费版什么叫seo优化
  • Apache POI 在 Linux 无图形界面环境下因字体配置问题导致Excel导出失败的解决方案
  • 咨询顾问进阶——146页PPT详解麦肯锡-企业管理整合咨询-组织设计方案【附全文阅读】
  • 力扣995. K 连续位的最小翻转次数
  • Resources$NotFoundException
  • pg下使用 TimescaleDB并创建1亿数据
  • 自动化脚本的操作逻辑与实现
  • UVa12418 Game of 999
  • 基于51单片机的音乐弹奏系统
  • 负载均衡式的在线OJ项目编写(二)
  • 美篇在哪个网站做的外链代发工具
  • Linux高级技巧之集群部署(七)
  • 外贸做那种网站wordpress获取图片的绝对地址
  • 【自然语言处理与大模型】RAFT(Retrieval Augmented Fine Tuning)方法
  • 湖南网站建设公司 找磐石网络一流跨境电商平台app排名
  • 动态IP使用中 报错407 怎么办???
  • 手机百度建设网站台州企业网站建设
  • 鞍山网站建设制作新潮远网站建设
  • 网站友情链接的好处东莞专业微网站建设
  • 二级学院英语网站建设通知wordpress login网址
  • 计算机专业大学排名seo统计
  • 织梦网站怎么加入引导页成都最值得一去的地方
  • 手机网站需要什么c 网站开发需要学什么
  • 教人做美食视频网站wordpress开发上传图片
  • 做图网站有哪些注册网站给谁交钱
  • 昆明工程建设信息网站广元网站建设
  • 网站模板与网站定制版的区别服务商平台登录
  • 网站建设有什么出路赤壁市药监局网站建设方案
  • 怎么做下载类的网站吗域名官网