MCP通信协议实战:从零搭建响应式智能应用

366 阅读5分钟

一、MCP协议:爆火的智能应用开发新范式

Model Context Protocol (MCP) 近期在AI开发领域火爆出圈,成为继Function Call之后的新一代工具调用标准。"如何看待MCP?大模型工具调用的解耦!"已成为热门话题。那么,什么是MCP?它为何能够在短时间内吸引如此多的关注?

1.1 MCP是什么?

image.png

MCP (Model Context Protocol) 是一种专为AI服务与客户端通信设计的协议,它允许服务端和客户端之间进行双向、实时的数据交换。与传统的RESTful API不同,MCP通过持久连接支持流式数据传输,特别适合AI模型生成、实时数据分析等场景。

"在MCP爆火之前,Function Call 函数调用模式也被众多开发者广泛使用",而MCP的出现则为大模型工具调用提供了更为灵活、标准化的解决方案。

1.2 MCP的爆火原因

MCP协议迅速走红有几个关键原因:

  1. 标准化工具调用:提供了统一的接口规范,简化了智能应用开发
  2. 工具使用平权:降低了开发门槛,使更多开发者能够参与AI应用开发
  3. 灵活的通信方式:支持SSE和stdio多种传输方式,适应不同应用场景
  4. 大厂背书:多家大厂相继推出MCP服务,推动了生态发展

二、MCP生态现状:大厂争相布局

2.1 阿里云MCP服务

阿里云上线全生命周期MCP服务:人人都可定制自己的Agent - B2B报道:"阿里云百炼上线的MCP服务可快速让大模型转化成真实场景的生产力工具。平台集成了阿里云函数计算、200多款业界领先的大模型、50多款主流MCP服务。"这表明阿里云已经建立起完整的MCP服务生态。

2.2 百度MCP布局

「电商」最新资讯列表-极客网报道:"百度发布全球首个电商交易MCP、搜索MCP,帮助开发者全面拥抱MCP"。百度在特定领域的MCP应用也在快速推进。

三、MCP架构设计:实战解析

要构建基于MCP的应用,我们需要理解其架构设计。以下是一个典型的MCP应用架构:

3.1 核心组件

  1. SSE服务器:处理客户端连接,维护长连接,实现实时通信
  2. MCP服务层:实现业务逻辑和命令处理
  3. 数据服务:提供后端数据管理功能

3.2 SSE服务器实现

Server-Sent Events (SSE) 是一种允许服务器向客户端推送实时更新的技术,非常适合MCP协议的实现:

// 初始化应用
const app = express();
const connections = new Map();

// SSE 连接建立端点
app.get("/sse", async (req, res) => {
  // 设置响应头,防止缓存
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Connection', 'keep-alive');
  res.flushHeaders();
  
  // 实例化SSE传输对象
  const transport = new SSEServerTransport("/messages", res);
  const sessionId = transport.sessionId;
  logger.info(`新的SSE连接建立`, { sessionId });

  // 注册连接
  connections.set(sessionId, transport);
  
  // 连接中断处理
  const cleanup = () => {
    logger.info(`SSE连接关闭`, { sessionId });
    connections.delete(sessionId);
    clearInterval(heartbeatInterval);
  };
  
  req.on('close', cleanup);
  req.on('error', (err) => {
    logger.error(`SSE连接错误`, { sessionId, error: err });
    cleanup();
  });
  
  try {
    // 将传输对象与MCP服务器连接
    await mcpServer.connect(transport);
    
    // 发送心跳包以保持连接
    const heartbeatInterval = setInterval(() => {
      try {
        res.write(`event: heartbeat\ndata: ${Date.now()}\n\n`);
      } catch (error) {
        cleanup();
      }
    }, CONFIG.heartbeatInterval);
  } catch (error) {
    res.status(500).write(`event: error\ndata: {"message": "服务器连接失败"}\n\n`);
    cleanup();
  }
});

3.3 实现双向通信

尽管SSE本身是服务器到客户端的单向通信,但我们可以通过额外的POST端点实现完整的双向通信:

/**
 * 接收客户端消息的端点
 */
app.post("/messages", async (req, res) => {
  const sessionId = req.query.sessionId;
  
  if (!sessionId) {
    return res.status(400).json({ error: '缺少sessionId参数' });
  }
  
  try {
    const transport = connections.get(sessionId);
    
    if (!transport) {
      return res.status(404).json({ error: '会话不存在或已过期', sessionId });
    }
    
    await transport.handlePostMessage(req, res);
  } catch (error) {
    res.status(500).json({ error: '处理消息失败', message: error.message });
  }
});

四、MCP工具定义:解耦与标准化

MCP的核心优势在于其对工具调用的标准化处理。下面是如何定义MCP工具:

export const server = new McpServer({
  name: "mcp-application",
  version: "1.0.0",
  description: "MCP应用示例"
});

// 定义工具示例
server.tool(
  "toolName", 
  "工具描述", 
  {
    // 使用zod库进行参数验证
    param1: z.string().describe("参数1描述"),
    param2: z.number().describe("参数2描述")
  }, 
  async ({ param1, param2 }) => {
    // 工具实现逻辑
    const result = await someService(param1, param2);
    return { 
      content: [
        { type: "text", text: JSON.stringify(result) }
      ] 
    };
  }
);

这种定义方式使得工具调用变得清晰、可维护,同时提供了强大的参数验证功能。

