什么是模型上下文协议(MCP)
· MCP (Model Context Protocol) 是 OpenAI 推出的一个 协议,用来让大模型和外部系统(数据库、API、本地文件、工具链等)打通。
· MCP 最早由Antrhopic 于2024 年底提出,至2025 年初,OpenAI、Google 也加入支援MCP 协定。
· 同时 MCP(模型上下文协议)是一个用于连接 AI 应用与外部系统的开源标准。
· 它把「模型」和「工具」之间的交互规范化,像一个“插件协议”。
· MCP 工具就是在这个协议下挂接的外部能力

本文Demo GitHub - pmhw/McpDemo: Model Context Protocol 的一个简单示例代码
MCP Tools 的作用
- 扩展模型能力
- 比如大模型本身不会直接操作 MySQL,但是你可以通过 MCP 工具,把 MySQL 封装成一个“工具”,模型就能发 MCP 请求去查数据。
- 标准化交互
- MCP 工具有统一的输入输出格式,方便模型调用,不需要每次都为不同工具写一堆 glue code。
- 安全可控
- 工具都跑在 MCP 服务里,调用权限、范围可控,避免模型随意直接访问敏感系统。
- 开发和复用
编写 MCP
- 启动 MCP Inspector ( MCP 检查器 )
https://modelcontextprotocol.io/legacy/tools/inspector
有node 环境的 直接运行
npx @modelcontextprotocol/inspecto
访问启动的URL

访问后界面

