首页
/ 从零构建LLM上下文服务:MCP TypeScript SDK实战指南

从零构建LLM上下文服务:MCP TypeScript SDK实战指南

2026-05-02 11:10:13作者:卓炯娓

在LLM开发过程中,你是否曾遇到以下挑战:如何标准化管理模型上下文数据?如何构建灵活的工具调用系统?如何实现跨平台的服务器客户端通信?MCP TypeScript SDK(模型上下文协议的官方TypeScript实现)为这些问题提供了完整解决方案。本文将通过"问题-方案-实践"三段式结构,帮助你掌握使用TypeScript开发LLM上下文服务的核心技能,从基础架构到实战进阶,全面提升你的模型上下文管理能力。

一、LLM上下文管理的核心痛点与MCP解决方案

在构建基于大语言模型的应用时,开发者常面临三个核心挑战:

痛点一:上下文数据管理混乱
不同LLM接口对上下文的处理方式各异,导致数据格式不统一,难以维护和迁移。

痛点二:工具集成复杂
为LLM添加工具能力时,需重复开发认证、参数验证和结果处理逻辑,代码复用率低。

痛点三:通信协议不兼容
客户端与服务器之间的通信方式多样,从HTTP到WebSocket,缺乏标准化的交互模式。

MCP协议(Model Context Protocol - 模型上下文协议)通过以下创新解决这些问题:

  • 标准化的上下文数据格式
  • 统一的工具、资源和提示注册机制
  • 多传输方式支持(Streamable HTTP、Stdio等)

二、基础架构篇:MCP核心组件与实现

如何实现MCP服务器的基础架构

MCP服务器是整个上下文服务的核心,负责管理工具、资源和提示,处理客户端请求。

概念解析
McpServer类是MCP协议的核心实现,提供了工具、资源和提示的注册机制,以及请求处理逻辑。

场景案例
构建一个天气查询服务器,提供实时天气查询工具和地理位置资源。

代码实现:[examples/server/simpleServer.ts]

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

// 创建MCP服务器实例
const server = new McpServer({
  name: 'weather-server',
  version: '1.0.0',
  description: '提供天气查询服务的MCP服务器'
});

// 注册天气查询工具
server.registerTool(
  'get-weather',
  {
    title: '天气查询工具',
    description: '根据经纬度获取实时天气信息',
    inputSchema: z.object({
      latitude: z.number().min(-90).max(90),
      longitude: z.number().min(-180).max(180)
    }),
    outputSchema: z.object({
      temperature: z.number(),
      condition: z.string(),
      humidity: z.number().min(0).max(100)
    })
  },
  async ({ latitude, longitude }) => {
    // 实际应用中这里会调用天气API
    const mockWeatherData = {
      temperature: 22.5,
      condition: '晴朗',
      humidity: 65
    };
    
    return {
      content: [{ 
        type: 'text', 
        text: `当前天气:${mockWeatherData.condition},温度:${mockWeatherData.temperature}°C` 
      }],
      structuredContent: mockWeatherData
    };
  }
);

// 设置Express服务器
const app = express();
app.use(express.json());

// 配置Streamable HTTP传输
app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // 禁用会话管理,适合无状态服务
    enableJsonResponse: true
  });

  // 客户端断开连接时清理资源
  res.on('close', () => transport.close());
  
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

// 启动服务器
const port = 3000;
app.listen(port, () => {
  console.log(`MCP天气服务器运行在 http://localhost:${port}/mcp`);
});

适用场景
快速搭建需要对外提供API服务的LLM上下文服务器,如企业内部AI助手、客服机器人后端等。

MCP工具、资源与提示的核心原理

MCP提供三种核心功能组件,它们在LLM应用中扮演不同角色:

组件类型 核心作用 设计理念 数据流向 典型应用场景
工具(Tools) 执行操作或计算 模型控制,AI决定调用时机和参数 客户端→服务器→外部服务→客户端 天气查询、数据计算、API调用
资源(Resources) 提供上下文数据 应用驱动,由应用决定暴露内容 服务器→客户端 用户资料、配置信息、文档内容
提示(Prompts) 提供交互模板 用户驱动,由用户选择使用方式 服务器→客户端→LLM 代码审查、邮件生成、翻译助手

