引言
青山不改,绿水长流。朋友们,上一篇《编写第一个MCP Server之Hello world》我们说到如何从0 开始借助SDK实现一个MCP Server的demo,结尾我们说要再搞一个Client 来配对。这不,今天小马就来啦。
本文延续上一篇的内容接着说MCP Client,基本的教程就是学习官方的这里和git的案例,但是小马阅读了之后觉得相对于demo还是有点复杂的,所以小马在实际操作中简化了一些干扰代码,直指Hello world上手的极简目标。
我们还是延续上次使用的环境,继续使用node环境来完成今天的demo。
一、检查环境并初始化项目
这一块与上一篇的类似,就不赘述。
node --version
npm --version
为了本次演示尽量清晰,我们计划重新构建项目来执行(如图)。
执行创建并设置我们的项目:
# Window 的命令如下
# Create a new directory for our project
md echoclient
cd echoclient
# Initialize a new npm project
npm init -y
# Install dependencies
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript
# Create our files
md src
new-item src\index.ts
当然我们还是同样会遇到上一次所遇到的问题,按照上一次解决方案解决之即可。
同样的,我们需要更新 package.json 文件以添加 type: “module” 和构建脚本:
{
"name": "echoclient",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"build": "tsc",
"prepare": "npm run build",
"dev": "tsc --watch",
"start": "node build/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "小马过河R",
"license": "ISC",
"description": "",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.1",
"zod": "^3.24.4"
},
"devDependencies": {
"@types/node": "^22.15.17",
"typescript": "^5.8.3"
},
"type": "module",
"bin": {
"echo": "./build/index.js"
},
"files": [
"build"
]
}
在项目的根目录中创建一个 tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
二、回顾MCP协议基础架构和通信方式
我们再来简单回顾一下MCP协议基础架构和通信方式。
MCP 采用 客户端-服务器模型,包含三个核心组件:
MCP 主机:用户直接交互的 AI 应用界面(如 IDE 插件);
MCP 客户端:管理主机与服务器间的连接中介;
MCP 服务器:提供具体功能的外部程序(工具/数据源);
MCP Server 的调用协议和通信方式可归纳如下:
1、调用协议规范
基于 JSON-RPC 2.0 标准
所有请求响应均采用 JSON-RPC 2.0 格式,包含以下核心字段:
{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/list",
"params": {}
}
method:指定调用的服务方法名(如资源查询、工具调用等)
params:携带结构化参数(支持对象或数组格式)
id:用于请求与响应的唯一标识匹配
支持同步/异步调用模式
同步请求直接返回 result 字段的响应结果
异步场景通过 SSE 长连接推送处理结果
2、通信方式实现
MCP Server 支持两种底层通信机制:
Stdio(标准输入输出)
适用场景:本地进程间通信
实现方式:通过管道传输 JSON-RPC 消息
HTTP + SSE 混合模式
长连接通道:通过 GET /sse 接口建立 SSE 连接,服务端持续推送异步事件流;
请求通道:通过 POST /message 接口发送请求和接收即时响应;
比如像如下这样:
技术优势:
连接复用减少握手开销;
支持实时数据推送(如 AI 生成中间结果流式返回);
天然适配事件驱动型交互场景;
三、构建MCP客户端
现在让我们开始构建您的客户端Client。
在src/index.ts文件导入包并设置实例。
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function main() {
// 创建标准输入输出传输层实例
// 配置要启动的子进程(这里启动Node.js运行指定脚本)
const transport = new StdioClientTransport({
command: "node",
args: ["d:/web2/echo/build/index.js"]//上一篇中实现的MCP Server
});
// 创建客户端实例,配置客户端元信息
const client = new Client(
{
name: "example-client",// 客户端名称(用于标识)
version: "1.0.0"// 客户端版本号
}
);
// 使用配置的传输层连接客户端
await client.connect(transport);
try {
// List prompts
//const prompts = await client.listPrompts();
// Get a prompt
/*const prompt = await client.getPrompt({
name: "example-prompt",
arguments: {
arg1: "value"
*/
// List resources
//const resources = await client.listResources();
// Read a resource
/*const resource = await client.readResource({
uri: "file:///example.txt"
});*/
// Call a tool
const result = await client.callTool({
name: "echo",// 要调用的工具名称
arguments: {// 传递给工具的参数
message: "xiaoma"// 示例参数(根据工具定义需要修改)
}
});
console.log("Tool response:", result);
} finally {
await client.close();
}
}
main().catch(console.error);
现在我们对关键代码进行简单的说明。可以看到,小马已经在关键代码加了注释说明了。且我们就以工具调用为主要功能来演示demo,临时注释掉了与其无关的resources、prompts相关代码。
为了直观,我们Client调用的MCP Server就直接使用上一篇中我们搭建的MCP Server echo。
最后,我们确保运行 npm run build
来构建您的Client并看到运行成功。
说明构建成功啦!
四、验证效果
需要验证我们编写的MCP Client是否成功,显然比验证MCP Server看起来简单多了。我们只需要将客户端运行命令node build/index.js
来run起来,直接能看到效果啦。
再回头看一样我们的代码:
嗯,这不就相当得哇塞,事情变得越来越有趣了不是么!!
至此,第一个MCP Client之Hello world的简易demo也结束了。下一篇的计划是尝试AI Agent自动调用 MCP的结合哈,拜了个拜,感谢品阅。
参考资料:
https://modelcontextprotocol.io/quickstart/client#node
https://github.com/modelcontextprotocol/typescript-sdk