Tạo một đại diện AI với MCP và TypeScript vào năm 2026

The Model Context Protocol đã vượt qua 97 triệu lượt tải SDK hàng tháng vào năm 2026. Hầu hết các hướng dẫn đều tập trung vào bên máy chủ — đăng ký công cụ và hiển thị chúng thông qua MCP. Hướng dẫn này sẽ đề cập đến nửa còn lại: xây dựng một đại diện kết nối đến các máy chủ, phát hiện các công cụ có sẵn tại thời gian chạy và gửi yêu cầu tool_use của Claude thông qua API khách MCP.
Bạn sẽ kết thúc bằng một chương trình TypeScript:
Khởi tạo một quy trình máy chủ MCP (transport stdio)
Gọi
listTools()để phát hiện các công cụ có sẵnĐưa ra một dấu nhắc người dùng cho Claude với các công cụ được gắn vào
Đoán các phản hồi
tool_usecủa ClaudeĐường dẫn mỗi cuộc gọi công cụ qua
callTool()trên khách hàng MCPTrả kết quả công cụ trở lại cho Claude để có một phản hồi cuối cùng
Yêu cầu trước
Node.js 20 hoặc sau đó
Một khóa API Anthropic (
ANTHROPIC_API_KEYtrong môi trường)Ngôn ngữ máy chủ MCP nào đó (hướng dẫn này sử dụng một máy chủ ví dụ tối thiểu, nhưng mô hình này hoạt động với bất kỳ máy chủ nào)
Cài đặt dự án
mkdir mcp-agent && cd mcp-agent
npm init -y
Cập nhật package.json để sử dụng mô-đun ES:
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node dist/agent.js"
}
}
Cài đặt phụ thuộc:
npm install @modelcontextprotocol/sdk @anthropic-ai/sdk
npm install -D typescript @types/node
Định dạng phiên bản từ npm registry vào ngày 05-05-2026:
@modelcontextprotocol/sdk: 1.29.0@anthropic-ai/sdk: 0.93.0
Tạo tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}
Cơ bản về Khách hàng MCP
SDK TypeScript tách máy chủ và khách hàng thành các điểm nhập riêng biệt:
// Máy chủ (các công cụ cung cấp nhập)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
// Khách hàng (các đại diện nhập)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
Transport khách hàng kết nối đến máy chủ bằng cách khởi tạo nó như một tiến trình con qua stdio. Điều này có nghĩa đại diện của bạn khởi tạo máy chủ, giao tiếp qua stdin/stdout và tiến trình máy chủ kết thúc khi đại diện thoát.
Tạo Agent: src/agent.ts
import Anthropic từ "@anthropic-ai/sdk";
import { Client } từ "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } từ "@modelcontextprotocol/sdk/client/stdio.js";
const anthropic = new Anthropic();
async function runAgent(userMessage: string, serverCommand: string, serverArgs: string[]) {
// Bước 1: Kết nối đến máy chủ MCP
const transport = new StdioClientTransport({
command: serverCommand,
args: serverArgs,
});
const mcp = new Client({ name: "mcp-agent", version: "1.0.0" });
await mcp.connect(transport);
// Bước 2: Khám phá các công cụ có sẵn
const { tools } = await mcp.listTools();
// Chuyển đổi các lược đồ công cụ MCP sang định dạng công cụ của Anthropic
const anthropicTools: Anthropic.Tool[] = tools.map((t) => ({
name: t.name,
description: t.description ?? "",
input_schema: t.inputSchema as Anthropic.Tool["input_schema"],
}));
console.log(`Kết nối thành công. ${tools.length} công cụ có sẵn: ${tools.map((t) => t.name).join(", ")}`);
// Bước 3: Gọi Claude lần đầu tiên
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: userMessage },
];
let response = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 4096,
tools: anthropicTools,
messages,
});
// Bước 4: Vòng lặp agentic — tiếp tục cho đến khi Claude dừng sử dụng công cụ
while (response.stop_reason === "tool_use") {
const toolUseBlocks = response.content.filter(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
// Xây dựng kết quả công cụ bằng cách chuyển từng công cụ_use qua cuộc gọi MCP callTool
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const toolUse of toolUseBlocks) {
console.log(`Gọi công cụ: ${toolUse.name}`, toolUse.input);
// Bước 5: Thực hiện công cụ qua MCP
const result = await mcp.callTool({
name: toolUse.name,
arguments: toolUse.input as Record<string, unknown>,
});
const resultText = result.content
.filter((c): c is { type: "text"; text: string } => c.type === "text")
.map((c) => c.text)
.join("\n");
toolResults.push({
type: "tool_result",
tool_use_id: toolUse.id,
content: resultText,
});
}
// Bước 6: Gửi kết quả công cụ trở lại cho Claude
messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });
response = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 4096,
tools: anthropicTools,
messages,
});
}
await mcp.close();
// Lấy kết quả văn bản cuối cùng
const finalText = response.content
.filter((block): block is Anthropic.TextBlock => block.type === "text")
.map((block) => block.text)
.join("\n");
return finalText;
}
// Điểm nhập
const result = await runAgent(
process.argv[2] ?? "Bạn có những công cụ nào có sẵn?",
"node",
["./dist/server.js"]
);
console.log("\nKết quả của agent:\n", result);
Cài đặt Server Nhỏ (để thử nghiệm)
Bạn cần một máy chủ MCP để kết nối. Dưới đây là máy chủ nhỏ nhất có thể, chỉ exposing một công cụ đơn giản - một máy tính bỏ túi. Lưu nó dưới dạng src/server.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "calc-server", version: "1.0.0" });
server.tool(
"add",
"Tính tổng hai số",
{ a: z.number().describe("Số thứ nhất"), b: z.number().describe("Số thứ hai") },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
})
);
const transport = new StdioServerTransport();
await server.connect(transport);
Xây dựng và Chạy
npm run build
node dist/agent.js "Tính 42 cộng 17?"
Kết quả mong đợi:
Kết nối thành công. Có 1 công cụ có sẵn: add
Gọi công cụ: add { a: 42, b: 17 }
Đáp án của Agent:
42 cộng 17 bằng 59.
Cách Lặp Của Agentic Là Làm Thế Nào
Cấu trúc vòng lặp quan trọng. Claude sẽ gọi nhiều công cụ liên tiếp trước khi có đủ thông tin để trả lời cuối cùng. Vòng lặp while (response.stop_reason === "tool_use") xử lý điều này:
Claude trả về
stop_reason: "tool_use"với một hoặc nhiều khối nội dungtool_useỨng dụng thực hiện mỗi công cụ qua
mcp.callTool()Kết quả được thêm vào lịch sử tin nhắn dưới dạng các khối
tool_resultClaude nhận được lịch sử được cập nhật và quyết định có gọi thêm công cụ hay trả lời cuối cùng
Khi
stop_reasontrở thành"end_turn", vòng lặp kết thúc
Sử Dụng Máy Chủ MCP Thực
Mã ứng dụng kết nối với bất kỳ máy chủ MCP nào - chỉ cần thay đổi lệnh. Dưới đây là một số máy chủ phổ biến từ hệ sinh thái:
Truy cập hệ thống tệp:
npx @modelcontextprotocol/server-filesystem /path/to/allowed/directory
Công cụ GitHub:
npx @modelcontextprotocol/server-github
Cơ sở dữ liệu (Postgres):
npx @modelcontextprotocol/server-postgres postgresql://localhost/mydb
Cập nhật lệnh gọi ứng dụng với lệnh và tham số phù hợp:
const result = await runAgent(
"Danh sách các tệp markdown trong thư mục hiện tại",
"npx",
["@modelcontextprotocol/server-filesystem", process.cwd()]
);
Kết Nối Với Máy Chủ MCP Trực Tuyến (HTTP Streamable)
Transport stdio tạo ra một quy trình cục bộ. Để sử dụng với các máy chủ MCP ở xa hoặc được lưu trữ trên đám mây, hãy sử dụng transport HTTP thay thế:
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
new URL("https://your-mcp-server.example.com/mcp")
);
Còn lại mã của agent là giống nhau — API Client là vô cùng độc lập với transport.
Khám Phá Công Cụ Trước Khi Viết Mã
MCP Inspector giúp dễ dàng khám phá bất kỳ máy chủ nào trong bộ sưu tập công cụ trước khi viết mã agent:
npx @modelcontextprotocol/inspector node ./dist/server.js
Inspector mở một giao diện trình duyệt cho thấy tất cả công cụ được đăng ký, lược đồ của chúng và một biểu mẫu để thử nghiệm từng công cụ một cách thủ công.
Những Điều Cần Xây Dựng Tiếp Theo
Agent trên là vô trạng thái — nó xử lý một câu hỏi và thoát. Để mở rộng nó thành một agent trò chuyện, có nghĩa là giữ mảng messages sống sót qua các vòng lặp và tái sử dụng kết nối MCP. Từ đó, bạn có thể thêm:
Lọc công cụ: Chuyển chỉ tập hợp các công cụ MCP liên quan đến nhiệm vụ hiện tại
Hỗ trợ nhiều máy chủ: Kết nối với nhiều máy chủ MCP và hợp nhất danh sách công cụ của chúng
Trả lời trực tuyến: Chuyển sang
anthropic.messages.stream()để có kết quả trực tuyếnTồn tại: Lưu lại lịch sử cuộc trò chuyện vào một tệp hoặc cơ sở dữ liệu giữa các phiên
Biện pháp khách hàng MCP giữ mã của agent mỏng. Công cụ sống trong máy chủ có thể được cập nhật, thay thế hoặc hoán đổi mà không chạm vào logic của agent.
Phiên bản SDK được xác minh từ npm registry vào ngày 2026-05-05: @modelcontextprotocol/sdk@1.29.0, @anthropic-ai/sdk@0.93.0. Mẫu mã được xác minh theo tài liệu chính thức SDK TypeScript MCP và tài liệu nền tảng Anthropic.