工具实现:股票价格查询

代码实现:[examples/server/tools/stockTool.ts]

// 注册股票价格查询工具
server.registerTool(
  'get-stock-price',
  {
    title: '股票价格查询',
    description: '获取指定股票代码的当前价格',
    inputSchema: z.object({
      symbol: z.string().regex(/^[A-Za-z0-9]{1,10}$/, '无效股票代码')
    }),
    outputSchema: z.object({
      symbol: z.string(),
      price: z.number(),
      timestamp: z.string()
    })
  },
  async ({ symbol }) => {
    // 实际应用中这里会调用股票API
    const mockPrice = 156.75 + Math.random() * 10;
    
    return {
      content: [{ 
        type: 'text', 
        text: `股票 ${symbol.toUpperCase()} 当前价格: $${mockPrice.toFixed(2)}` 
      }],
      structuredContent: {
        symbol: symbol.toUpperCase(),
        price: mockPrice,
        timestamp: new Date().toISOString()
      }
    };
  }
);

资源实现:用户配置信息

代码实现:[examples/server/resources/userConfigResource.ts]

import { ResourceTemplate } from '@modelcontextprotocol/sdk/core/types.js';

// 注册用户配置资源
server.registerResource(
  'user-config',
  new ResourceTemplate('config://users/{userId}', { list: undefined }),
  {
    title: '用户配置信息',
    description: '获取指定用户的应用配置'
  },
  async (uri, { userId }) => {
    // 实际应用中这里会从数据库获取
    const mockConfig = {
      theme: 'dark',
      notifications: true,
      timezone: 'Asia/Shanghai',
      displayDensity: 'comfortable'
    };
    
    return {
      contents: [{
        uri: uri.href,
        text: JSON.stringify(mockConfig, null, 2),
        mimeType: 'application/json'
      }]
    };
  }
);

提示实现:邮件生成助手

代码实现:[examples/server/prompts/emailPrompt.ts]

// 注册邮件生成提示
server.registerPrompt(
  'generate-email',
  {
    title: '邮件生成助手',
    description: '根据主题和收件人生成专业邮件',
    argsSchema: z.object({
      recipient: z.string().email(),
      subject: z.string(),
      purpose: z.enum(['introduction', 'follow-up', 'complaint', 'thank-you']),
      details: z.string().optional()
    })
  },
  ({ recipient, subject, purpose, details }) => {
    const purposeDescriptions = {
      introduction: '介绍自己或公司业务',
      'follow-up': '跟进之前的沟通或会议',
      complaint: '表达不满或投诉问题',
      'thank-you': '表达感谢'
    };
    
    return {
      messages: [
        {
          role: 'system',
          content: {
            type: 'text',
            text: `你是一位专业邮件撰写助手。请根据以下信息生成一封${purposeDescriptions[purpose]}的邮件。`
          }
        },
        {
          role: 'user',
          content: {
            type: 'text',
            text: `收件人: ${recipient}\n主题: ${subject}\n详细信息: ${details || '无'}`
          }
        }
      ]
    };
  }
);

💡 提示技巧:在设计工具和资源时,尽量使用详细的描述和明确的输入输出模式,这将帮助LLM更好地理解如何使用它们。

三、实战进阶篇:传输方式与部署策略

如何选择适合的MCP传输方式

MCP支持多种传输方式,每种方式都有其适用场景:

1. Streamable HTTP传输

概念解析
Streamable HTTP是一种支持双向通信的HTTP传输方式,允许在单个HTTP连接上发送多个消息,适合远程服务器通信。

场景案例
构建一个需要处理大量并发请求的公共API服务。

代码实现:[examples/server/streamableHttpServer.ts]

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
import { createServer } from 'http';
import { randomUUID } from 'crypto';

const app = express();
app.use(express.json());

