Xây dựng máy chủ & máy khách MCP tùy chỉnh bằng TypeScript: Công cụ, tài nguyên & kiến trúc Prompt

Mục lục bài viết(25 mục)
Giao thức Ngữ cảnh Mô hình (Model Context Protocol - MCP) định nghĩa một giao diện chuẩn cho các Mô hình Ngôn ngữ Lớn (LLM) để tương tác với các công cụ bên ngoài, truy cập tài nguyên động và nhận ngữ cảnh có cấu trúc. Tài liệu này trình bày chi tiết việc xây dựng các máy chủ và máy khách MCP tùy chỉnh bằng TypeScript, tập trung vào @modelcontextprotocol/sdk, cơ chế truyền tải, bảo mật và kiến trúc lời nhắc.
Tìm hiểu các Cơ chế Truyền tải MCP: Stdio so với SSE
MCP hỗ trợ nhiều lớp truyền tải. Các cơ chế chính cho việc triển khai tùy chỉnh là Stdio và Server-Sent Events (SSE). Mỗi cơ chế đều có những ưu điểm và đặc tính hoạt động riêng biệt.
Truyền tải Stdio
Stdio (Standard Input/Output) là một cơ chế đồng bộ, yêu cầu-phản hồi. Nó lý tưởng cho các môi trường thực thi cục bộ, công cụ CLI hoặc các kịch bản mà một tiến trình duy nhất, liên tục quản lý tương tác LLM. Máy khách gửi yêu cầu JSON-RPC qua stdin và máy chủ phản hồi qua stdout.
Ưu điểm:
- Đơn giản cho phát triển và gỡ lỗi cục bộ.
- Chi phí thấp cho các tương tác một lần.
- Tích hợp trực tiếp với các mô hình thực thi tiến trình.
Nhược điểm:
- Khả năng mở rộng hạn chế cho các yêu cầu đồng thời.
- Không phù hợp cho các hệ thống dựa trên web hoặc phân tán nếu không có sự điều phối đáng kể.
- Xử lý lỗi có thể phức tạp hơn do quản lý vòng đời tiến trình.
Truyền tải SSE
SSE (Server-Sent Events) cung cấp một cơ chế truyền phát sự kiện một chiều qua HTTP. Nó rất phù hợp cho các máy khách dựa trên web, các kết nối lâu dài và các kịch bản yêu cầu cập nhật liên tục hoặc thực thi công cụ không đồng bộ. Máy khách thiết lập kết nối HTTP và máy chủ đẩy các sự kiện.
Ưu điểm:
- Có thể mở rộng cho nhiều máy khách đồng thời.
- Hỗ trợ gốc cho môi trường web.
- Phân phối sự kiện không đồng bộ, phù hợp cho việc truyền phát đầu ra công cụ hoặc cập nhật tài nguyên.
- Xử lý lỗi mạnh mẽ và cơ chế kết nối lại vốn có của HTTP.
Nhược điểm:
- Yêu cầu cơ sở hạ tầng máy chủ HTTP.
- Thiết lập phức tạp hơn Stdio cho các trường hợp sử dụng cục bộ cơ bản.
- Một chiều; giao tiếp từ máy khách đến máy chủ yêu cầu các yêu cầu HTTP riêng biệt (ví dụ: POST).
Xây dựng Máy chủ MCP tùy chỉnh với @modelcontextprotocol/sdk
@modelcontextprotocol/sdk cung cấp các thành phần cơ bản để triển khai máy chủ và máy khách MCP trong TypeScript. Chúng ta sẽ tập trung vào việc xây dựng một máy chủ hiển thị các công cụ và tài nguyên động.
Kiến trúc Máy chủ cốt lõi
Một máy chủ MCP thường bao gồm:
- Lớp Truyền tải: Xử lý các yêu cầu đến và phản hồi đi (Stdio hoặc SSE).
- Bộ xử lý Công cụ: Các hàm thực thi các hoạt động cụ thể được LLM yêu cầu.
- Nhà cung cấp Tài nguyên: Các cơ chế để hiển thị dữ liệu hoặc lược đồ động cho LLM.
- Bảo mật & Xác thực: Đảm bảo các yêu cầu được ủy quyền và đầu vào được làm sạch.
Hãy cùng xây dựng một máy chủ MCP cơ bản dựa trên SSE.
// src/server.ts
import {
createMCPSSEServer,
MCPTool,
MCPResource,
MCPContext,
MCPError,
MCPErrorCode,
} from '@modelcontextprotocol/sdk';
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import { z } from 'zod'; // For schema validation
// --- 1. Define Tool Handlers ---
// Tools are functions the LLM can call. They must have a schema for arguments.
// Tool: `searchWeb`
const searchWebArgsSchema = z.object({
query: z.string().describe('The search query to execute.'),
numResults: z.number().int().min(1).max(10).optional().default(3).describe('Number of search results to return.'),
});
const searchWebTool: MCPTool<typeof searchWebArgsSchema> = {
name: 'searchWeb',
description: 'Performs a web search and returns relevant results.',
argsSchema: searchWebArgsSchema,
handler: async (args, context: MCPContext) => {
console.log(`[Tool] searchWeb called with query: "${args.query}", results: ${args.numResults}`);
// In a real scenario, this would call an external search API.
// For demonstration, we return mock data.
const mockResults = [
{ title: `Result 1 for "${args.query}"`, url: `https://example.com/search/${args.query}/1` },
{ title: `Result 2 for "${args.query}"`, url: `https://example.com/search/${args.query}/2` },
{ title: `Result 3 for "${args.query}"`, url: `https://example.com/search/${args.query}/3` },
];
return mockResults.slice(0, args.numResults);
},
};
// Tool: `createFile`
const createFileArgsSchema = z.object({
path: z.string().describe('The full path including filename where the file should be created.'),
content: z.string().describe('The content to write into the file.'),
overwrite: z.boolean().optional().default(false).describe('Whether to overwrite the file if it already exists.'),
});
const createFileTool: MCPTool<typeof createFileArgsSchema> = {
name: 'createFile',
description: 'Creates a new file with specified content at a given path.',
argsSchema: createFileArgsSchema,
handler: async (args, context: MCPContext) => {
console.log(`[Tool] createFile called: ${args.path}, overwrite: ${args.overwrite}`);
// Simulate file system interaction. In production, use `fs.promises`.
if (!args.overwrite && args.path.includes('existing-file.txt')) { // Mock existing file
throw new MCPError(MCPErrorCode.RESOURCE_CONFLICT, `File already exists at ${args.path}. Set overwrite to true.`);
}
return { success: true, message: `File '${args.path}' created/updated.` };
},
};
// --- 2. Define Dynamic Resources ---
// Resources provide structured data or schemas that the LLM can query.
// Resource: `projectFiles`
const projectFilesResource: MCPResource = {
name: 'projectFiles',
description: 'Lists files and directories within the current project context.',
schema: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Name of the file or directory.' },
type: { type: 'string', enum: ['file', 'directory'], description: 'Type of the entry.' },
size: { type: 'number', description: 'Size in bytes (for files).' },
lastModified: { type: 'string', format: 'date-time', description: 'Last modification timestamp.' },
},
required: ['name', 'type'],
},
},
// The `get` method is called when the LLM requests this resource.
get: async (context: MCPContext) => {
console.log('[Resource] projectFiles requested.');
// In a real application, this would scan the project directory.
return [
{ name: 'src/', type: 'directory', lastModified: new Date().toISOString() },
{ name: 'src/server.ts', type: 'file', size: 4096, lastModified: new Date().toISOString() },
{ name: 'package.json', type: 'file', size: 1024, lastModified: new Date().toISOString() },
{ name: 'README.md', type: 'file', size: 2048, lastModified: new Date().toISOString() },
];
},
};
// --- 3. Initialize MCP SSE Server ---
const app = express();
app.use(cors()); // Enable CORS for web clients
app.use(bodyParser.json()); // Parse JSON request bodies
const mcpServer = createMCPSSEServer({
tools: [searchWebTool, createFileTool],
resources: [projectFilesResource],
// Optional: Implement an authentication/authorization middleware
// This example uses a simple token check.
authenticate: async (token: string | undefined) => {
if (token === 'my-secret-api-key') {
return { userId: 'dev-user', roles: ['admin'] }; // Return user context
}
throw new MCPError(MCPErrorCode.UNAUTHENTICATED, 'Invalid or missing authentication token.');
},
// Optional: Custom error handler for tool/resource execution
onError: (error: Error) => {
console.error('MCP Server Error:', error);
// You might want to log this to a monitoring system.
},
});
// Mount the MCP server routes
app.use('/mcp', mcpServer.router);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`MCP SSE Server listening on http://localhost:${PORT}/mcp`);
console.log(`Tools available: ${mcpServer.getToolNames().join(', ')}`);
console.log(`Resources available: ${mcpServer.getResourceNames().join(', ')}`);
});
// To run this:
// 1. npm init -y
// 2. npm install @modelcontextprotocol/sdk express body-parser cors zod
// 3. ts-node src/server.ts (or compile and run with node)
Hiển thị Bộ xử lý Công cụ
Bộ xử lý công cụ là các hàm không đồng bộ thực thi logic dựa trên các đối số được LLM cung cấp. Thuộc tính argsSchema, thường được định nghĩa bằng zod, rất quan trọng để xác thực đầu vào và để LLM hiểu các tham số của công cụ.
// Example tool handler structure
const myTool: MCPTool<typeof myArgsSchema> = {
name: 'myTool',
description: 'Does something useful.',
argsSchema: myArgsSchema,
handler: async (args, context) => {
// `args` is type-safe due to `myArgsSchema`
// `context` contains information about the current MCP session (e.g., authentication)
console.log('Tool called with:', args);
// Perform operations, e.g., API calls, file system access
return { status: 'success', data: 'some result' };
},
};
Định nghĩa Lược đồ Tài nguyên Động
Tài nguyên cho phép LLM truy vấn thông tin động. Thuộc tính schema mô tả cấu trúc dữ liệu được trả về bởi phương thức get. Lược đồ này được cung cấp cho LLM, cho phép nó hiểu và truy vấn tài nguyên một cách hiệu quả.
// Example resource structure
const myResource: MCPResource = {
name: 'myResource',
description: 'Provides dynamic data.',
schema: {
type: 'object',
properties: {
id: { type: 'string' },
value: { type: 'number' },
},
required: ['id', 'value'],
},
get: async (context) => {
// Fetch or generate dynamic data
return [{ id: 'item1', value: 123 }, { id: 'item2', value: 456 }];
},
};
Tích hợp với Máy khách LLM: Claude Code, Cursor và Các Tác nhân Tùy chỉnh
Sức mạnh của MCP nằm ở khả năng tương tác của nó.
Tích hợp Claude Code & Cursor
Các IDE Claude Code và Cursor của Anthropic được thiết kế để sử dụng các máy chủ MCP. Khi bạn khởi động một máy chủ MCP (đặc biệt là máy chủ SSE), các máy khách này có thể được cấu hình để kết nối với điểm cuối của nó. Chúng sẽ tự động khám phá các công cụ và tài nguyên được hiển thị, làm cho chúng có sẵn để LLM sử dụng trong ngữ cảnh IDE.
Ví dụ, trong Cursor, bạn có thể cấu hình một điểm cuối MCP trong cài đặt của nó, trỏ đến http://localhost:3000/mcp. IDE sau đó hoạt động như một máy khách MCP, chuyển tiếp các yêu cầu LLM đến máy chủ của bạn và hiển thị kết quả.
Các Runtime Tác nhân Tùy chỉnh
Đối với các runtime tác nhân tùy chỉnh, bạn sẽ sử dụng máy khách @modelcontextprotocol/sdk.
// src/client.ts
import { createMCPClient, MCPClientOptions } from '@modelcontextprotocol/sdk';
async function runMCPClient() {
const clientOptions: MCPClientOptions = {
// For SSE, specify the base URL of your MCP server
// For Stdio, you'd pass `process.stdin` and `process.stdout`
transport: {
type: 'sse',
baseUrl: 'http://localhost:3000/mcp',
headers: {
'Authorization': 'Bearer my-secret-api-key', // Include authentication token
},
},
// Optional: Logger for debugging
logger: console,
};
const client = createMCPClient(clientOptions);
try {
// --- 1. Get available tools and resources ---
const tools = await client.getTools();
console.log('Available Tools:', tools.map(t => t.name));
const resources = await client.getResources();
console.log('Available Resources:', resources.map(r => r.name));
// --- 2. Call a tool ---
console.log('\nCalling searchWeb tool...');
const searchResults = await client.callTool('searchWeb', { query: 'MCP protocol best practices', numResults: 2 });
console.log('Search Results:', searchResults);
// --- 3. Get a resource ---
console.log('\nGetting projectFiles resource...');
const projectFiles = await client.getResource('projectFiles');
console.log('Project Files:', projectFiles);
// --- 4. Handle errors ---
console.log('\nCalling createFile tool with conflict...');
try {
await client.callTool('createFile', { path: 'existing-file.txt', content: 'new content' });
} catch (error: any) {
console.error('Error calling createFile:', error.message);
}
console.log('\nCalling createFile tool with overwrite...');
const createResult = await client.callTool('createFile', { path: 'new-file.txt', content: 'Hello, MCP!', overwrite: true });
console.log('Create File Result:', createResult);
} catch (error) {
console.error('MCP Client Error:', error);
}
}
runMCPClient();
// To run this:
// 1. Ensure the server (src/server.ts) is running.
// 2. npm install @modelcontextprotocol/sdk
// 3. ts-node src/client.ts
Các Mẫu Lời nhắc Ngữ cảnh
MCP không trực tiếp định nghĩa các mẫu lời nhắc, nhưng nó cung cấp thông tin có cấu trúc cần thiết để LLM xây dựng các lời nhắc hiệu quả. LLM nhận được:
- Lược đồ Công cụ: Định nghĩa JSON Schema cho từng công cụ, bao gồm
name,descriptionvàargsSchema. - Lược đồ Tài nguyên: Định nghĩa JSON Schema cho từng tài nguyên, bao gồm
name,descriptionvà cấu trúc dữ liệu của nó. - Dữ liệu Tài nguyên: Dữ liệu thực tế được trả về khi một tài nguyên được
getbởi LLM.
Một mẫu lời nhắc được thiết kế tốt cho LLM sử dụng MCP có thể trông như thế này (khái niệm, cú pháp cụ thể của LLM):
You are an AI assistant with access to the following tools and resources:
<tools>
{{#each tools}}
<tool_code>
{
"name": "{{this.name}}",
"description": "{{this.description}}",
"parameters": {{json this.argsSchema}}
}
</tool_code>
{{/each}}
</tools>
<resources>
{{#each resources}}
<resource_code>
{
"name": "{{this.name}}",
"description": "{{this.description}}",
"schema": {{json this.schema}}
}
</resource_code>
{{/each}}
</resources>
<context>
{{#if currentResourceData}}
<resource_data name="{{currentResourceData.name}}">
{{json currentResourceData.data}}
</resource_data>
{{/if}}
</context>
Your goal is to assist the user by leveraging these capabilities.
If you need to perform an action, use the `<call_tool>` tag.
If you need to retrieve information, use the `<get_resource>` tag.
If you have retrieved information from a resource, it will appear in the `<context>` block.
User: {{user_query}}
Mẫu này tự động đưa các khả năng của máy chủ MCP vào, cho phép LLM suy luận về các hành động và cấu trúc dữ liệu có sẵn.
Ranh giới Bảo mật và Làm sạch Đầu vào
Bảo mật là tối quan trọng khi hiển thị các công cụ cho LLM.
-
Xác thực & Ủy quyền:
- Xác thực: Sử dụng khóa API, mã thông báo OAuth hoặc JWT để xác minh danh tính của máy khách. Hàm
authenticatetrongcreateMCPSSEServerlà điểm vào cho việc này. - Ủy quyền: Dựa trên vai trò hoặc quyền của người dùng đã được xác thực, hạn chế quyền truy cập vào các công cụ hoặc tài nguyên nhất định. Logic này thuộc về
handlercủa công cụ/tài nguyên hoặc một middleware.
typescript// Example: Authorization within a tool handler const restrictedTool: MCPTool<typeof someSchema> = { name: 'restrictedAction', description: 'Only for admins.', argsSchema: someSchema, handler: async (args, context: MCPContext) => { if (!context.user || !context.user.roles.includes('admin')) { throw new MCPError(MCPErrorCode.PERMISSION_DENIED, 'Only administrators can perform this action.'); } // ... execute admin action }, }; - Xác thực: Sử dụng khóa API, mã thông báo OAuth hoặc JWT để xác minh danh tính của máy khách. Hàm
-
Xác thực Đầu vào (Thực thi Lược đồ):
argsSchemacho các công cụ vàschemacho các tài nguyên là rất quan trọng.@modelcontextprotocol/sdktự động xác thực các đối số đến dựa trên các lược đồ này.- Sử dụng các thư viện xác thực lược đồ mạnh mẽ như
zodhoặcJoiđể định nghĩa các kiểu, phạm vi và mẫu nghiêm ngặt.
-
Làm sạch Đầu ra:
- Đảm bảo rằng bất kỳ dữ liệu nào được trả về bởi các công cụ hoặc tài nguyên không chứa thông tin nhạy cảm trừ khi được dự định và ủy quyền rõ ràng.
- Lọc hoặc biên tập dữ liệu trước khi trả về cho LLM nếu nó có thể bị lộ cho các bên không được ủy quyền hoặc được sử dụng theo những cách không mong muốn.
-
Đặc quyền Tối thiểu:
- Thiết kế các công cụ chỉ thực hiện các hành động cần thiết. Tránh tạo các công cụ "thần thánh" có thể làm bất cứ điều gì.
- Nếu một công cụ tương tác với các hệ thống bên ngoài (cơ sở dữ liệu, API, hệ thống tệp), hãy đảm bảo các thông tin xác thực hoặc quyền cơ bản được cấp cho tiến trình máy chủ càng hạn chế càng tốt.
-
Giới hạn Tốc độ & Ngăn chặn Lạm dụng:
- Triển khai giới hạn tốc độ trên các điểm cuối máy chủ MCP của bạn để ngăn chặn các cuộc tấn công từ chối dịch vụ hoặc tiêu thụ tài nguyên quá mức bởi các tác nhân hoạt động sai.
- Giám sát việc sử dụng công cụ để tìm các mẫu bất thường.
Những Vấn đề và Khắc phục sự cố trong Sản xuất
1. MCPError: UNAUTHENTICATED hoặc PERMISSION_DENIED
Chế độ lỗi: Máy khách nhận được lỗi xác thực hoặc quyền. Khắc phục:
- Xác thực: Xác minh tiêu đề
Authorizationtrong yêu cầu máy khách của bạn khớp với mã thông báo dự kiến trong hàmauthenticatecủa bạn. Đảm bảo mã thông báo được truyền chính xác. - Ủy quyền: Kiểm tra đối tượng
context.usertrong các bộ xử lý công cụ/tài nguyên của bạn. Đảm bảo người dùng có các vai trò hoặc quyền cần thiết cho hành động được yêu cầu. Gỡ lỗi logic trongauthenticatevà các hàm xử lý của bạn.
2. MCPError: INVALID_ARGUMENTS
Chế độ lỗi: Các lệnh gọi công cụ thất bại do đối số không khớp. Khắc phục:
- LLM đã cung cấp các đối số không tuân thủ
argsSchemacủa bạn. - Phía máy chủ: Kiểm tra lại các định nghĩa lược đồ
zodcủa bạn. Tất cả các trường bắt buộc có mặt không? Các kiểu có đúng không (chuỗi, số, boolean)? Có bất kỳ ràng buộcmin/maxnào bị vi phạm không? - Phía máy khách (LLM): Nếu bạn đang xây dựng một tác nhân tùy chỉnh, hãy đảm bảo logic gọi công cụ của tác nhân của bạn trích xuất và định dạng các đối số chính xác theo lược đồ. Nếu sử dụng IDE, LLM có thể đang tạo ra các đối số; tinh chỉnh lời nhắc hoặc mô tả công cụ của bạn.
3. MCPError: TOOL_EXECUTION_FAILED hoặc RESOURCE_GET_FAILED
Chế độ lỗi: Logic bộ xử lý công cụ/tài nguyên ném ra một ngoại lệ không được xử lý. Khắc phục:
- Phía máy chủ: Triển khai các khối
try...catchmạnh mẽ trong các bộ xử lý công cụ và tài nguyên của bạn. Bắt các lỗi cụ thể (ví dụ: lỗi mạng từ API bên ngoài, lỗi hệ thống tệp) và trả về các mãMCPErrorhoặc thông báo có ý nghĩa. - Ghi nhật ký: Đảm bảo lệnh gọi lại
onErrorcủa bạn trongcreateMCPSSEServerđang ghi nhật ký các lỗi này một cách hiệu quả. Sử dụng một trình ghi nhật ký có cấu trúc.
4. Kết nối SSE bị ngắt hoặc không có sự kiện
Chế độ lỗi: Máy khách không nhận được sự kiện hoặc kết nối không ổn định. Khắc phục:
- CORS: Đảm bảo máy chủ Express của bạn có middleware
cors()được bật nếu máy khách của bạn ở một nguồn gốc khác. - Proxy/Tường lửa: Kiểm tra xem có bất kỳ proxy hoặc tường lửa nào đang can thiệp vào các kết nối HTTP lâu dài hoặc luồng sự kiện SSE hay không.
- Nhịp tim Máy chủ:
@modelcontextprotocol/sdkxử lý nhịp tim SSE, nhưng đảm bảo máy chủ của bạn không bị chấm dứt một cách mạnh mẽ bởi bộ cân bằng tải hoặc trình điều phối vùng chứa do nhận thấy không hoạt động. - Kết nối lại Máy khách: Đảm bảo việc triển khai SSE phía máy khách của bạn (hoặc máy khách của SDK) có logic tự động kết nối lại mạnh mẽ.
5. Giảm hiệu suất với Stdio
Chế độ lỗi: Phản hồi chậm hoặc hành vi chặn với truyền tải Stdio. Khắc phục:
- Stdio vốn dĩ đồng bộ trên mỗi tiến trình. Nếu bạn cần đồng thời, bạn phải quản lý nhiều tiến trình máy chủ (ví dụ: sử dụng trình quản lý tiến trình như PM2) hoặc chuyển sang SSE.
- Đảm bảo các bộ xử lý công cụ của bạn thực sự không đồng bộ và không chặn vòng lặp sự kiện.
So sánh Kiến trúc & Truyền tải
| Tính năng | Truyền tải Stdio | Truyền tải SSE |
|---|---|---|
| Giao tiếp | Hai chiều (yêu cầu/phản hồi) | Một chiều (luồng từ máy chủ đến máy khách) |
| Giao thức | JSON-RPC qua stdin/stdout | HTTP/1.1 (event-stream) |
| Đồng thời | Một yêu cầu trên mỗi tiến trình | Nhiều máy khách đồng thời |
| Khả năng mở rộng | Thấp (yêu cầu quản lý tiến trình) | Cao (mở rộng máy chủ HTTP tiêu chuẩn) |
| Trường hợp sử dụng | Công cụ CLI cục bộ, tác nhân một tiến trình | Máy khách web, tác nhân phân tán, cập nhật luồng |
| Độ phức tạp thiết lập | Thấp (I/O tiến trình cơ bản) | Trung bình (máy chủ HTTP, định tuyến, CORS) |
| Xử lý lỗi | Mã thoát tiến trình, lỗi JSON-RPC | Mã trạng thái HTTP, lỗi sự kiện SSE, kết nối lại máy khách |
| Xác thực | Ngoài băng tần (ví dụ: biến môi trường) | Tiêu đề HTTP (mã thông báo Bearer, cookie) |
| Chi phí mạng | Thấp (JSON thô) | Trung bình (tiêu đề HTTP, đóng khung) |
Các câu hỏi thường gặp
1. Tôi có thể sử dụng MCP với các LLM khác ngoài Claude của Anthropic không?
Có. Mặc dù Anthropic là người tiên phong trong MCP, giao thức này là mở và được thiết kế để tương tác. Bất kỳ LLM hoặc runtime tác nhân nào có khả năng phân tích cú pháp JSON Schema cho định nghĩa công cụ/tài nguyên và thực hiện các yêu cầu HTTP (đối với SSE) hoặc quản lý I/O tiến trình (đối với Stdio) đều có thể tích hợp với máy chủ MCP. Bạn sẽ cần điều chỉnh kỹ thuật lời nhắc của LLM để sử dụng hiệu quả các lược đồ do MCP cung cấp.
2. Làm cách nào để xử lý các tác vụ công cụ chạy dài?
Đối với các công cụ chạy dài, handler lý tưởng nhất nên trả về nhanh chóng với trạng thái cho biết hoạt động đã bắt đầu, sau đó sử dụng một cơ chế riêng biệt (ví dụ: webhook, thăm dò ý kiến hoặc một kênh SSE khác) để thông báo cho máy khách/LLM về việc hoàn thành hoặc tiến độ. Đặc tả MCP hiện tại chủ yếu hỗ trợ thực thi công cụ đồng bộ, trong đó giá trị trả về của bộ xử lý là kết quả cuối cùng. Đối với các tác vụ không đồng bộ, chạy dài thực sự, hãy xem xét:
- Một công cụ khởi tạo tác vụ và trả về
job_id. - Một công cụ khác
getJobStatus(job_id)mà LLM có thể thăm dò. - Hoặc, nếu máy khách của bạn hỗ trợ, đẩy các cập nhật qua một luồng SSE riêng biệt.
3. Có thể định nghĩa các mã lỗi tùy chỉnh ngoài MCPErrorCode không?
Enum MCPErrorCode cung cấp một tập hợp các lỗi tiêu chuẩn. Mặc dù bạn có thể trả về các thông báo lỗi tùy chỉnh trong MCPError, nhưng tốt nhất là nên ánh xạ các lỗi ứng dụng nội bộ của bạn đến MCPErrorCode gần nhất để duy trì tính nhất quán của giao thức. Nếu một điều kiện lỗi thực sự độc đáo phát sinh, bạn có thể sử dụng MCPErrorCode.INTERNAL_ERROR với một thông báo chi tiết.
4. Làm cách nào để quản lý trạng thái trên nhiều lệnh gọi công cụ trong một phiên MCP?
Đối tượng MCPContext được truyền đến các bộ xử lý công cụ và tài nguyên được thiết kế cho việc này. Bạn có thể đính kèm dữ liệu cụ thể của phiên vào đó. Đối với SSE, máy chủ duy trì một kết nối trên mỗi máy khách, cho phép bạn liên kết trạng thái với kết nối đó. Đối với Stdio, quản lý trạng thái thường là bên ngoài hoặc được truyền rõ ràng trong các yêu cầu tiếp theo nếu tiến trình tồn tại trong thời gian ngắn. Ví dụ, bạn có thể lưu trữ một session_id trong context và sử dụng nó để truy xuất dữ liệu từ một kho lưu trữ phụ trợ.
5. Các phương pháp hay nhất để quản lý phiên bản API máy chủ MCP của tôi là gì?
Hãy coi các công cụ và tài nguyên của máy chủ MCP của bạn như bất kỳ API nào khác.
- Tiến hóa Lược đồ: Thực hiện các thay đổi bổ sung cho lược đồ (ví dụ: thêm các trường tùy chọn) để duy trì khả năng tương thích ngược.
- Công cụ/Tài nguyên Mới: Giới thiệu các công cụ hoặc tài nguyên mới mà không làm hỏng các máy khách hiện có.
- Thay đổi Gây hỏng: Đối với các thay đổi gây hỏng (ví dụ: đổi tên công cụ, xóa trường bắt buộc), hãy xem xét:
- Triển khai phiên bản máy chủ mới trên một đường dẫn cơ sở khác (ví dụ:
/mcp/v1,/mcp/v2). - Sử dụng đàm phán nội dung (ít phổ biến hơn đối với MCP).
- Cung cấp các cảnh báo ngừng sử dụng rõ ràng.
- Triển khai phiên bản máy chủ mới trên một đường dẫn cơ sở khác (ví dụ:
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

Xây dựng một MCP Client tùy chỉnh: Kết nối bất kỳ LLM nào với nhiều Model Context Protocol Server
Hướng dẫn toàn diện về xây dựng một mcp client tùy chỉnh: kết nối bất kỳ llm nào với nhiều model context protocol server với kiến trúc cấp độ sản xuất và các ví dụ mã.
Read more
Xây dựng máy chủ MCP tùy chỉnh bằng TypeScript: Hướng dẫn kiến trúc & triển khai hoàn chỉnh
Hướng dẫn toàn diện về xây dựng máy chủ MCP tùy chỉnh bằng TypeScript, bao gồm kiến trúc và triển khai hoàn chỉnh với các ví dụ về kiến trúc và mã cấp độ sản xuất.
Read more
Xây dựng máy chủ MCP sản xuất trên Cloudflare Workers, KV & Durable Objects
Hướng dẫn toàn diện về xây dựng máy chủ mcp sản xuất trên Cloudflare Workers, KV & Durable Objects với kiến trúc cấp độ sản xuất và các ví dụ mã.
Read more