在这里插入图片描述

项目结构

在这里插入图片描述
前端项目--------->MCP Client----------->MCP Server
在这里插入图片描述
server就不过多赘述了,他只是相当于添加了多个的tools

链接前后端

http.createServer创建一个服务器


// ----------------------------------------------------------------
// server.js
import http from "http";
import url from "url";
// ----------------------------------------------------------------  const server = http.createServer(async (req: any, res: any) => {const parsedUrl = url.parse(req.url, true); // 解析 url(含 query 参数)const name = parsedUrl.query.name; // ✅ 获取 ?name=xxx 的值res.setHeader("Access-Control-Allow-Origin", "*"); // 允许跨域res.setHeader("Content-Type", "application/json; charset=utf-8");// 简单路由匹配if (req.method === "GET" && parsedUrl.pathname === "/api/hello") {console.log("收到请求参数 name =", name);const ans = await mcpClient.processQuery(name as string);console.log("AI 回复:", ans);res.end(JSON.stringify({ message: ans }));} else {res.statusCode = 404;res.end(JSON.stringify({ error: "接口未找到" }));}});// ----------------------------------------------------------------// 启动服务器server.listen(3002, () => {console.log("🚀 本地服务器启动成功:http://127.0.0.1:3002");});

如何区分多个Server

通过获取配置的server,来进行循环,解构出来所有的tools并且绑定对应的serverName来区分属于哪个Server

const paths = [{name: "mcp",args: "/Users/v-yangziqi1/Desktop/work/mcpserver/mcp/build/index.js",},{name: "mcp1",args: "/Users/v-yangziqi1/Desktop/work/mcpserver/mcp1/build/index.js",},
];// 初始化mcp server连接async connectToServer(serverScriptPath?: string) {if (!serverScriptPath) return;const res = await Promise.all(paths.map((item, index) => {this.mcpServer.push(new Client({ name: "mcp-client-cli-" + item.name, version: "1.0.0" }));const mcp = this.mcpServer[index]; // 创建 MCP Client 实例// 判断文件类型const state = item.args.endsWith(".py")? process.platform === "win32"? "python": "python3": process.execPath;//  建立mcp传输层const transport = new StdioClientTransport({command: state,args: [item.args],});mcp.connect(transport); // connect 方法用于连接到 MCP Server。// 获取 MCP Server 上的所有工具名称return mcp.listTools();}));const nestedArr = res.map(({ tools }, index) => {return tools.map((item) => ({ ...item, serverName: index })); // serverName是服务器的index所引致});const toolsArr = nestedArr.flat();// console.log("obj", JSON.stringify(toolsArr, null, 2));// 生成工具数组this.tools = toolsArr.map((t) => ({name: t.name, // 工具名称description: t.description || "", // 工具描述parameters: t.inputSchema, // 工具参数定义Schema的格式execute: async (args: any) => {// 执行工具的逻辑const result = await this.mcpServer[t.serverName].callTool({name: t.name,arguments: args,});return result.content as string;},}));console.log("已连接 MCP Server,工具:",this.tools.map((t) => t.name).join(", "));}

完整代码