// 创建带有会话管理的Streamable HTTP传输
app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(), // 为每个请求生成唯一会话ID
    enableJsonResponse: true
  });

  // 处理连接关闭
  res.on('close', () => {
    console.log(`会话 ${transport.sessionId} 已关闭`);
    transport.close();
  });

  // 创建并配置服务器
  const server = new McpServer({
    name: 'streamable-server',
    version: '1.0.0'
  });
  
  // 注册基础工具...
  
  await server.connect(transport);
  console.log(`新会话已建立: ${transport.sessionId}`);
  
  try {
    await transport.handleRequest(req, res, req.body);
  } catch (error) {
    console.error(`处理请求时出错: ${error}`);
    res.status(500).json({ error: '服务器内部错误' });
  }
});

const httpServer = createServer(app);
const port = 3000;

httpServer.listen(port, () => {
  console.log(`Streamable HTTP服务器运行在 http://localhost:${port}/mcp`);
});

适用场景:生产环境中的API服务,需要处理多个客户端的并发请求。

2. Stdio传输

概念解析
Stdio传输通过标准输入输出流进行进程间通信,适合本地应用集成。

场景案例
作为独立进程运行的LLM助手,与主应用通过标准流通信。

代码实现:[examples/server/stdioServer.ts]

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

async function runServer() {
  const transport = new StdioServerTransport({
    // 配置输入输出流,默认为process.stdin和process.stdout
    input: process.stdin,
    output: process.stdout
  });

  const server = new McpServer({
    name: 'stdio-server',
    version: '1.0.0',
    description: '通过Stdio通信的MCP服务器'
  });

  // 注册工具和资源...
  
  console.log('Stdio MCP服务器已启动,等待连接...');
  
  // 处理连接关闭
  transport.on('close', () => {
    console.log('连接已关闭');
    process.exit(0);
  });

  await server.connect(transport);
  console.log('服务器已准备就绪');
}

runServer().catch(error => {
  console.error('服务器启动失败:', error);
  process.exit(1);
});

适用场景:桌面应用中的本地LLM集成,或需要与其他进程通信的场景。

⚠️ 注意事项:Stdio传输不适合网络通信,仅用于本地进程间通信。在生产环境中,建议使用Streamable HTTP传输。

MCP服务器的部署策略与性能优化

单节点部署

概念解析
单节点部署是最简单的部署方式,所有组件运行在单个服务器实例上。

代码实现:[examples/deployment/singleNode.ts]

// 这是一个完整的单节点部署示例,包含服务器配置和启动脚本
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
import { createServer } from 'http';
import { config } from 'dotenv';

// 加载环境变量
config();

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

// 健康检查端点
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
});

// MCP端点
app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // 无状态模式
    enableJsonResponse: true
  });

  res.on('close', () => transport.close());
  
  const server = new McpServer({
    name: 'production-server',
    version: process.env.VERSION || '1.0.0'
  });
  
  // 注册工具、资源和提示...
  
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
});

// 创建HTTP服务器并启动
const port = process.env.PORT || 3000;
const httpServer = createServer(app);

httpServer.listen(port, () => {
  console.log(`MCP服务器运行在 http://localhost:${port}`);
  console.log(`环境: ${process.env.NODE_ENV || 'development'}`);
});

// 优雅关闭
process.on('SIGTERM', () => {
  console.log('收到关闭信号,正在优雅关闭服务器...');
  httpServer.close(() => {
    console.log('服务器已关闭');
    process.exit(0);
  });
});

适用场景:开发环境、小型应用或流量适中的服务。

多节点部署

概念解析
多节点部署通过负载均衡将请求分发到多个服务器实例,提高系统的可用性和扩展性。

场景案例
构建支持高并发的MCP服务,确保服务稳定性和可扩展性。

架构说明

客户端 → 负载均衡器 → MCP服务器集群 → 共享数据库/缓存

性能优化建议

  1. 使用连接池:对数据库和外部API调用使用连接池,减少连接建立开销
  2. 实现请求缓存:对频繁访问的资源和工具响应进行缓存
  3. 启用压缩:对传输的数据进行gzip压缩,减少网络传输量
  4. 限流保护:实现请求限流,防止服务过载
  5. 异步处理:对耗时操作采用异步处理,避免阻塞主线程

四、MCP客户端实现与应用集成

如何构建MCP客户端应用

概念解析
MCP客户端负责与MCP服务器通信,发送请求并处理响应,是连接LLM与MCP服务器的桥梁。