五、MCP在Cursor中的应用

5.1 在Cursor中配置MCP服务器

  1. 打开Cursor编辑器

  2. 进入Cursor设置 > 功能 > MCP

  3. 点击"添加新的全局MCP服务器"

  4. 填写配置信息:

    • 名称:给你的MCP服务器起一个易识别的名称
    • 类型:选择"sse"
    • URL:填写你的MCP服务器的SSE端点URL,例如http://localhost:8080/sse
{
  "servers": {
    "your-application": {
      "name": "应用名称",
      "type": "sse",
      "url": "http://localhost:8080/sse",
      "env": {}
    }
  }
}

5.2 使用MCP工具

成功连接后,可以在Cursor的Chat窗口中通过自然语言使用MCP工具,Cursor将通过MCP协议调用对应的工具函数。

六、高级功能与最佳实践

6.1 健康检查和系统稳定性

一个健壮的MCP应用必须有完善的健康检查机制:

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

6.2 优雅退出机制

在生产环境中,服务可能需要重启或升级,我们需要确保所有连接能够优雅关闭:

/**
 * 优雅关闭
 */
function setupGracefulShutdown() {
  const shutdown = async (signal) => {
    logger.info(`接收到${signal}信号,准备关闭`);
    await closeAllConnections();
    
    server.close(() => {
      logger.info(`服务器已关闭`);
      process.exit(0);
    });
    
    // 强制退出超时
    setTimeout(() => {
      logger.error(`强制关闭服务器(超时)`);
      process.exit(1);
    }, 10000);
  };

  process.on('SIGTERM', () => shutdown('SIGTERM'));
  process.on('SIGINT', () => shutdown('SIGINT'));
}

6.3 参数验证与错误处理

使用zod库进行严格的参数验证是一种最佳实践:

// 记录新数据工具
server.tool(
  "recordData",
  "记录数据",
  {
    items: z
      .array(
        z.object({
          id: z.number().describe("ID"),
          value: z.number().describe("值")
        })
      )
      .describe("要记录的数据列表"),
    category: z.string().describe("分类")
  },
  async ({ items, category }) => {
    try {
      const result = await recordNewData(category, items);
      return { 
        content: [
          { 
            type: "text", 
            text: JSON.stringify(result) 
          }
        ] 
      };
    } catch (error) {
      return { 
        content: [
          { 
            type: "text", 
            text: JSON.stringify({ error: error.message }) 
          }
        ] 
      };
    }
  }
);

七、MCP实践案例:学生成绩管理系统

我们可以通过一个实际案例来展示MCP的应用,以学生成绩管理系统为例:

7.1 MCP工具设计

// 获取全部学生信息
server.tool(
  "getAllStudents", 
  "获取所有学生信息", 
  {}, 
  async () => {
    const students = await getAllStudents();
    return { 
      content: [{ type: "text", text: JSON.stringify(students) }] 
    };
  }
);

// 获取成绩信息
server.tool(
  "getGrades", 
  "获取所有学生的最新成绩信息", 
  {}, 
  async () => {
    const grades = await getGrades();
    return { 
      content: [{ type: "text", text: JSON.stringify(grades) }] 
    };
  }
);

// 获取考试历史
server.tool(
  "getExamHistory", 
  "获取所有考试历史记录", 
  {}, 
  async () => {
    const examHistory = await getExamHistory();
    return { 
      content: [{ type: "text", text: JSON.stringify(examHistory) }] 
    };
  }
);

// 记录新成绩
server.tool(
  "recordGrade",
  "记录学生成绩",
  {
    grades: z
      .array(
        z.object({
          studentId: z.number().describe("学生ID"),
          score: z.number().describe("考试分数")
        })
      )
      .describe("要记录的学生成绩列表"),
    examName: z.string().describe("考试名称")
  },
  async ({ grades, examName }) => {
    try {
      const result = await recordNewGrade(examName, grades);
      return { 
        content: [{ type: "text", text: JSON.stringify(result) }] 
      };
    } catch (error) {
      return { 
        content: [{ type: "text", text: JSON.stringify({ error: error.message }) }] 
      };
    }
  }
);

八、MCP的未来发展与机遇

8.1 MCP与Function Call的关系

MCP并非要完全取代Function Call,而是提供了一种更为标准化、灵活的解决方案。MCP的出现将大模型工具调用带入了一个新的发展阶段。

8.2 多模型协作的新范式

"Claude 提出方便LLM 理解、使用第三方工具的通用协议MCP 后,LLM 能调用的工具变多,把LLM 当作Agent 大脑的趋势增强。"

这表明MCP正在成为构建高级Agent系统的重要基础设施,使得不同模型之间的协作变得更加容易。

总结与展望

MCP作为一种新兴的AI通信协议,正在改变大模型与工具集成的方式。它的标准化、灵活性和低门槛特性,使得更多开发者能够参与到AI应用的开发中来。

从本文的实战案例可以看出,使用Express和SSE技术实现MCP通信协议并不复杂,但能够构建出强大的实时通信系统。随着像Cursor这样的工具对MCP的支持,以及阿里云、百度等大厂的积极布局,MCP生态正在迅速成熟。

未来,MCP有望成为连接大模型与各种工具的标准接口,推动AI应用从实验室走向实际生产环境,创造更多商业价值。无论你是开发者还是创业者,现在都是了解和掌握MCP技术的最佳时机。