- 所需依赖
modelcontextprotocol: Model Context Protocol (MCP) 是一个 开放标准,用来让 AI 模型和外部工具/数据源 互相通信。
3.编写代码
导入 MCP SDK 相关模块
// 导入 MCP SDK 相关模块
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
创建 MCP 服务器实例
/**
* 创建 MCP 服务器实例
*
* @param {Object} serverInfo - 服务器信息
* @param {string} serverInfo.name - 服务器名称
* @param {string} serverInfo.version - 服务器版本
* @param {Object} capabilities - 服务器能力配置
* @param {Object} capabilities.tools - 工具能力配置
*/
const server = new Server(
{
name: 'lottery-tool', // 服务器名称,用于标识
version: '1.0.0', // 服务器版本号
},
{
capabilities: {
tools: {}, // 声明支持工具功能
},
}
);
定义工具列表
/**
* 定义工具列表
*
* 每个工具包含:
* - name: 工具名称
* - description: 工具描述
* - inputSchema: 输入参数模式(JSON Schema)
*/
const tools = [
{
name: 'draw_lottery',
description: '从给定的选项列表中随机抽取一个或多个结果',
inputSchema: {
type: 'object',
properties: {
options: {
type: 'array',
items: { type: 'string' },
description: '抽签选项列表',
},
count: {
type: 'number',
description: '抽取数量,默认为1',
default: 1,
},
allow_duplicate: {
type: 'boolean',
description: '是否允许重复抽取,默认为false',
default: false,
},
},
required: ['options'], // 必需参数
},
},
{
name: 'roll_dice',
description: '投掷骰子,支持自定义面数和数量',
inputSchema: {
type: 'object',
properties: {
sides: {
type: 'number',
description: '骰子面数,默认为6',
default: 6,
},
count: {
type: 'number',
description: '骰子数量,默认为1',
default: 1,
},
},
},
},
{
name: 'flip_coin',
description: '抛硬币,返回正面或反面',
inputSchema: {
type: 'object',
properties: {
count: {
type: 'number',
description: '抛硬币次数,默认为1',
default: 1,
},
},
},
},
];
处理工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools, // 返回工具列表
};
});
处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
// 根据工具名称执行相应的功能
switch (name) {
case 'draw_lottery': {
// 抽签工具:从选项列表中随机抽取结果
const { options, count = 1, allow_duplicate = false } = args;
// 参数验证
if (!Array.isArray(options) || options.length === 0) {
throw new Error('选项列表不能为空');
}
if (count > options.length && !allow_duplicate) {
throw new Error('抽取数量不能超过选项数量(不允许重复时)');
}
// 执行抽签逻辑
const results = [];
const availableOptions = [...options]; // 创建选项副本
for (let i = 0; i < count; i++) {
// 随机选择索引
const randomIndex = Math.floor(Math.random() * availableOptions.length);
const selected = availableOptions[randomIndex];
results.push(selected);
// 如果不允许重复,从可用选项中移除已选择的
if (!allow_duplicate) {
availableOptions.splice(randomIndex, 1);
}
}
// 返回格式化的结果
return {
content: [
{
type: 'text',
text: `🎲 抽签结果:\n${results.map((result, index) => `${index + 1}. ${result}`).join('\n')}`,
},
],
};
}
case 'roll_dice': {
// 投骰子工具:模拟投掷骰子
const { sides = 6, count = 1 } = args;
// 参数验证
if (sides < 2) {
throw new Error('骰子面数至少为2');
}
if (count < 1) {
throw new Error('骰子数量至少为1');
}
// 执行投骰子逻辑
const results = [];
let total = 0;
for (let i = 0; i < count; i++) {
// 生成 1 到 sides 之间的随机数
const roll = Math.floor(Math.random() * sides) + 1;
results.push(roll);
total += roll;
}
// 根据骰子数量格式化输出
const resultText = count === 1
? `🎲 投掷结果:${results[0]}`
: `🎲 投掷结果:${results.join(', ')}\n📊 总计:${total}`;
return {
content: [
{
type: 'text',
text: resultText,
},
],
};
}
case 'flip_coin': {
// 抛硬币工具:模拟抛硬币
const { count = 1 } = args;
// 参数验证
if (count < 1) {
throw new Error('抛硬币次数至少为1');
}
// 执行抛硬币逻辑
const results = [];
let heads = 0; // 正面次数
let tails = 0; // 反面次数
for (let i = 0; i < count; i++) {
// 50% 概率生成正面或反面
const result = Math.random() < 0.5 ? '正面' : '反面';
results.push(result);
if (result === '正面') heads++;
else tails++;
}
// 根据抛硬币次数格式化输出
const resultText = count === 1
? `🪙 抛硬币结果:${results[0]}`
: `🪙 抛硬币结果:${results.join(', ')}\n📊 统计:正面 ${heads} 次,反面 ${tails} 次`;
return {
content: [
{
type: 'text',
text: resultText,
},
],
};
}
default:
// 未知工具名称
throw new Error(`未知工具:${name}`);
}
} catch (error) {
// 错误处理:返回错误信息
return {
content: [
{
type: 'text',
text: `❌ 错误:${error.message}`,
},
],
isError: true,
};
}
});
启动服务器
/**
* 启动服务器
*
* 使用标准输入输出传输协议启动 MCP 服务器
* 这种方式适合与 AI 客户端(如 Claude Desktop)集成
*/
async function main() {
try {
// 创建标准输入输出传输实例
const transport = new StdioServerTransport();
// 连接服务器到传输层
await server.connect(transport);
// 输出启动信息(使用 stderr 避免干扰 MCP 协议)
console.error('🎲 抽签工具 MCP 服务器已启动');
console.error('📡 传输方式:标准输入输出 (stdio)');
console.error('🔧 可用工具:draw_lottery, roll_dice, flip_coin');
} catch (error) {
console.error('❌ 服务器启动失败:', error);
process.exit(1);
}
}
// 启动服务器并处理错误
main().catch((error) => {
console.error('❌ 服务器运行错误:', error);
process.exit(1);
});
调试

我的代码放置示例 src/server.js
需要对mcp 调试工具进行如下配置
Transport Type: stdio
URL: (留空)
Command: node
Args: src/server.js
Working Directory: D:\代码存储\McpDemo

继续配置 Working Directory: D:\代码存储\McpDemo



点击Connect 即可开始


至此您的第一个mcp 插件开发完成了
如何在AI 中调用呢
以cursor 示例
如下图设置中配置以下参数 根据您代码存储位置自行调整
{
"mcpServers": {
"lottery-tool": {
"command": "node",
"args": ["D:\\代码存储\\McpDemo\\src\\server.js"],
"cwd": "D:\\代码存储\\McpDemo"
}
}
}

补充
Demo:https://github.com/pmhw/McpDemo
MCP英文文档:https://modelcontextprotocol.io/docs/getting-started/intro