场景案例
创建一个天气查询客户端,连接到前面实现的MCP服务器。

代码实现:[examples/client/weatherClient.ts]

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

async function main() {
  // 创建HTTP传输
  const transport = new StreamableHttpClientTransport({
    url: 'http://localhost:3000/mcp',
    timeout: 30000 // 30秒超时
  });

  // 创建MCP客户端
  const client = new McpClient(transport);
  
  try {
    // 连接到服务器
    console.log('连接到MCP服务器...');
    await client.connect();
    console.log('连接成功');
    
    // 获取服务器元数据
    const serverInfo = await client.getServerInfo();
    console.log(`服务器信息: ${serverInfo.name} v${serverInfo.version}`);
    
    // 调用天气查询工具
    console.log('\n调用天气查询工具...');
    const weatherResult = await client.callTool('get-weather', {
      latitude: 39.9042,
      longitude: 116.4074
    });
    
    console.log('天气查询结果:');
    console.log(weatherResult.content[0].text);
    console.log('结构化数据:', weatherResult.structuredContent);
    
    // 获取用户配置资源
    console.log('\n获取用户配置资源...');
    const configResource = await client.getResource('config://users/123');
    console.log('用户配置:');
    console.log(configResource.contents[0].text);
    
    // 使用邮件生成提示
    console.log('\n生成邮件提示...');
    const emailPrompt = await client.getPrompt('generate-email', {
      recipient: 'contact@example.com',
      subject: 'MCP服务使用咨询',
      purpose: 'introduction',
      details: '我想了解如何将MCP集成到我们的AI助手产品中'
    });
    
    console.log('邮件提示:');
    emailPrompt.messages.forEach((msg, index) => {
      console.log(`[${index}] ${msg.role}: ${msg.content.text}`);
    });
    
  } catch (error) {
    console.error('操作出错:', error);
  } finally {
    // 断开连接
    await client.disconnect();
    console.log('\n已断开与服务器的连接');
  }
}

main();

适用场景:任何需要与MCP服务器交互的应用,如AI助手、自动化工具、开发环境插件等。

五、测试调试与常见错误排查

MCP应用的测试策略

概念解析
测试是确保MCP服务质量的关键环节,包括单元测试、集成测试和端到端测试。

