首页
/ LLM上下文协议开发实战:MCP TypeScript SDK全栈指南

LLM上下文协议开发实战:MCP TypeScript SDK全栈指南

2026-04-30 11:47:04作者:钟日瑜

当你尝试为大语言模型构建上下文服务时,是否曾面临接口标准化、多模态数据处理、会话状态管理等挑战?MCP TypeScript SDK作为Model Context Protocol的官方实现,提供了一套完整的解决方案。本文将以"问题-方案-实践"三段式架构,带你从零掌握这个强大的TypeScript AI开发框架,构建专业级LLM上下文服务。

一、核心问题:LLM上下文服务开发的痛点与挑战

在构建LLM应用时,你是否遇到过这些问题:如何标准化工具调用接口?怎样高效管理会话状态?如何实现客户端与服务器的双向通信?这些挑战正是MCP协议旨在解决的核心问题。

📌 MCP核心价值:将上下文提供与LLM交互解耦,通过标准化协议实现工具、资源和提示的统一管理,让你专注于业务逻辑而非通信细节。

想象一下,MCP就像餐厅的服务系统:LLM是顾客,MCP服务器是餐厅,工具是厨师,资源是食材库,传输方式则是服务员——各司其职又协同工作,共同为顾客提供优质体验。

二、解决方案:MCP SDK核心组件解析

如何设计MCP服务器架构?

MCP服务器是整个系统的核心,负责管理工具、资源和会话。让我们通过一个文件处理工具的案例,了解服务器的基本架构:

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
import { z } from 'zod';
import fs from 'fs/promises';
import path from 'path';

// 创建服务器实例,就像开一家餐厅需要先注册营业执照
const server = new McpServer({
  name: 'file-processing-server',
  version: '1.0.0',
  description: '提供文件读写和处理功能的MCP服务器'
});

// 注册文件读取工具 - 就像聘请一位专门负责取食材的厨师
server.registerTool(
  'read-file', // 工具唯一标识
  {
    title: '文件读取工具',
    description: '读取指定路径的文件内容',
    inputSchema: z.object({ 
      filePath: z.string().describe('要读取的文件路径') 
    }),
    outputSchema: z.object({ 
      content: z.string().describe('文件内容'),
      size: z.number().describe('文件大小(字节)')
    })
  },
  async ({ filePath }) => {
    try {
      // 实际执行文件读取操作
      const fullPath = path.resolve(filePath);
      const content = await fs.readFile(fullPath, 'utf8');
      const stats = await fs.stat(fullPath);
      
      return {
        content: [{ type: 'text', text: `文件内容: ${content.substring(0, 100)}...` }],
        structuredContent: { content, size: stats.size }
      };
    } catch (error) {
      throw new Error(`读取文件失败: ${error.message}`);
    }
  }
);

// 注册用户资料资源 - 就像建立一个顾客信息数据库
server.registerResource(
  'user-profile',
  new ResourceTemplate('users://{userId}/profile', { list: undefined }),
  {
    title: '用户个人资料',
    description: '获取指定用户的基本信息'
  },
  async (uri, { userId }) => {
    // 在实际应用中,这里会从数据库获取真实用户数据
    const mockUserData = {
      userId,
      name: '测试用户',
      email: 'user@example.com',
      joinDate: '2023-01-15'
    };
    
    return {
      contents: [
        {
          uri: uri.href,
          text: JSON.stringify(mockUserData, null, 2)
        }
      ]
    };
  }
);

从零实现Streamable HTTP传输层

Streamable HTTP是MCP推荐的远程通信方式,支持双向数据流。以下是实现无会话管理模式的完整代码:

// 创建Express应用
const app = express();
app.use(express.json());

