打造你自己的第一个 MCP Server:Stdio 与 SSE 两种方式

半兽人 发表于: 2025-04-23   最后更新时间: 2025-12-02 13:54:36  
{{totalSubscript}} 订阅, 203 游览

通过两个实例构建自己的 MCP Server:

  • 基于标准输入输出的轻量服务Stdio。
  • 通过 HTTP SSE(Server-Sent Events)支持前端连接,实现更复杂的交互。

MCP 简介

MCP(Model Context Protocol)是一种协议标准,旨在为 LLM 提供更丰富、更结构化的上下文支持。它支持三种主要功能类型:

  • Resources:公开数据,用于将信息加载到 LLM 的上下文中(可以将其视为 GET 端点)
  • Tools:提供功能,供 LLM 调用的函数。
  • Prompts:通过提示词定义交互模式(可重复使用的LLM交互模板)。

SDK封装好了协议内部细节(JSON-RPC 2.0),包括架构分层,开发者直接写一些业务代码就可以了。
https://github.com/modelcontextprotocol/typescript-sdk

示例一:基于 stdio 的 MCP Server

src/demo-stdio.js

这是一个最简版本的 MCP Server,通过标准输入输出(stdin/stdout)进行通信。

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",
    version: "1.0.0"
});

server.tool("add", 'Add two numbers', { a: z.number(), b: z.number() },
    async ({ a, b }) => ({
        content: [{ type: "text", text: String(a + b) }]
    })
);

async function main() {
    const transport = new StdioServerTransport();
    await server.connect(transport);
}

main()

这段代码中,tool() 声明了一个简单的加法功能,StdioServerTransport 处理 stdin/stdout 通信。

初始化依赖:

pnpm init
pnpm add zod
pnpm add @modelcontextprotocol/sdk

调试方法

如果写好了代码,怎么调试这个Server呢?官方提供了一个调试器:

npx @modelcontextprotocol/inspector

运行后,访问调试器页面:

Starting MCP inspector...
⚙️ Proxy server listening on localhost:6277
🔑 Session token: a45ed6e4cbe32b213673aa5ae189fd4639648f8a81ec80181c357177d3a00db4
   Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth

🚀 MCP Inspector is up and running at:
   http://localhost:6274

我的前端项目结构如下:

.
├── package.json
├── pnpm-lock.yaml
└── src
    └── demo-stdio.js

基于你自己的位置调整:

  • Command:node
  • Arguments:src/demo-stdio.js

配置session(从运行调试器日志里获取):
mcp session配置

点击:Connect

可以看到已经调用成功。

示例二:基于 SSE 的 HTTP Server

创建文件 src/exchange.ts

import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";

const server = new McpServer({
    name: "demo-sse",
    version: "1.0.0"
});

server.tool("exchange", '人民币汇率换算', { rmb: z.number() },
    async ({ rmb }) => {
        // 使用固定汇率进行演示,实际应该调用汇率API
        const usdRate = 0.14; // 1人民币约等于0.14美元
        const hkdRate = 1.09; // 1人民币约等于1.09港币

        const usd = (rmb * usdRate).toFixed(2);
        const hkd = (rmb * hkdRate).toFixed(2);

        return {
            content: [{
                type: "text",
                text: `${rmb}人民币等于:\n${usd}美元\n${hkd}港币`
            }]
        }
    },
);
const app = express();
const sessions: Record<string, { transport: SSEServerTransport; response: express.Response }> = {}
app.get("/sse", async (req, res) => {
    console.log(`New SSE connection from ${req.ip}`);
    const sseTransport = new SSEServerTransport("/messages", res);
    const sessionId = sseTransport.sessionId;
    if (sessionId) {
        sessions[sessionId] = { transport: sseTransport, response: res }
    }
    await server.connect(sseTransport);
});

app.post("/messages", async (req, res) => {
    const sessionId = req.query.sessionId as string;
    const session = sessions[sessionId];
    if (!session) {
        res.status(404).send("Session not found");
        return;
    }

    await session.transport.handlePostMessage(req, res);
});

app.listen(3001);

添加依赖

pnpm add express
pnpm add -D @types/express
  • 这是 Express 框架的主包,实际运行服务所需要的。
  • @types/express:让 TypeScript 能识别 express 的类型,开发体验更好,也能避免类型相关的报错。

编译配置

安装 TypeScript(作为开发依赖):

pnpm add typescript -D

初始化 TypeScript,可以用下面命令生成:

pnpm exec tsc --init

修改生成的 tsconfig.json

{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

我修改了 "outDir": "./dist"./dist 目录。

编译代码:

pnpm exec tsc

src/exchange.ts 编译成 dist/exchange.js

执行:

node dist/exchange.js

没有报错就是正常运行了。

访问地址:

http://127.0.0.1:3001/sse

控制台输出如下:

event: endpoint
data: /messages?sessionId=b42287de-fc9a-4626-bdea-47de5dc2aaa9

成功了!

另外

另外,我的package.json是下面的,供你参考:

{
  "name": "mcp-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/exchange.js",
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "packageManager": "pnpm@10.8.1",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.10.2",
    "express": "^5.1.0",
    "zod": "^3.24.3"
  },
  "devDependencies": {
    "@types/express": "^5.0.1",
    "ts-node": "^10.9.2"
  }
}

如果你要放到其他地方运行,可能需要tsc换成tsup,tsup 可以把它打包成一个完整文件,在别的机器上跑起来不需要源码。

加入tsup命令:

pnpm add -D tsup

构建命令:

tsup src/exchange.ts --format cjs --out-dir dist --dts false

接下来

MCP
更新于 2025-12-02

查看MCP更多相关的文章或提一个关于MCP的问题,也可以与我们一起分享文章