代码实现:[test/integration/mcpServer.test.ts]

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { McpClient } from '@modelcontextprotocol/sdk/client/client.js';
import { StreamableHttpClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import express from 'express';
import { createServer } from 'http';

describe('MCP服务器集成测试', () => {
  let server: McpServer;
  let httpServer: any;
  let port: number;
  
  beforeAll(async () => {
    // 创建测试服务器
    const app = express();
    app.use(express.json());
    
    app.post('/mcp', async (req, res) => {
      const transport = new StreamableHTTPServerTransport({
        sessionIdGenerator: undefined,
        enableJsonResponse: true
      });
      
      res.on('close', () => transport.close());
      
      await server.connect(transport);
      await transport.handleRequest(req, res, req.body);
    });
    
    // 随机端口
    port = 30000 + Math.floor(Math.random() * 1000);
    httpServer = createServer(app).listen(port);
    
    // 创建MCP服务器并注册测试工具
    server = new McpServer({
      name: 'test-server',
      version: '1.0.0'
    });
    
    server.registerTool(
      'test-add',
      {
        title: '测试加法工具',
        description: '用于测试的简单加法工具',
        inputSchema: { a: { type: 'number' }, b: { type: 'number' } },
        outputSchema: { result: { type: 'number' } }
      },
      async ({ a, b }) => ({
        content: [{ type: 'text', text: `结果: ${a + b}` }],
        structuredContent: { result: a + b }
      })
    );
  });
  
  afterAll(async () => {
    httpServer.close();
  });
  
  it('应该成功连接到服务器并调用工具', async () => {
    const transport = new StreamableHttpClientTransport({
      url: `http://localhost:${port}/mcp`
    });
    
    const client = new McpClient(transport);
    await client.connect();
    
    const result = await client.callTool('test-add', { a: 2, b: 3 });
    
    expect(result.structuredContent.result).toBe(5);
    expect(result.content[0].text).toContain('结果: 5');
    
    await client.disconnect();
  });
  
  it('应该处理不存在的工具调用', async () => {
    const transport = new StreamableHttpClientTransport({
      url: `http://localhost:${port}/mcp`
    });
    
    const client = new McpClient(transport);
    await client.connect();
    
    await expect(
      client.callTool('non-existent-tool', {})
    ).rejects.toThrow(/工具不存在/);
    
    await client.disconnect();
  });
});

常见错误排查

1. 连接超时

问题:客户端无法连接到服务器,出现超时错误。

排查步骤

  • 检查服务器是否正在运行
  • 验证网络连接和防火墙设置
  • 确认服务器地址和端口是否正确
  • 检查服务器日志是否有错误信息

解决方案

// 增加超时时间并添加重试逻辑
const transport = new StreamableHttpClientTransport({
  url: 'http://localhost:3000/mcp',
  timeout: 30000 // 增加超时时间到30秒
});

// 实现简单的重试机制
async function withRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T> {
  try {
    return await fn();
  } catch (error) {
    if (retries > 0) {
      console.log(`重试中... (剩余: ${retries})`);
      await new Promise(resolve => setTimeout(resolve, 1000));
      return withRetry(fn, retries - 1);
    }
    throw error;
  }
}

// 使用重试机制连接服务器
await withRetry(() => client.connect());

2. 工具调用参数错误

问题:调用工具时出现参数验证错误。

排查步骤

  • 检查工具定义的输入模式
  • 验证客户端提供的参数类型和格式
  • 查看服务器返回的详细错误信息

解决方案

// 客户端参数验证
const AddInputSchema = z.object({
  a: z.number(),
  b: z.number()
});

try {
  // 调用前验证参数
  const validatedInput = AddInputSchema.parse(inputData);
  const result = await client.callTool('add', validatedInput);
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error('参数验证失败:', error.errors);
    // 向用户显示友好的错误提示
  } else {
    console.error('工具调用失败:', error);
  }
}

3. 会话管理问题

问题:状态信息丢失或会话无法维持。

排查步骤

  • 确认服务器是否启用了会话管理
  • 检查会话ID是否正确传递
  • 验证会话存储是否正常工作

解决方案

// 服务器端启用会话管理
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => randomUUID(),
  // 使用持久化存储
  eventStore: new DatabaseEventStore()
});

// 客户端保存会话ID
let sessionId: string | undefined;

transport.on('session', (id) => {
  sessionId = id;
  // 保存会话ID到本地存储
  localStorage.setItem('mcp-session-id', id);
});

// 重连时恢复会话
const savedSessionId = localStorage.getItem('mcp-session-id');
if (savedSessionId) {
  transport.sessionId = savedSessionId;
}

六、进阶学习路径

掌握MCP TypeScript SDK后,你可以通过以下路径继续深入学习:

路径一:高级协议特性

深入了解MCP协议的高级特性,如:

  • 增量更新机制
  • 权限控制与认证
  • 批量操作优化
  • 协议扩展与自定义消息类型

相关资源:

  • 协议规范文档:docs/protocol.md
  • 高级示例:examples/advanced/

路径二:性能优化与扩展

学习如何优化MCP服务性能和扩展性:

  • 分布式会话管理
  • 负载均衡策略
  • 缓存机制实现
  • 水平扩展架构设计

相关资源:

  • 性能测试工具:tools/performance/
  • 扩展指南:docs/scaling.md

路径三:实际应用场景

探索MCP在不同领域的应用:

  • AI助手集成
  • 自动化工作流
  • 多模型协作
  • 实时数据处理

相关资源:

  • 应用案例:examples/applications/
  • 集成指南:docs/integrations.md

总结

MCP TypeScript SDK为LLM上下文管理提供了标准化解决方案,通过本文的学习,你已经掌握了从基础架构到实战进阶的核心技能。无论是构建简单的工具服务还是复杂的分布式系统,MCP都能提供灵活而强大的支持。随着LLM技术的不断发展,MCP协议将继续进化,为开发者提供更完善的上下文管理工具。

开始你的MCP开发之旅吧!通过实践和探索,你将能够构建出更智能、更高效的LLM应用。

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