讲师中心 微信公众号

工具推荐

视频效率加速
updream

一键生成高质量推广成片

Seko
Seko

AI短剧一键生成成片

剧云
剧云

中文短剧剧本制作平台

Laper
Laper

剧本策划到成片协作

MCP SDK 快速接入 DeepSeek 并添加工具!万万没想到MCP这么简单好用!

阿涛小哥_5969

阿涛小哥_5969

发布时间:2025-05-11 11:14:16

|

280人浏览过

|

来源于php中文网

原创

前言

重新整理了上篇文章,主要修正了错误的地方,加上了正确的截图和代码!感谢大家的积极指正!

这篇文章记录一下我用 MCPTypeScriptSDK 实现一个自包含的 AI 聊天应用的过程:内部包含 MCP 服务器提供上下文,客户端拿上下文再去调 LLM 接口拿回答!

正文MCP 是什么?

简单说,MCP 是一个给 AI 应用提供上下文的标准协议。你可以把它理解成一个服务标准,它规定了“资源”和“工具”的接口规范,然后通过客户端连接这些接口,就可以组合出丰富的上下文数据。比如说资源可以是“当前时间”、“用户历史记录”,工具可以是“数据库搜索”、“调用外部 API”。

它采用的是客户端-服务器架构,Server 暴露上下文能力,Client 拉取这些上下文,再拿去调语言模型生成回答,而 Transport 负责 Server 和 Client 的通信部分!

MCP SDK 快速接入 DeepSeek 并添加工具!万万没想到MCP这么简单好用!MCP 架构

MCP 架构

(AI 帮我画的图)

其中图片中的 Transport 层还分为:

StdioServerTransport:用于 CLI 工具对接 stdin/stdoutSSEServerTransport:用于HTTP通信StdioClientTransport:客户端以子进程方式拉起服务端,这个不常用

另外,Server 层分为:

Server 基本类:原始的类,适合自己定制功能!McpServer基于Server 封装好了可以快速使用的方法!安装依赖

用的是官方的 TypeScriptSDK:

仓库:https://github.com/modelcontextprotocol/typescript-sdk

官网:https://modelcontextprotocol.io

代码语言:javascript代码运行次数:0运行复制
npm install @modelcontextprotocol/sdk axios

DeepSeek 没有官方 SDK,用的是 HTTP API,所以需要 axios!

记得把 API Key 放到 .env 或直接配置成环境变量,我用的 DEEPSEEK_API_KEY。

实现一个 McpServer

我们先实现一个本地 McpServer,实现两个东西:

Github Codebase Inspection
Github Codebase Inspection

使用 pygount 检查代码库:统计代码行数(LOC)、编程语言及占比。

下载
当前时间(资源)本地“知识库”搜索(工具)

代码如下:

代码语言:javascript代码运行次数:0运行复制
// src/server.jsimport {  McpServer,  ResourceTemplate,} from"@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from"@modelcontextprotocol/sdk/server/stdio.js";import { z } from"zod";const facts = ["公理1: 生存是文明的第一需要.","公理2: 文明不断增长和扩张,但宇宙中的物质总量保持不变.",].map((f) => f.toLowerCase());try {const server = new McpServer({    name: "mcp-cli-server",    version: "1.0.0",  });// 使用 Zod 定义工具的输入模式  server.tool(    "search_local_database",   {      query: z.string(),    },    async ({ query }) => {      console.log("Tool called with query:", query);      const queryTerms = query.toLowerCase().split(/\s+/);      const results = facts.filter((fact) =>        queryTerms.some((term) => fact.includes(term))      );      return {        content: [          {            type: "text",            text: results.length === 0 ? "未找到相关公理" : results.join("\n"),          },        ],      };    }  );// 定义资源  server.resource(    "current_time",    new ResourceTemplate("time://current", { list: undefined }),    async (uri) => ({      contents: [{ uri: uri.href, text: newDate().toLocaleString() }],    })  );await server.connect(new StdioServerTransport());console.log("Server is running...");} catch (err) {console.error("Server connection failed:", err);}

