从零开发 MCP 服务:原理到实战(实现飞书文档 MCP)

在使用 Claude、GPT 等 AI 模型时,你是否遇到过这些问题:

  • AI 无法访问最新数据,知识截止日期限制了应用场景
  • 需要 AI 操作外部系统(如数据库、API),但缺乏连接机制
  • 想让 AI 访问企业内部数据,但担心数据安全问题

MCP (Model Context Protocol) 协议正是为解决这些问题而生,它为 AI 提供了统一的工具调用规范和外部系统连接能力。本文将详细讲解如何构建飞书文档 MCP 服务,从理论到实战,帮助你快速掌握 MCP 开发技能。

通过本文,您将学会:

  • MCP 核心原理,核心组件的封装
  • 使用 nodejs 从 0-1 开发 MCP 服务,同时也可做为 MCP 轻量脚手架,实战开发飞书云文档 MCP 服务
  • 学会在开发工具中接入 MCP 服务

项目代码仓库,可先行下载代码再往下学习,建议收藏 star。

MCP 服务构建:核心原理与实战

什么是 MCP?

MCP (Model Context Protocol) 是由 Anthropic 公司推出的标准化协议,允许 AI 模型通过统一接口与外部工具和服务进行通信。MCP 解决了大型语言模型无法直接访问外部最新数据和系统的限制,是一个"AI 能力扩展协议"。

我第一次接触 MCP 是在使用 Cursor 编辑器时,它能够通过 MCP 连接本地代码库和外部工具,极大提升了开发效率。MCP 的强大之处在于统一了工具调用格式,提供了请求/响应的规范定义,使得 AI 可以像调用函数一样使用外部工具。

MCP 的核心价值在于:

  • 提供统一的工具调用规范
  • 实现 AI 与外部系统的无缝连接
  • 支持实时数据获取与操作

MCP 服务核心组件

MCP 服务主要由这三个核心组件构成:

  1. MCP 服务器:注册工具、处理请求并返回响应的核心
  2. 工具定义与实现:定义工具的名称、描述、参数和执行逻辑
  3. 传输层:与 AI 客户端通信的机制,通常是 HTTP SSE 或命令行标准输入/输出

下面我们将以飞书文档 MCP 服务为例,详细讲解每个组件的实现。

技术选型与项目结构

在本项目中,我们采用以下技术栈实现飞书文档 MCP 服务:

  • Node.js + TypeScript:强类型支持,提高代码质量
  • Express.js:轻量且灵活,完美适配 HTTP SSE 传输需求
  • @modelcontextprotocol/sdk:Anthropic 官方 SDK
  • zod:参数验证库,确保 AI 传入的参数符合预期

项目结构:

bash

体验AI代码助手

代码解读

. ├── src/ │ ├── api/ # 外部服务的API客户端 │ │ └── feishu.ts # 飞书API客户端 │ ├── server.ts # MCP服务器实现 │ ├── index.ts # 应用入口 │ └── mcp-types.d.ts # 类型声明 ├── .env # 环境变量配置 ├── package.json # 项目配置和依赖 └── tsconfig.json # TypeScript配置

这种结构的好处是职责分明:

  • api 目录负责封装与飞书服务的交互
  • server.ts 负责 MCP 核心逻辑和工具注册
  • index.ts 处理服务启动和环境配置
  • mcp-types.d.ts 解决了 TypeScript 与 MCP SDK 的类型兼容问题

环境准备

开始前,先安装必要的依赖:

bash

体验AI代码助手

代码解读

pnpm init -y pnpm install @modelcontextprotocol/sdk express zod axios --save pnpm install typescript tsx @types/node @types/express --save-dev

然后初始化 TypeScript 配置:

bash

体验AI代码助手

代码解读

npx tsc --init

修改 tsconfig.json,主要调整这几项:

json

体验AI代码助手

代码解读

