logo 🤗

技术视野

聚焦科技前沿,分享技术解析,洞见未来趋势。在这里,与您一起探索人工智能的无限可能,共赴技术盛宴。

logo
  • 需要已经安装nodejs以及python环境
  • 准备好任意一个大模型的api-key和base_url
  • 和上节一样,我们先试试用tool来调用当前时间,使用mcp-server-time 来做演示。
  • 使用pip安装一下它。
pip install mcp-server-time
  1. 初始化一个Nodejs项目,安装mcp ts sdk / openai / node types
npm init -y
npm install @modelcontextprotocol/sdk
npm install openai
npm i --save-dev @types/node
  1. 全局安装ts,初始化ts项目
npm install -g typescript
tsc --init
  1. 安装完成后,我们可以使用下面的代码来测试一下。
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport, StdioServerParameters} from "@modelcontextprotocol/sdk/client/stdio.js";


const params: StdioServerParameters = {
  command: "python", // 建议改成你的python绝对路径
  args: [
     "-m",
    "mcp_server_time",
    "--local-timezone=Asia/Shanghai"
  ]
} 

const transport = new StdioClientTransport(params);

const client = new Client(
  {
    name: "example-client",
    version: "1.0.0"
  }
);

await client.connect(transport);

// List tool
const tools = await client.listTools();
console.log("===tools===")
console.log(tools)
console.log("==========")
// Call a tool
const result = await client.callTool({
  name: "get_current_time",
  arguments: {
    timezone: "Asia/Shanghai"
  }
});
if (Array.isArray(result.content) && result.content.length > 0) {
  let data: {type: string, text: string} = result.content[0];
  console.log("===result ===")
  console.log(data.text)
  console.log("===========")
}

await client.close()
  1. 输出结果,可以看到能够准确获取当前时间
===tools===
{
  tools: [
    {     
      name: 'get_current_time',
      description: 'Get current time in a specific timezones',
      inputSchema: [Object]
    },
    {
      name: 'convert_time',
      description: 'Convert time between timezones',
      inputSchema: [Object]
    }
  ]
}
==========
===result ===
{
  "timezone": "Asia/Shanghai",
  "datetime": "2025-06-05T10:22:33+08:00",
  "is_dst": false
}
===========
  1. 不过,上面调用工具这块,不够优雅。只能手动调用固定的tool,这部分应该让AI来完成,就像我们上一节做的那样,我们提供工具和命令,AI执行工具以及获取结果。我们应该将工具和要求传给AI,我们可以回忆一下之前tool_call时,是怎么做的。于是有了下面的代码:
import {Client} from "@modelcontextprotocol/sdk/client/index.js"
import {StdioClientTransport, StdioServerParameters} from "@modelcontextprotocol/sdk/client/stdio.js"
import {OpenAI} from "openai"
import {
  ChatCompletionCreateParamsBase,
  ChatCompletionMessageParam,
  ChatCompletionTool,
  ChatCompletion
} from "openai/src/resources/chat/completions.js"

const params: StdioServerParameters = {
  command: "python", // 建议改成你的python绝对路径
  args: [
    "-m",
    "mcp_server_time",
    "--local-timezone=Asia/Shanghai"
  ]
};