// 定义MCP端点 - 就像餐厅的点餐窗口
app.post('/mcp', async (req, res) => {
  // 创建传输层实例
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // 禁用会话管理
    enableJsonResponse: true       // 支持JSON响应
  });
  
  // 当客户端断开连接时清理资源
  res.on('close', () => {
    transport.close();
  });
  
  // 连接服务器和传输层
  await server.connect(transport);
  
  // 处理请求
  try {
    await transport.handleRequest(req, res, req.body);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 启动服务器
const port = parseInt(process.env.PORT || '3000');
app.listen(port, () => {
  console.log(`MCP服务器运行在 http://localhost:${port}/mcp`);
  console.log('支持的工具: read-file');
  console.log('支持的资源: users://{userId}/profile');
});

三、实践指南:构建完整MCP应用

▶️ 环境准备与项目初始化

首先,确保你的开发环境满足要求:

# 检查Node.js版本 (需要v14+)
node -v

# 克隆项目仓库
git clone https://gitcode.com/GitHub_Trending/ty/typescript-sdk
cd typescript-sdk

# 安装依赖
npm install

# 安装示例所需依赖
npm install express zod

▶️ 实现文件处理服务器

创建examples/server/fileProcessingServer.ts文件,复制上述服务器代码。然后添加文件写入工具:

// 添加文件写入工具
server.registerTool(
  'write-file',
  {
    title: '文件写入工具',
    description: '将内容写入指定路径的文件',
    inputSchema: z.object({ 
      filePath: z.string().describe('要写入的文件路径'),
      content: z.string().describe('要写入的内容'),
      overwrite: z.boolean().optional().default(false).describe('是否覆盖现有文件')
    }),
    outputSchema: z.object({ 
      success: z.boolean().describe('操作是否成功'),
      message: z.string().describe('操作结果消息')
    })
  },
  async ({ filePath, content, overwrite }) => {
    try {
      const fullPath = path.resolve(filePath);
      
      // 检查文件是否存在
      try {
        await fs.access(fullPath);
        if (!overwrite) {
          return {
            content: [{ type: 'text', text: `文件已存在,未覆盖` }],
            structuredContent: { success: false, message: '文件已存在,未覆盖' }
          };
        }
      } catch {
        // 文件不存在,直接写入
      }
      
      await fs.writeFile(fullPath, content, 'utf8');
      return {
        content: [{ type: 'text', text: `文件写入成功: ${fullPath}` }],
        structuredContent: { success: true, message: `文件写入成功: ${fullPath}` }
      };
    } catch (error) {
      throw new Error(`写入文件失败: ${error.message}`);
    }
  }
);

▶️ 创建MCP客户端

创建examples/client/fileClient.ts文件,实现客户端代码:

import { StreamableHttpClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { McpClient } from '@modelcontextprotocol/sdk/client/index.js';

async function main() {
  // 创建传输层 - 就像顾客打电话给餐厅
  const transport = new StreamableHttpClientTransport({
    url: 'http://localhost:3000/mcp'
  });
  
  // 创建客户端实例
  const client = new McpClient(transport);
  
  try {
    // 连接服务器
    console.log('连接到MCP服务器...');
    await client.connect();
    console.log('成功连接到服务器');
    
    // 调用写文件工具
    console.log('\n=== 调用写文件工具 ===');
    const writeResult = await client.callTool('write-file', {
      filePath: './test.txt',
      content: '这是通过MCP客户端写入的文件内容',
      overwrite: true
    });
    console.log('写文件结果:', writeResult.structuredContent);
    
    // 调用读文件工具
    console.log('\n=== 调用读文件工具 ===');
    const readResult = await client.callTool('read-file', {
      filePath: './test.txt'
    });
    console.log('文件内容:', readResult.structuredContent.content);
    
    // 获取用户资源
    console.log('\n=== 获取用户资源 ===');
    const userResource = await client.getResource('users://123/profile');
    console.log('用户资料:', userResource.contents[0].text);
    
  } catch (error) {
    console.error('操作失败:', error.message);
  } finally {
    // 断开连接
    await client.disconnect();
    console.log('\n已断开与服务器的连接');
  }
}

main();

▶️ 运行与测试

分别打开两个终端窗口,执行以下命令:

# 终端1: 启动服务器
npx tsx examples/server/fileProcessingServer.ts

# 终端2: 运行客户端
npx tsx examples/client/fileClient.ts

四、常见错误排查

1. 传输层连接失败

症状:客户端无法连接到服务器,报"连接超时"或"拒绝连接"错误。

排查步骤

  • 确认服务器是否已启动并监听正确端口
  • 检查防火墙设置是否阻止端口访问
  • 验证客户端使用的URL是否正确

解决方案

// 增加连接超时和错误处理
const transport = new StreamableHttpClientTransport({
  url: 'http://localhost:3000/mcp',
  timeout: 5000 // 设置5秒超时
});

// 增加错误处理
try {
  await client.connect();
} catch (error) {
  console.error('连接失败:', error);
  // 提供用户友好的错误提示
  if (error.code === 'ECONNREFUSED') {
    console.error('请确保服务器已启动并在指定端口运行');
  }
}

2. 工具调用参数验证失败

症状:调用工具时收到"输入验证失败"错误。

排查步骤

  • 检查工具定义的inputSchema
  • 验证客户端传递的参数是否符合schema要求
  • 查看错误消息中的具体验证失败原因

解决方案

// 调用工具时增加参数验证
try {
  const result = await client.callTool('read-file', {
    filePath: './test.txt'
  });
} catch (error) {
  if (error.name === 'ValidationError') {
    console.error('参数验证失败:', error.details);
  }
}

五、生产环境最佳实践

1. 会话状态管理

在生产环境中,建议使用持久化存储来管理会话状态:

// 使用数据库存储会话状态
import { DatabaseEventStore } from '@modelcontextprotocol/sdk/server/stores/database.js';

// 创建带会话管理的传输层
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
  eventStore: new DatabaseEventStore({
    connectionString: process.env.DATABASE_URL
  })
});

2. 安全加固

  • 输入验证:对所有输入进行严格验证
  • 权限控制:为工具和资源添加访问控制
  • 传输加密:使用HTTPS加密传输数据
  • 速率限制:防止DoS攻击
// 添加请求速率限制
import rateLimit from 'express-rate-limit';

const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15分钟
  max: 100, // 每个IP限制100请求
  standardHeaders: true,
  legacyHeaders: false,
});

app.use('/mcp', apiLimiter);

3. 监控与日志

集成监控和日志系统,及时发现和解决问题:

// 添加请求日志
app.use((req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
  next();
});

// 服务器错误监控
server.on('error', (error) => {
  console.error('服务器错误:', error);
  // 可以集成错误报告服务,如Sentry
});

总结

通过本文,你已经学会了如何使用MCP TypeScript SDK构建完整的LLM上下文服务,包括服务器设计、工具和资源开发、客户端实现以及生产环境部署。MCP协议为LLM应用开发提供了标准化框架,使你能够专注于业务逻辑而非通信细节。

下一步,你可以探索更高级的功能:动态服务器配置、多节点部署、高级授权机制等。MCP SDK的灵活性和扩展性将支持你构建更复杂的AI应用系统。

官方文档:docs/capabilities.md 示例代码:examples/ 核心实现:packages/server/src/server/mcp.ts

登录后查看全文
热门项目推荐
相关项目推荐