{ "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "NodeNext", "esModuleInterop": true, "outDir": "./dist", "strict": true } }

创建 MCP 类型声明文件。因为官方 SDK 缺少完整的 TypeScript 类型声明,我们需要自己定义。创建 src/mcp-types.d.ts

typescript

体验AI代码助手

代码解读

declare module '@modelcontextprotocol/sdk/server/mcp.js' { import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; export class McpServer { constructor(options: any, capabilities: any); tool(name: string, description: string, params: any, handler: Function): void; connect(transport: Transport): Promise<void>; server: any; } } declare module '@modelcontextprotocol/sdk/server/sse.js' { import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; export class SSEServerTransport implements Transport { constructor(path: string, res: any); onMessage: (callback: (message: any) => void) => void; send: (message: any) => void; handlePostMessage(req: any, res: any): Promise<void>; } } declare module '@modelcontextprotocol/sdk/server/stdio.js' { import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'; export class StdioServerTransport implements Transport { constructor(); onMessage: (callback: (message: any) => void) => void; send: (message: any) => void; } } declare module '@modelcontextprotocol/sdk/shared/transport.js' { export interface Transport { onMessage: (callback: (message: any) => void) => void; send: (message: any) => void; } }

有了这些准备,我们就可以开始构建 MCP 服务的核心部分了!

实现飞书 API 客户端

实现飞书功能前提

  • 飞书开放平台去创建应用,后续需要使用到应用的App ID、App Secret
  • 放开应用对于云文档的操作权限
  • 为了获取云文档的权限,给应用添加群聊机器人权限
  • 在飞书客户端创建群聊,将该应用添加到群聊管理员
  • 完成以上步骤后,可以在开放平台中自行测试后再调用相关接口,如遇到权限不足或者数据为空,请仔细查阅相关文档,本项目只操作最简单的云文档空间展示,后续可自行扩展。

首先,我们需要一个飞书 API 客户端来处理与飞书服务的通信。这是 MCP 服务的基础层,负责封装所有与飞书相关的 API 调用。

在我们的项目中,src/api/feishu.ts 文件实现了飞书客户端,主要包括以下功能:

  1. 身份验证:获取和刷新飞书访问令牌
  2. API 请求封装:处理 HTTP 请求、响应和错误
  3. 知识库操作:提供获取空间列表、文档列表等方法

客户端的核心代码结构如下:

typescript

体验AI代码助手

代码解读

复制代码

export class FeishuClient { private appId: string; private appSecret: string; private accessToken: string | null; private tokenExpireTime: number; private baseUrl: string; constructor(appId?: string, appSecret?: string) { this.appId = appId || process.env.FEISHU_APP_ID || ''; this.appSecret = appSecret || process.env.FEISHU_APP_SECRET || ''; this.accessToken = null; this.tokenExpireTime = 0; this.baseUrl = 'https://open.feishu.cn/open-apis'; } // 获取访问令牌 async getAccessToken(): Promise<string> { // 如果token还有效,直接返回 if (this.accessToken && Date.now() < this.tokenExpireTime) { return this.accessToken; } // 获取新的访问令牌... } // 通用请求方法 async request<T>(method: string, url: string, data: any = null, params: any = null): Promise<T> { // 处理HTTP请求和响应... } // 获取知识空间列表 async getSpaces(pageSize = 50, pageToken = ''): Promise<SpaceResponse> { // 实现获取知识空间列表的逻辑... } // 获取知识空间内的节点列表 async getNodes(spaceId: string, parentNodeToken = '', pageSize = 50, pageToken = ''): Promise<NodeResponse> { // 实现获取节点列表的逻辑... } }

在我们的实现中,飞书客户端完全负责与飞书 API 的交互,使 MCP 服务层可以专注于工具逻辑实现。

构建 MCP 服务和工具注册

MCP 服务的核心部分是工具的定义和注册。在我们的项目中,src/server.ts 文件实现了一个专门的飞书 MCP 服务类:

typescript

体验AI代码助手

代码解读

复制代码

export class FeishuMcpServer { private server: McpServer; private feishuClient: FeishuClient; private transport: Transport | null = null; constructor(appId?: string, appSecret?: string) { // 创建飞书客户端 this.feishuClient = new FeishuClient(appId, appSecret); // 创建MCP服务器 this.server = new McpServer({ name: "飞书文档MCP服务", version: "1.0.0", }, { capabilities: { logging: {}, tools: {}, }, }); // 注册工具 this.registerTools(); } // 工具注册方法 private registerTools() { const { feishuClient } = this; // 注册工具... } }

接下来,让我们详细看看工具注册的实现。我们将实现两个主要工具:列出知识空间和列出文档。

标准工具定义与实现模式

MCP 工具开发是整个服务的核心,包含三个关键部分:

  1. 工具定义:名称、描述和参数类型
  2. 参数验证:使用 Zod 等库进行参数验证
  3. 执行逻辑:实际功能实现和标准化的返回格式

实现一个高质量的 MCP 工具,需要遵循这些原则:

  • 工具名称要简洁明了(推荐使用连字符命名,如 list-spaces
  • 描述要清晰全面,这直接影响 AI 对工具用途的理解
  • 参数验证一定要严格,防止错误输入导致工具执行失败
  • 返回格式必须符合 MCP 规范,否则 AI 无法正确解析

在我们的实现中,有两种工具注册模式:无参数工具和带参数工具。

无参数工具示例:list-spaces

typescript

体验AI代码助手

代码解读

// 列出文档空间 this.server.tool( "list-spaces", "列出所有可用的飞书文档空间", {}, async () => { try { const response = await feishuClient.getSpaces(); const spaces = response.items || []; return { content: [ { type: "text", text: JSON.stringify({ spaces: spaces.map(space => ({ id: space.space_id, name: space.name })) }) } ] }; } catch (error: any) { Logger.error(`获取空间列表失败:`, error); return { isError: true, content: [ { type: "text", text: `获取空间列表失败: ${error.message || '未知错误'}` } ] }; } } );

这个工具没有参数,只需提供一个空对象 {} 作为参数定义。它直接调用飞书客户端获取空间列表,并以标准 MCP 格式返回结果。

带参数工具示例:list-documents

typescript

体验AI代码助手

代码解读

// 列出文档 this.server.tool( "list-documents", "获取指定空间或所有空间的文档列表", { spaceId: z.string().optional().describe("空间ID,不提供则返回所有空间的文档") }, async ({ spaceId }: { spaceId?: string }) => { try { let allDocuments: any[] = []; if (spaceId) { // 获取指定空间的文档 try { const response = await feishuClient.getNodes(spaceId); allDocuments = (response.items || []).map(node => ({ id: node.node_token, name: node.title || 'Untitled', type: node.obj_type || 'Unknown', spaceId: spaceId })); } catch (error: any) { if (error.message?.includes('权限')) { return { isError: true, content: [{ type: "text", text: `无权访问空间(${spaceId})的文档` }] }; } throw error; } } else { // 获取所有空间的文档... } return { content: [ { type: "text", text: JSON.stringify({ documents: allDocuments }) } ] }; } catch (error: any) { Logger.error(`获取文档列表失败:`, error); return { isError: true, content: [ { type: "text", text: `获取文档列表失败: ${error.message || '未知错误'}` } ] }; } } );

这个工具使用 Zod 定义了一个可选的字符串参数 spaceId。根据是否提供 spaceId,工具会采取不同的处理逻辑:获取指定空间的文档或获取所有空间的文档。

标准化错误处理与返回格式

在上面的两个例子中,我们都采用了一致的错误处理模式和返回格式:

  • 成功时,返回一个包含 content 数组的对象,数组中是带有 typetext 字段的内容项
  • 失败时,返回一个带有 isError: true 标志和错误消息的对象

这种标准格式确保了 AI 能够正确解析工具的执行结果,无论成功还是失败。

实现传输层

传输层可以说是 MCP 服务中最容易被忽视却最容易出问题的部分。在实际项目中,大多数 MCP 服务故障都出在传输层,尤其是 SSE 连接相关的问题。

MCP 支持两种主要传输方式:

  1. HTTP SSE(Server-Sent Events):适用于 Web 应用集成
  2. 命令行 STDIO:适用于命令行环境和 API 集成

在我们的项目中,两种传输方式都已实现:

typescript

体验AI代码助手

代码解读

/** * 启动标准输入输出模式 */ async startStdio() { const transport = new StdioServerTransport(); this.transport = transport; await this.connect(transport); return this; } /** * 启动HTTP服务器 * @param port 端口号 */ async startHttp(port: number = 7777) { const app = express(); // 配置路由... // SSE 路由 app.get('/mcp', async (req: Request, res: Response) => { console.log("新的MCP SSE连接已建立"); const transport = new SSEServerTransport( "/mcp-messages", res as unknown as ServerResponse<IncomingMessage>, ); this.transport = transport; await this.connect(transport); }); app.post('/mcp-messages', async (req: Request, res: Response) => { if (!this.transport) { res.status(400).send("SSE连接尚未建立"); return; } const sseTransport = this.transport as SSEServerTransport; await sseTransport.handlePostMessage( req as unknown as IncomingMessage, res as unknown as ServerResponse<IncomingMessage>, ); }); // 启动HTTP服务器... }
传输层的连接管理

无论使用哪种传输方式,我们都需要一个统一的连接方法来处理连接建立后的逻辑:

typescript

体验AI代码助手

代码解读

/** * 连接到传输层 */ private async connect(transport: Transport): Promise<void> { await this.server.connect(transport); // 配置日志... Logger.log("服务器已连接,可以处理请求"); }

这种设计确保了无论使用哪种传输方式,服务器都能正确处理连接和日志记录。

入口文件实现

入口文件是整个服务的启动点,需要处理命令行参数、环境变量以及不同启动模式的选择。在我们的项目中,src/index.ts 实现了服务的启动逻辑:

typescript

体验AI代码助手

代码解读

#!/usr/bin/env node import { FeishuMcpServer } from "./server.js"; import { resolve } from "path"; import { config } from "dotenv"; import 'dotenv/config'; // 加载.env文件 config({ path: resolve(process.cwd(), ".env") }); // 检查必要的环境变量 if (!process.env.FEISHU_APP_ID || !process.env.FEISHU_APP_SECRET) { console.error("错误: 请设置环境变量 FEISHU_APP_ID 和 FEISHU_APP_SECRET"); console.error("您可以在 .env 文件中配置这些变量,例如:"); console.error("FEISHU_APP_ID=your_app_id"); console.error("FEISHU_APP_SECRET=your_app_secret"); process.exit(1); } export async function startServer(): Promise<void> { const port = parseInt(process.env.PORT || '7777', 10); // 创建服务器实例 const server = new FeishuMcpServer( process.env.FEISHU_APP_ID as string, process.env.FEISHU_APP_SECRET as string ); try { // 启动HTTP服务器 console.log("启动飞书MCP服务器..."); await server.startHttp(port); } catch (error) { console.error("服务器启动失败:", error); process.exit(1); } } // 启动服务器 startServer();

这个入口文件完成了几个关键任务:

  1. 加载环境变量配置
  2. 验证必要的凭证是否存在
  3. 创建服务器实例
  4. 启动 HTTP 服务

项目执行与测试

运行项目

sql

体验AI代码助手

代码解读

复制代码

pnpm start

在 cursor 中使用

在 Cursor Settings 中添加 MCP,把下面代码写进去即可,亮绿灯了则表示连接成功

json

体验AI代码助手

代码解读

复制代码

{ "mcpServers": { "feishu-docs": { "url": "http://127.0.0.1:7777/mcp", "enabled": true } } }

测试

至此,项目已经成功搭建~

与 AI 工具集成

创建完 MCP 服务后,主要有以下几种 AI 工具集成方式:

1. 在 Cursor 中使用

Cursor 是一款专为 AI 开发优化的编辑器,原生支持 MCP。集成步骤:

  1. 启动你的 MCP 服务
  2. 在 Cursor 设置中添加 MCP 服务
    • 打开 Cursor 设置
    • 找到 "LLM Tools" 部分
    • 添加自定义 MCP 服务,URL 填写 http://localhost:7777/mcp
  3. 测试集成:在 Cursor 中向 AI 提问,要求它使用你的 MCP 工具
2. 在 Claude API 中使用

通过命令行模式可以将 MCP 服务集成到 Claude API 应用中:

  1. 启动 MCP 服务(命令行模式)node dist/index.js --stdio
  2. 在 API 请求中包含 MCP 工具描述
  3. 管道连接 MCP 服务
3. 作为独立服务运行

你也可以将 MCP 服务部署为独立的微服务,提供给多个 AI 应用使用:

  1. 部署 MCP 服务到服务器
  2. 通过反向代理提供安全访问
  3. 添加认证机制

结语

通过本文,我们详细探讨了 MCP 服务的构建过程,从飞书文档 API 客户端到 MCP 工具定义,再到传输层实现,每个环节都进行了深入讲解。MCP 为 AI 提供了一种安全、标准化的方式与外部世界交互,解决了知识截止和能力边界的问题。

希望这篇文章能帮助你开始构建自己的 MCP 服务。无论你是想增强现有 AI 应用,还是构建全新的智能系统,MCP 都提供了一个强大的框架,让 AI 的能力边界不再受限。

 这份《AI产品经理学习资料包》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以在文末CSDN官方认证二维码免费领取【保证100%免费】
资料包: CSDN大礼包:《对标阿里黑客&网络安全入门&进阶学习资源包》免费分享


AI产品经理,0基础小白入门指南
作为一个零基础小白,如何做到真正的入局AI产品?

什么才叫真正的入局?

是否懂 AI、是否懂产品经理,是否具备利用大模型去开发应用能力,是否能够对大模型进行调优,将会是决定自己职业前景的重要参数。

你是否遇到这些问题:
1、传统产品经理

不懂Al无法对AI产品做出判断,和技术沟通丧失话语权
不了解 AI产品经理的工作流程、重点
2、互联网业务负责人/运营
对AI焦虑,又不知道怎么落地到业务中想做定制化AI产品并落地创收缺乏实战指导
3、大学生/小白
就业难,不懂技术不知如何从事AI产品经理想要进入AI赛道,缺乏职业发展规划,感觉遥不可及
为了帮助开发者打破壁垒,快速了解AI产品经理核心技术原理,学习相关AI产品经理,及大模型技术。从原理出发真正入局AI产品经理。

这里整理了一些AI产品经理学习资料包给大家
📖AI产品经理经典面试八股文
📖大模型RAG经验面试题
📖大模型LLMS面试宝典
📖大模型典型示范应用案例集99个
📖AI产品经理入门书籍
📖生成式AI商业落地白皮书

🔥作为AI产品经理,不仅要懂行业发展方向,也要懂AI技术,可以帮助大家:
✅深入了解大语言模型商业应用,快速掌握AI产品技能
✅掌握AI算法原理与未来趋势,提升多模态AI领域工作能力
✅实战案例与技巧分享,避免产品开发弯路

这份《AI产品经理学习资料包》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
资料包: CSDN大礼包:《对标阿里黑客&网络安全入门&进阶学习资源包》免费分享

AI大模型学习福利
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

大模型&AI产品经理如何学习
求大家的点赞和收藏,我花2万买的大模型学习资料免费共享给你们,来看看有哪些东西。

1.学习路线图


第一阶段: 从大模型系统设计入手,讲解大模型的主要方法;

第二阶段: 在通过大模型提示词工程从Prompts角度入手更好发挥模型的作用;

第三阶段: 大模型平台应用开发借助阿里云PAI平台构建电商领域虚拟试衣系统;

第四阶段: 大模型知识库应用开发以LangChain框架为例,构建物流行业咨询智能问答系统;

第五阶段: 大模型微调开发借助以大健康、新零售、新媒体领域构建适合当前领域大模型;

第六阶段: 以SD多模态大模型为主,搭建了文生图小程序案例;

第七阶段: 以大模型平台应用与开发为主,通过星火大模型,文心大模型等成熟大模型构建大模型行业应用。

2.视频教程
网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己整理的大模型视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要点击CSDN大礼包:《对标阿里黑客&网络安全入门&进阶学习资源包》免费分享前往获取

3.技术文档和电子书
这里主要整理了大模型相关PDF书籍、行业报告、文档,有几百本,都是目前行业最新的。


4.LLM面试题和面经合集
这里主要整理了行业目前最新的大模型面试题和各种大厂offer面经合集。


👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;

• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;

• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;

• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。


1.AI大模型学习路线图
2.100套AI大模型商业化落地方案
3.100集大模型视频教程
4.200本大模型PDF书籍
5.LLM面试题合集
6.AI产品经理资源合集

👉获取方式:
😝有需要的小伙伴,可以CSDN大礼包:《对标阿里黑客&网络安全入门&进阶学习资源包》免费分享免费领取【保证100%免费】🆓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值