class MCPClient {
  #transport = new StdioClientTransport(params);
  #client = new Client({
    name: "Demo",
    version: "0.1.0"
  })
  #aiSession = new OpenAI({
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
    apiKey: process.env["DASHSCOPE_API_KEY"]
  });
  #model = "qwen-max" // 你可以换成其他的

  async connect() {
    await this.#client.connect(this.#transport)
  }

  async processQuery(query: string, system_prompt: string ="You are a helpful assistant.") {

    let messages: Array<ChatCompletionMessageParam> = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": query}
    ];
    let toolResponse = await this.#client.listTools()
    // 生成 tool call 的描述信息
    let availableTools: ChatCompletionTool[] = toolResponse.tools.map((tool)=>{
      return {
        type: "function",
        function: {
          name: tool.name,
          description: tool.description ?? "",
          parameters: tool.inputSchema
        }
      }
    });
    // console.log("await Tools:", availableTools);
    // 调用模型
    let clientParams: ChatCompletionCreateParamsBase = {
        messages: messages,
        model: this.#model,
        tools: availableTools
    }
    let response = await this.#aiSession.chat.completions.create(clientParams) as ChatCompletion;
    // console.log(response)
    if (response.choices.length > 0) {
      let choice = response.choices[0];
      if (choice.finish_reason == "tool_calls" && choice.message.tool_calls?.length) {
        // 如果AI决定执行tool_call
        let toolCall = choice.message.tool_calls[0];
        let toolName = toolCall.function.name;
        let toolArgs = JSON.parse(toolCall.function.arguments);
        // 将结果加入message
        messages.push({
          role: "assistant",
          tool_calls: [toolCall]
        });
        // 执行工具
        let toolResult = await this.#client.callTool({
          name: toolName,
          arguments: toolArgs
        });
        let toolText: string = "";
        if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {
          toolText = toolResult.content[0].text;
        }
        // 将工具执行结果丢给AI处理
        messages.push({
          role: "tool",
          content: toolText,
          tool_call_id: toolCall.id,
        });
        // 将上面的结果再返回给 AI用于生产最终的结果
        let aiResponse = await this.#aiSession.chat.completions.create({
          messages: messages,
          model: this.#model,
        });
        let content = aiResponse.choices?.[0].message.content?? "";
        return content
      } else {
        let content = response.choices?.[0].message.content?? "";
        return content
      }
    } else {
      return "";
    }

  }

  async disconect() {
    await this.#client.close();
  }
}

let mcpClient = new MCPClient();
await mcpClient.connect();
let response = await mcpClient.processQuery("当前时间是?")
console.log(response)
await mcpClient.disconect();
  • 运行一下,输出结果为:
根据您提供的信息,当前时间是2025年6月5日12点53分28秒,时区为亚洲/上海(+08:00),并且没有实行夏令时。请注意,这个时间是您所提供数据中的时间,并非实时获取的时间。
  1. 上面输入时写死的,如果还要更加灵活的话,我们可以支持用户自定义输入,并且弄一个循环体,并且利用messages来控制上下文,于是就有了下面的代码。
import {Client} from "@modelcontextprotocol/sdk/client/index.js"
import {StdioClientTransport, StdioServerParameters} from "@modelcontextprotocol/sdk/client/stdio.js"
import {OpenAI} from "openai"
import * as readline from "node:readline/promises";
import {stdin, stdout} from "node:process"
import {
  ChatCompletionCreateParamsBase,
  ChatCompletionMessageParam,
  ChatCompletionTool,
  ChatCompletion
} from "openai/src/resources/chat/completions.js"

const params: StdioServerParameters = {
  command: "C:\\Users\\37104\\anaconda3\\envs\\tools\\python",
  args: [
    "-m",
    "mcp_server_time",
    "--local-timezone=Asia/Shanghai"
  ]
};

