什么是MCP?
首先我们先明白,在没有MCP之前,我们想结合LLM和自己的知识进行回答,一般是通过 FunctionCall 或者代码层 if else,亦或者是插件、LangChain等。
在这里不是说这些解决方案不够好,而是相比 MCP 他们越来越定制化且不可拆分。这样一来、其他的 LLM客户端想调取你的能力就非常难。
所以 MCP 的出现是将能力进行模块化,给模型调用。
MCP 是 C/S 架构。可以理解为 Client 端会结合AI 应用决定和调取哪些 MCP Server。
此篇我们只开发 Server 服务。
MCP Server 和 Client 的通信可以是,本地Stdio,Http,也就是说 MCP Server可以是本地的、也可以是远程的。
通过 JSON 形式(JSON-RPC)进行数据传输约定。
从最简单的 Demo 开始。
让Cursor 列出我桌面的文件夹
import { readdir, stat } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// 创建 MCP 服务器实例
// name 和 version 用于标识服务器
const server = new McpServer({
name: "desktop_folders",
version: "1.0.0"
});
/**
* 注册工具:list_desktop_folders
*
* server.tool() 方法用于注册一个可被 AI 调用的工具
* 参数说明:
* - 第一个参数:工具名称(AI 通过这个名称调用工具)
* - 第二个参数:工具的参数定义(这里为空对象,表示不需要参数)
* - 第三个参数:工具的执行函数(异步函数,返回工具执行结果)
*/
server.tool(
"list_desktop_folders",
{}, // 工具参数定义(空对象表示无参数)
async () => {
try {
// 获取桌面路径(跨平台兼容)
const desktopPath = join(homedir(), 'Desktop');
// 读取桌面目录下的所有文件和文件夹
const items = await readdir(desktopPath);
// 并行检查每个项目是否为文件夹(提高性能)
const folderChecks = await Promise.all(
items.map(async (item) => {
const itemPath = join(desktopPath, item);
const stats = await stat(itemPath);
return stats.isDirectory() ? item : null;
})
);
// 过滤出文件夹名称(移除 null 值)
const folders = folderChecks.filter(Boolean);
// 格式化返回结果
// MCP 工具必须返回特定格式:content 数组包含文本内容
return {
content: [{
type: "text",
text: folders.length > 0
? `桌面上的文件夹:\n${folders.join('\n')}\n\n共 ${folders.length} 个文件夹`
: '桌面上没有文件夹'
}]
};
} catch (error) {
// 错误处理:返回错误信息并标记为错误
return {
content: [{
type: "text",
text: `错误:${error.message}`
}],
isError: true
};
}
}
);
/**
* 启动服务器
*
* StdioServerTransport 使用标准输入输出进行通信
* 这是 MCP 服务器最常见的通信方式
*/
const transport = new StdioServerTransport();
await server.connect(transport);
延展阅读
https://modelcontextprotocol.io/docs/develop/build-server