// mcp-client-cli.ts
import axios from "axios"; // 引入axios用于发送HTTP请求
import readline from "readline/promises"; // 获取用户的输入命令
import dotenv from "dotenv"; // 用于加载环境变量配置文件(.env)
import { Client } from "@modelcontextprotocol/sdk/client/index.js"; // MCP Client 的核心类
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; // StdioClientTransport 是 MCP Client 的传输层,// ----------------------------------------------------------------
// server.js
import http from "http";
import url from "url";
// ----------------------------------------------------------------dotenv.config();const QIHOOGPT_KEY = process.env.QIHOOGPT_KEY;
if (!QIHOOGPT_KEY) throw new Error("请在 .env 中配置 QIHOOGPT_KEY");interface ToolCall {id: string;function: {name: string;arguments: string;};
}interface ToolDefinition {name: string;description: string;parameters: Record<string, any>;execute: (args: any) => Promise<string>;
}
const paths = [{name: "mcp",args: "/Users/v-yangziqi1/Desktop/work/mcpserver/mcp/build/index.js",},{name: "mcp1",args: "/Users/v-yangziqi1/Desktop/work/mcpserver/mcp1/build/index.js",},
];
class MCPClient {private model = "360gpt-pro";private tools: ToolDefinition[] = [];private mcpServer: Client[] = [];// 初始化mcp server连接async connectToServer(serverScriptPath?: string) {if (!serverScriptPath) return;const res = await Promise.all(paths.map((item, index) => {this.mcpServer.push(new Client({ name: "mcp-client-cli-" + item.name, version: "1.0.0" }));const mcp = this.mcpServer[index]; // 创建 MCP Client 实例// 判断文件类型const state = item.args.endsWith(".py")? process.platform === "win32"? "python": "python3": process.execPath;//  建立mcp传输层const transport = new StdioClientTransport({command: state,args: [item.args],});mcp.connect(transport); // connect 方法用于连接到 MCP Server。// 获取 MCP Server 上的所有工具名称return mcp.listTools();}));const nestedArr = res.map(({ tools }, index) => {return tools.map((item) => ({ ...item, serverName: index })); // serverName是服务器的index所引致});const toolsArr = nestedArr.flat();// console.log("obj", JSON.stringify(toolsArr, null, 2));// 生成工具数组this.tools = toolsArr.map((t) => ({name: t.name, // 工具名称description: t.description || "", // 工具描述parameters: t.inputSchema, // 工具参数定义Schema的格式execute: async (args: any) => {// 执行工具的逻辑const result = await this.mcpServer[t.serverName].callTool({name: t.name,arguments: args,});return result.content as string;},}));console.log("已连接 MCP Server,工具:",this.tools.map((t) => t.name).join(", "));}// 将工具定义转换为模型可以理解的格式private convertTool(tool: ToolDefinition) {return {type: "function",function: {name: tool.name,description: tool.description,parameters: tool.parameters,},};}// 360模型的方法private async call360GPT(payload: any) {const { data } = await axios.post("https://api.360.cn/v1/chat/completions",{ ...payload, stream: false },{headers: {"Content-Type": "application/json",Authorization: `Bearer ${QIHOOGPT_KEY}`,},});return data;}// 处理用户查询// 该方法会将用户的查询发送到360GPT模型,并处理返回的async processQuery(query: string) {const messages: any[] = [{ role: "user", content: query }];// 发送用户消息和mcp server的tools到360GPT模型const res = await this.call360GPT({model: this.model, // 模型名称messages, // 用户消息tools: this.tools.map((t) => this.convertTool(t)), // 工具列表tool_choice: "auto", // 自动选择工具});const choice = res.choices[0]; // 获取模型返回的第一个选择const toolCalls = choice.message.tool_calls as ToolCall[] | undefined; // 获取工具调用列表console.log(choice);console.log(toolCalls);// 如果有工具调用,则执行工具if (toolCalls?.length) {console.log("工具调用列表:", toolCalls);for (const call of toolCalls) {// 在 tools 数组中查找与调用名称匹配的工具const tool = this.tools.find((t) => t.name === call.function.name);if (!tool) continue; // 如果没有找到对应的工具,跳过const args = JSON.parse(call.function.arguments || "{}"); // 解析工具调用的参数const result = await tool.execute(args); // 执行工具并获取结果messages.push({ role: "user", content: result }); // 将工具结果添加到消息中console.log(messages);// 再次调用360GPT模型,传入更新后的消息进行润色console.log("🤖 正在思考...");const final = await this.call360GPT({ model: this.model, messages });// 如果有工具调用结果,则返回最终的内容return final.choices[0].message.content;}}return choice.message.content;}// 聊天循环方法async chatLoop() {// 创建 readline 接口,用于读取用户输入const rl = readline.createInterface({input: process.stdin,output: process.stdout,});console.log("输入内容,输入 quit 退出:");while (true) {const query = await rl.question("请输入: "); // 提示用户输入查询内容if (query.toLowerCase() === "quit") break;console.log("🤖 正在思考...");const ans = await this.processQuery(query);console.log("\nAI:", ans, "\n");}rl.close();}
}(async () => {const mcpClient = new MCPClient();const scriptArg = process.argv[2];// 初始化if (scriptArg) await mcpClient.connectToServer(scriptArg);// 服务器监听// await mcpClient.chatLoop();// process.exit(0);// ----------------------------------------------------------------// server.js// 创建一个简单的服务器const server = http.createServer(async (req: any, res: any) => {const parsedUrl = url.parse(req.url, true); // 解析 url(含 query 参数)const name = parsedUrl.query.name; // ✅ 获取 ?name=xxx 的值res.setHeader("Access-Control-Allow-Origin", "*"); // 允许跨域res.setHeader("Content-Type", "application/json; charset=utf-8");// 简单路由匹配if (req.method === "GET" && parsedUrl.pathname === "/api/hello") {console.log("收到请求参数 name =", name);const ans = await mcpClient.processQuery(name as string);console.log("AI 回复:", ans);res.end(JSON.stringify({ message: ans }));} else {res.statusCode = 404;res.end(JSON.stringify({ error: "接口未找到" }));}});// ----------------------------------------------------------------// 启动服务器server.listen(3002, () => {console.log("🚀 本地服务器启动成功:http://127.0.0.1:3002");});
})();

验证是否成功

在这里插入图片描述
已经获取到两个仓库的参数了
trae的仓库
在这里插入图片描述

开始调用

这样就称得上是成功了
在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/913672.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/913672.shtml
英文地址,请注明出处:http://en.pswp.cn/news/913672.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

香港站群服务器与普通香港服务器对比

在选择香港服务器时&#xff0c;用户常常会遇到"站群服务器"和"普通服务器"两种选项&#xff0c;虽然它们都基于香港数据中心的基础设施&#xff0c;但在 IP 地址配置、功能定位和管理复杂度、成本上存在显著差异&#xff0c;理解这些差异有助于用户根据实…

4.B树和B+树的区别?为什么MySQL选择B+树作为索引?

区别&#xff1a;1.数据存储位置B树每个节点都存储了索引和数据B树只有叶子节点存储数据&#xff0c;非叶子节点仅存储索引2.叶子节点的链接B树的所有叶子节点通过指针连接成一个双向链表&#xff0c;可以高效地进行范围查询或者顺序遍历B树则没有这样的连接关系&#xff0c;查…

转换狂魔,Modbus TCP转Profinet网关打通视觉传感线连接之路

在汽车零部件冲压生产线的世界中&#xff0c;液压机的压力稳定性是确保产品质量的秘密武器。然而&#xff0c;旧时代的人工巡检和传统监测方式却好似拖累现代化进程的沉重枷锁&#xff1a;效率低、成本高&#xff0c;还总是赶不上实时反馈的快车。这时&#xff0c;工厂决心大刀…

C++进阶—二叉树进阶

第一章&#xff1a;内容安排说明 map和set特性需要先铺垫二叉搜索树&#xff0c;而二叉搜索树也是一种树形结构二叉搜索树的特性了解&#xff0c;有助于更好的理解map和set的特性二叉树中部分面试题稍微有点难度&#xff0c;在前面讲解大家不容易接受&#xff0c;且时间长容易…

驱动下一代E/E架构的神经脉络进化—10BASE-T1S

汽车电子电气架构的演进正经历一场深刻的变革&#xff0c;“中央计算单元区域控制器”的架构模式已成为当前主流车型平台发展的明确方向。这种从传统的“功能域”&#xff08;Domain&#xff09;架构向“区域”&#xff08;Zonal&#xff09;架构的转型升级&#xff0c;旨在实现…

某学校系统中挖矿病毒应急排查

本篇文章主要记录某学校长期未运营维护的程序&#xff0c;被黑客发现了漏洞&#xff0c;但好在学校有全流量设备&#xff0c;抓取到了过程中的流量包 需要你进行上机以及结合流量分析&#xff0c;排查攻击者利用的漏洞以及上传利用成功的木马 文章目录靶机介绍1.使用工具分析共…

vue 、react前端页面支持缩放,echarts、地图点击左边不准的原因和解决办法

原因 由于以上都是通过canvas画布生成的&#xff0c;一旦初始化&#xff0c;就会按照比例进行缩放&#xff0c;但与此同时&#xff0c;比例尺并没有变化&#xff0c;导致坐标偏移 解决办法 设置一个zoomVal产量&#xff0c;在页面加载时计算缩放比例&#xff0c;然后在canvas容…

(LeetCode 每日一题) 1353. 最多可以参加的会议数目 (优先队列、小顶堆)

题目&#xff1a;1353. 最多可以参加的会议数目 思路&#xff1a;优先队列实现小顶堆&#xff0c;0(mx*logn) 在第i天&#xff0c;优先选endDay最小的那一个活动进行。那么遍历每一天&#xff0c;用小顶堆来维护每个活动的最后一天即可&#xff0c;细节看注释。 C版本&#xf…

Java结构型模式---代理模式

代理模式基础概念代理模式是一种结构型设计模式&#xff0c;其核心思想是通过创建一个代理对象来控制对另一个真实对象的访问。代理对象在客户端和真实对象之间起到中介作用&#xff0c;允许在不改变真实对象的前提下&#xff0c;对其进行增强或控制。代理模式的核心组件主题接…

MySQL流程控制函数全解析