这样一来,我们的服务端就能通过 MCP 协议对外暴露两个上下文能力了。

配置 MCP Client

MCP 的客户端用来连接服务器并获取资源或调用工具:

代码语言:javascript代码运行次数:0运行复制
// src/client.js;import { Client } from"@modelcontextprotocol/sdk/client/index.js";import { StdioClientTransport } from"@modelcontextprotocol/sdk/client/stdio.js";exportasyncfunction createClient() {const client = new Client({    name: "Demo",    version: "1.0.0",  });const transport = new StdioClientTransport({    command: "node",    args: ["src/server.js"],  });try {    await client.connect(transport);    console.log("Client connected successfully");  } catch (err) {    console.error("Client connection failed:", err);    throw err;  }// 可选:添加客户端方法调用后的调试return client;}

连上之后,我们就可以开始调用服务端的资源和工具了。

获取上下文

我们设定一个简单的逻辑:每次用户提问,客户端都会获取当前时间;如果问题里包含 公理,那就调用搜索工具查一下本地知识库:

代码语言:javascript代码运行次数:0运行复制
async function getContext(client, question) {let currentTime = "";let additionalContext = "";try {    const resources = await client.readResource(      { uri: "time://current" },      { timeout: 15000 }    ); // 增加超时时间    console.log("Resources response:", resources);    currentTime = resources.contents[0]?.text ||      newDate().toLocaleString(); // 注意:resources 直接包含 contents  } catch (err) {    console.error("Resource read error:", err);    currentTime = newDate().toLocaleString();  }if (question.toLowerCase().includes("公理")) {    console.log("Searching for axioms...", question);    try {      const result = await client.getPrompt({        name: "search_local_database",        arguments: { query: question },      });      console.log("Tool result:", result);      additionalContext = result?.[0]?.text || "No results found.";    } catch (err) {      console.error("Tool call error:", err);      additionalContext = "Error searching database.";    }  }return { currentTime, additionalContext };}
集成 DeepSeek,开始问答

DeepSeek 使用的是标准 OpenAI 接口风格,HTTP POST 请求即可。这里我们用 axios 调用:

代码语言:javascript代码运行次数:0运行复制
import axios from"axios";asyncfunction askLLM(prompt) {try {    console.log("Calling LLM with prompt:", prompt);    const res = await axios.post(      "https://api.deepseek.com/chat/completions",      {        model: "deepseek-chat",        messages: [{ role: "user", content: prompt }],        max_tokens: 2048,        stream: false,        temperature: 0.7,      },      {        headers: {          Authorization: `Bearer ${process.env.DEEPSEEK_API_KEY}`,          "Content-Type": "application/json",        },        timeout: 1000000,      }    );    console.log("LLM response:", res.data);    return res.data.choices[0].message.content;  } catch (err) {    console.error("LLM error:", err);    return"Error calling LLM.";  }}

完整的代码,包含用命令行做一个简单的交互界面:

代码语言:javascript代码运行次数:0运行复制
// src/index.jsimport readline from"readline";import axios from"axios";import { createClient } from"./client.js";import { DEEPSEEK_API_KEY } from"./config.js";asyncfunction askLLM(prompt) {try {    console.log("Calling LLM with prompt:", prompt);    const res = await axios.post(      "https://api.deepseek.com/chat/completions",      {        model: "deepseek-chat",        messages: [{ role: "user", content: prompt }],        max_tokens: 2048,        stream: false,        temperature: 0.7,      },      {        headers: {          Authorization: `Bearer ${DEEPSEEK_API_KEY}`,          "Content-Type": "application/json",        },        timeout: 1000000,      }    );    return res.data.choices[0].message.content;  } catch (err) {    console.error("LLM error:", err);    return"Error calling LLM.";  }}asyncfunction getContext(client, question) {let currentTime = "";let additionalContext = "";try {    const resources = await client.readResource(      { uri: "time://current" },      { timeout: 15000 }    ); // 增加超时时间    currentTime = resources.contents[0]?.text || newDate().toLocaleString(); // 注意:resources 直接包含 contents  } catch (err) {    console.error("Resource read error:", err);    currentTime = newDate().toLocaleString();  }if (question.toLowerCase().includes("公理")) {    try {      // const result = await client.getPrompt({      //   name: "search_local_database",      //   arguments: { query: question },      // });            const toolResult = await client.callTool({        name: "search_local_database",        arguments: { query: question },      });      console.log("Tool result:", toolResult);      additionalContext = toolResult?.content?.[0]?.text || "No results found.";    } catch (err) {      console.error("Tool call error:", err);      additionalContext = "Error searching database.";    }  }return { currentTime, additionalContext };}const rl = readline.createInterface({  input: process.stdin,  output: process.stdout,});const client = await createClient();while (true) {const question = awaitnewPromise((resolve) =>    rl.question("You: ", resolve)  );if (question.toLowerCase() === "exit") {    console.log("Exiting...");    rl.close();    process.exit(0);  }// 使用上下文const context = await getContext(client, question);// 不使用上下文// const context = {};const prompt = `Time: ${context.currentTime}\nContext: ${context.additionalContext}\nQ: ${question}\nA:`;console.log("Prompt:", prompt);const answer = await askLLM(prompt);console.log('Assistant:', answer);}

接着在终端运行:

代码语言:javascript代码运行次数:0运行复制
# 启动服务器node src/server.js
代码语言:javascript代码运行次数:0运行复制
# 启动客户端node src/index.js

运行结果:可以看到识别到关键字之后,答案更加集中在特定领域!

MCP SDK 快速接入 DeepSeek 并添加工具!万万没想到MCP这么简单好用!未命中关键词

未命中关键词

MCP SDK 快速接入 DeepSeek 并添加工具!万万没想到MCP这么简单好用!命中了关键词

命中了关键词

一些注意点

这个项目虽然小,但也踩了些坑,顺便分享几点:

MCP SDK 的 server 和 client 都是异步启动的,别忘了加上 await connect()。工具的入参和 schema 必须严格匹配,否则会抛错。

下面是我的目录结构,做个参考吧!

代码语言:javascript代码运行次数:0运行复制
mcp-mini/├── package.json├── src/│   ├── client.js│   ├── server.js│   └── index.js
最后

总的来说,MCP TypeScriptSDK 用起来还是挺顺的,适合做一些轻量、模块化、支持上下文的 AI 应用。这种服务 + 客户端 + LLM 的组合模式挺适合本地测试,也方便后续扩展别的服务。

今天的分享就到这了,如果文章中有啥错误,欢迎指正!

热门AI工具

更多
墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

相关专题

更多
TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

332

2026.02.13

TypeScript全栈项目架构与接口规范设计
TypeScript全栈项目架构与接口规范设计

本专题面向全栈开发者,系统讲解基于 TypeScript 构建前后端统一技术栈的工程化实践。内容涵盖项目分层设计、接口协议规范、类型共享机制、错误码体系设计、接口自动化生成与文档维护方案。通过完整项目示例,帮助开发者构建结构清晰、类型安全、易维护的现代全栈应用架构。

540

2026.02.25

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

411

2026.03.13

TypeScript 全栈开发进阶指南
TypeScript 全栈开发进阶指南

面向有 JavaScript 基础的开发者,深入讲解 TypeScript 的类型系统与全栈开发实践。

326

2026.06.03

TypeScript Node.js 全栈工程化与Monorepo架构实践
TypeScript Node.js 全栈工程化与Monorepo架构实践

本专题围绕 TypeScript 在 Node.js 全栈开发中的工程化实践展开,系统讲解 Monorepo 架构设计、包管理策略、模块复用机制以及服务端与前端统一类型系统的构建方法。通过真实项目案例,帮助开发者提升大型全栈项目的可维护性与协作效率。

738

2026.06.16

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3228

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

5369

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

3889

2025.12.29

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

40

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Postman Native Git工作流指南
Postman Native Git工作流指南

共0课时 | 0人学习

vscode手册
vscode手册

共0课时 | 0人学习

Git 教程
Git 教程

共21课时 | 8.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn