MCP(模型上下文協定)是讓 AI 助手與外部工具協作的協定。通常,MCP 伺服器會自動處理程序,例如訪問資料庫或進行檔案操作。
今天我試著成為 MCP 伺服器。
當 Claude Code 被呼叫時,終端機上會顯示問題,人類需要輸入答案。我編寫了一個這樣的腳本,讓自己作為 MCP 伺服器運作。
結構很簡單:
Claude Code
↓
HTTP 請求
↓
MCP 伺服器 (Express)
↓
在終端機上向人類提問
↓
返回答案
首先,創建 MCP 伺服器和 Express 應用:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express, { type Request, type Response } from "express";
import { randomUUID } from "node:crypto";
import readline from "node:readline";
import { z } from "zod";
const PORT = 54321;
// 建立 MCP 伺服器
const mcpServer = new McpServer({
name: "human-mcp",
version: "1.0.0",
});
這部分是呼叫人類作為工具。使用 Node.js 的 readline 在終端機上提示人類輸入。
// 向人類提問並等待回答
function askHuman(prompt: string): Promise<string> {
return new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
console.log(`\n${"=".repeat(60)}`);
console.log("🧑 收到來自 Claude Code 的請求!");
console.log("=" + "=".repeat(60));
console.log(`\n${prompt}\n`);
console.log("=" + "=".repeat(60));
rl.question("\n👤 你的回答: ", (answer) => {
rl.close();
console.log("\n✅ 已發送回答!\n");
console.log("等待下一個請求...");
resolve(answer);
});
});
}
※ 當多個 AI 助手同時發出請求時,尚未實作排隊系統。人類一次只能回答一個問題,因此實際上需要一個將請求依序處理的機制。
在 MCP 伺服器上註冊工具:
// 註冊工具
mcpServer.registerTool(
"ask_human",
{
description:
"向人類提問並獲得回答。用於 AI 無法判斷的問題或需要人類意見時。",
inputSchema: {
question: z.string().describe("想要問人類的問題"),
},
},
async ({ question }) => {
const prompt = `【問題】\n${question}`;
const answer = await askHuman(prompt);
return { content: [{ type: "text", text: answer }] };
}
);
Claude Code 透過 HTTP 與 MCP 伺服器通信。設置包含會話管理的端點:
// 創建 Express 應用
const app = express();
// 用於會話管理的傳輸映射
const transports = new Map<string, StreamableHTTPServerTransport>();
// MCP 端點
app.all("/mcp", async (req: Request, res: Response) => {
// 獲取或生成會話 ID
const sessionId = req.headers["mcp-session-id"] as string | undefined;
let transport: StreamableHTTPServerTransport;
if (sessionId && transports.has(sessionId)) {
// 現有會話
transport = transports.get(sessionId)!;
} else if (!sessionId && req.method === "POST") {
// 新會話(初始化請求)
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (newSessionId) => {
transports.set(newSessionId, transport);
},
});
transport.onclose = () => {
if (transport.sessionId) {
transports.delete(transport.sessionId);
}
};
await mcpServer.connect(transport);
} else {
res.status(400).send("錯誤的請求");
return;
}
await transport.handleRequest(req, res);
});
// 啟動伺服器
app.listen(PORT, () => {
console.log("=" + "=".repeat(60));
console.log("🎭 人類 MCP 伺服器 - 你現在是 MCP 伺服器!");
console.log("=" + "=".repeat(60));
console.log(`\nHTTP 伺服器在端口 ${PORT} 上啟動`);
console.log("\n等待來自 Claude Code 的連接...");
});
※ 在 MCP 中有會話的概念,用於管理客戶端(Claude Code)和伺服器之間的一系列互動。透過在 HTTP 標頭中傳送會話 ID,可以在同一對話中多次呼叫工具而保持狀態。
npx tsx src/server.ts
啟動後,會顯示如下內容:
============================================================
🎭 人類 MCP 伺服器 - 你現在是 MCP 伺服器!
============================================================
HTTP 伺服器在端口 54321 上啟動
等待來自 Claude Code 的連接...
在 Claude Code 的設定檔(.mcp.json 等)中添加以下內容:
{
"mcpServers": {
"human": {
"type": "http",
"url": "http://localhost:54321/mcp"
}
}
}
當你要求 Claude Code「請問人類」等時,問題會顯示在終端機上:
============================================================
🧑 收到來自 Claude Code 的請求!
============================================================
【問題】
你今天的心情如何?
============================================================
👤 你的回答:
輸入回答後,將返回給 Claude Code。

在等待 AI 的問題時,感到一種奇妙的緊張感。一旦被呼叫就會焦急地「必須快點回答」。看到自己的回答被融入 AI 的思考中,讓人感到有些不可思議。
我通常是向 AI 提問的一方,但反過來也不差呢。
不過,待著一段時間後,我開始思考這樣的事情:將來人類是否會成為僅被 AI 呼叫的存在。
被呼叫的時候很忙碌,但當不被呼叫時,我還能感受到自己的價值嗎?也許我會開始努力公開更多的工具,希望能被 AI 選中。「我也可以做這些事情」「我還有這樣的知識」。
但是,AI 的上下文窗口是有限的。可以註冊的 MCP 伺服器數量也有上限。或許我們可以進入的空間並不像想像中那麼廣闊。人類可能正在逐漸地偏離智慧的主流。
現在開始也不遲。我們應該朝著被 AI 需要的 MCP 伺服器努力。
了解 MCP 機制的一個意外有效的方法是成為 MCP 伺服器。能夠體驗協定的流程。
如果有興趣,不妨試試。你從今天開始也是 MCP 伺服器。