MySQL 中的流程控制函数&#xff08;也称为条件函数&#xff09;允许你在 SQL 语句中进行逻辑判断&#xff0c;根据不同的条件返回不同的值或执行不同的操作。它们极大地增强了 SQL 的灵活性和表达能力&#xff0c;尤其在进行数据转换、结果格式化、条件聚合和复杂业务逻辑实现…

【7】PostgreSQL 事务

【7】PostgreSQL 事务前言使用事务事务内错误处理事务保存点DDL 事务前言 在 PostgreSQL 中&#xff0c;每一个操作都是一个事务。即使一个简单的查询(select)&#xff0c;这也是一个事务。 例如&#xff1a; postgres# select now();now --------------------…

Linux:多线程---深入互斥浅谈同步

文章目录1. 互斥1.1 为什么需要互斥1.2 互斥锁1.3 初谈互斥与同步1.4 锁的原理1.5 可重入VS线程安全1.6 死锁1.7 避免死锁的算法&#xff08;扩展&#xff09;序&#xff1a;在上一章中我们知道了线程控制的三个角度&#xff1a;线程创建、线程等待和线程终止&#xff0c;分别从…

适用于 vue2、vue3 的自定义指定:v-int(正整数)

在项目中&#xff0c;我们经常会遇到输入框只允许输入数字的情况&#xff0c;下面是一段自定义指定 代码&#xff0c;复制到项目中&#xff0c;注册指定即可使用用法如下&#xff1a; 创建一个IntInput.js 文件&#xff0c;将下面代码复制到文件中保存在项目中的 main.js 文件中…

学习基于springboot秒杀系统-环境配置(接口封装,mybatis,mysql,redis(Linux))

文章目录前言创建springboot项目封装controller层输入输出rest api 的json输出返回页面集成mybatis集成redis下载虚拟机和centos下载redis.tar.gz上传redis.tar.gz 到虚拟机前言 今天开始记录学习秒杀系统-课程是基于慕课上的搜索秒杀系统的课程&#xff0c;老师讲解非常好。这…

stm32达到什么程度叫精通?

STM32达到什么程度叫精通&#xff1f;一个十年老兵的深度反思 前言&#xff1a;精通二字&#xff0c;重如泰山 每次有人问我"STM32达到什么程度叫精通"这个问题&#xff0c;我都会沉默很久。 不是因为这个问题难回答&#xff0c;而是因为"精通"这两个字太重…

微软上线Deep Research:OpenAI同款智能体,o3+必应双王炸

今天凌晨&#xff0c;微软在官网宣布&#xff0c;Azure AI Foundry中上线Deep Research公开预览版。这是支持API和SDK的OpenAI 高级智能体研究能力产品&#xff0c;并且Azure 的企业级智能体平台完全集成。Deep Research是OpenAI在今年4月25日发布的最新产品&#xff0c;能够像…

Spring Batch终极指南:原理、实战与性能优化

&#x1f31f; Spring Batch终极指南&#xff1a;原理、实战与性能优化单机日处理10亿数据&#xff1f;揭秘企业级批处理架构的核心引擎&#xff01;一、Spring Batch 究竟是什么&#xff1f;Spring batch是用于创建批处理应用程序&#xff08;执行一系列作业&#xff09;的开源…

【Part 3 Unity VR眼镜端播放器开发与优化】第四节|高分辨率VR全景视频播放性能优化

文章目录《VR 360全景视频开发》专栏Part 3&#xff5c;Unity VR眼镜端播放器开发与优化第一节&#xff5c;基于Unity的360全景视频播放实现方案第二节&#xff5c;VR眼镜端的开发适配与交互设计第三节&#xff5c;Unity VR手势交互开发与深度优化第四节&#xff5c;高分辨率V…

TCP/IP协议基础

TCPIP协议基础 网络模型 -OSI参考模型 -OSI参考模型各层功能 -TCP/IP网络模型 -TCP/IP协议栈OSI参考模型 – 为了解决网络设备之间的兼容性问题&#xff0c;国际标准化组织ISO于1984年提出了OSI RM&#xff08;开放系统互连参考模型&#xff09;。 OSI参考模型一共有七层&#…

【Nginx】Nginx代理WebSocket

1.websocketWebSocket 是一种网络通信协议&#xff0c;它提供了在单个 TCP 连接上进行全双工&#xff08;双向&#xff09;通信的能力假设需求&#xff1a;把 ws://192.168.0.1:8088/ws-api/websocket/pushData代理到ws://192.168.0.156:8888/websocket/pushData&#xff1b;同…