class MCPClient {
  #transport = new StdioClientTransport(params);
  #client = new Client({
    name: "Demo",
    version: "0.1.0"
  })
  #aiSession = new OpenAI({
    baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
    apiKey: process.env["DASHSCOPE_API_KEY"]
  });
  #model = "qwen-max" // 你可以换成其他的

  async connect() {
    await this.#client.connect(this.#transport)
  }

  async processQuery(messages: Array<ChatCompletionMessageParam>) {
    let toolResponse = await this.#client.listTools()
    // 生成 tool call 的描述信息
    let availableTools: ChatCompletionTool[] = toolResponse.tools.map((tool)=>{
      return {
        type: "function",
        function: {
          name: tool.name,
          description: tool.description ?? "",
          parameters: tool.inputSchema
        }
      }
    });
    // console.log("await Tools:", availableTools);
    // 调用模型
    let clientParams: ChatCompletionCreateParamsBase = {
        messages: messages,
        model: this.#model,
        tools: availableTools
    }
    let response = await this.#aiSession.chat.completions.create(clientParams) as ChatCompletion;
    // console.log(response)
    if (response.choices.length > 0) {
      let choice = response.choices[0];
      if (choice.finish_reason == "tool_calls" && choice.message.tool_calls?.length) {
        // 如果AI决定执行tool_call
        let toolCall = choice.message.tool_calls[0];
        let toolName = toolCall.function.name;
        let toolArgs = JSON.parse(toolCall.function.arguments);
        // 将结果加入message
        messages.push({
          role: "assistant",
          tool_calls: [toolCall]
        });
        // 执行工具
        let toolResult = await this.#client.callTool({
          name: toolName,
          arguments: toolArgs
        });
        let toolText: string = "";
        if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {
          toolText = toolResult.content[0].text;
        }
        // 将工具执行结果丢给AI处理
        messages.push({
          role: "tool",
          content: toolText,
          tool_call_id: toolCall.id,
        });
        // 将上面的结果再返回给 AI用于生产最终的结果
        let aiResponse = await this.#aiSession.chat.completions.create({
          messages: messages,
          model: this.#model,
        });
        let content = aiResponse.choices?.[0].message.content?? "";
        return content
      } else {
        let content = response.choices?.[0].message.content?? "";
        return content
      }
    } else {
      return "";
    }

  }

  async disconect() {
    await this.#client.close();
  }
}

async function main() {
  const system_prompt: string ="You are a helpful assistant."
  let messages: Array<ChatCompletionMessageParam> = [
      {role: "system", content: system_prompt},
  ];
  let mcpClient = new MCPClient();
  await mcpClient.connect();
  console.log("=".repeat(20))
  console.log("欢迎使用AI聊天机器人,你可以问我当前时间相关信息,输入exit或者quit退出,输入clear清空历史记录")
  console.log("=".repeat(20))
  const face = readline.createInterface({input: stdin, output: stdout});
  while (true) {
    const query = await face.question("input: ")
    messages.push({role: "user", content: query});
    if (["exit", "exit()"].includes(query)) {
      console.log("output: 即将退出");
      break;
    }
    if (["clear", "clear()"].includes(query)) {
      messages = messages.slice(0, 1);
      console.log("messages length: ", messages.length)
      console.log("output: 已清理历史对话信息。")
    }
    let response = await mcpClient.processQuery(messages)
    messages.push({role: "assistant", content: response});
    console.log("output:", response);
  }
  face.close();
  await mcpClient.disconect();
}

await main();
  • 输入输出信息如下:
====================
欢迎使用AI聊天机器人,你可以问我当前时间相关信息,输入exit或者quit退出,输入clear清空历史记录
====================
input: 你好
output: 你好!有什么我能帮助你的吗?
input: 你叫啥?
output: 您好,我是通义千问,是阿里云开发的一款人工智能助手。有什么我可以帮助您的吗?
input: 现在几点了?
output: 根据您提供的信息,现在是北京时间2025年6月5日18点16分。
input: exit
outptu: 即将退出
  • 可以看到,AI能够在需要的时候,正确调用获取当前时间tool。不需要的时候,也可以进入闲聊模式。
  • 那么,动动手吧,试试上面的代码,顺便把上节的playwright操作浏览器这个功能,也用代码实现一下。

版权属于:tlntin
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
更新于: 2025年06月05日 18:19


46 文章数
6 分类数
47 页面数
已在风雨中度过 2年27天9小时36分
目录
来自 《(2)使用代码调用MCP工具(TS 篇)》
暗黑模式
暗黑模式
返回顶部
暗黑模式
暗黑模式
返回顶部