保姆级MCP开发上手指南

超详细MCP开发指南,有手就会,开发属于自己的MCP吧。

什么是MCP

MCP官方文档modelcontextprotocol.io/quickstart

用户视角 :MCP与传统的Chat对话服务系统不同,它可以直接处理、编辑和分析用户本地的文件,就像拥有一位能够亲自处理本地文件的"AI PC私人助理"!

技术视角 :MCP(Model Context Protocol)本质上是一个允许AI模型安全访问外部工具和数据的协议。然而,它的意义远不止于此------它是连接AI能力与现实世界的桥梁。通过MCP,AI助手可以"看到 "文件系统、"操作 "数据库以及"使用 "各种工具,这极大地扩展了AI的实际应用范围。在稳定性方面,MCP拥有官方服务和社区贡献,已经建立了标准协议、软件开发工具包(SDK)和安全框架,同时也正在形成新的软件范式。举个例子,当您想将一些指定的后缀文件放入到一个新的文件夹时,只需要输入给MCP一行指令,便可以直接帮您省略终端输入命令行的流程

一、环境准备

step1: 检查环境

目前mcp官方提供了NodeJs 和 Python 两个语言版本的开发SDK,配套工具都很成熟。下面以Node举例。

js 复制代码
# 检查环境,node版本需要>=16,建议>=20
node --version

# 如果没有node,推荐安装nvm,进行node版本管理。
# 安装 nvm (Node 版本管理器)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash

Step 2:创建项目存在以下三种方法

方法一: 使用create-typescript-server 工具快速初始化一个,快速记笔记的小工具(是一个通过mcp-server 链接 local data sources 的例子)

js 复制代码
# Create a new server in the directory `my-server`
npx @modelcontextprotocol/create-server my-server

# With options
npx @modelcontextprotocol/create-server my-server --name "My MCP Server" --description "A custom MCP server"

推荐使用这个方法。

方法二: 参考quickstart文档。 以下是基于node实现一个图片读取的MCP为例:

1、需要先创建文件:

js 复制代码
// 创建项目的文件夹
mkdir image-processor
cd image-processor

// 初始化项目(执行完后,项目中会初始化相关的文件)
npm init -y

// 创建开发文件(MCP的逻辑在这个文件编写)
mkdir src
touch src/index.ts

2、 配置 package.json 开发MCP时需要借助于一些外部依赖库的能力进行文件读写,需要在配置​package.json后,​npm install安装。

json 复制代码
{
  "name": "@block/image-processor",
  "version": "1.0.0",
  "description": "A MCP server for image",
  "type": "module",
  "bin": {
    "image-processor": "./build/index.js"
  },
  "scripts": {
    "build": "tsc && chmod +x build/index.js",
    "prepublishOnly": "npm run build"
  },
  "files": [
    "build"
  ],
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.4",
    "axios": "^1.7.9",
    "form-data": "^4.0.1",
    "fs": "^0.0.1-security",
    "os": "^0.1.2",
    "path": "^0.12.7",
    "zod": "^3.24.1",
    "zod-to-json-schema": "^3.24.1"
  },
  "devDependencies": {
    "@types/node": "^22.10.2",
    "typescript": "^5.7.2"
  },
  "publishConfig": {
    "access": "public"
  },
  "keywords": [
    "mcp",
    "image"
  ]
}

如果是基于​typescript实现,还需配置​tsconfig.json

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"]
  }

方法三: 从官方的server汇总仓库里fork一个你感兴趣的server,然后在上面二开

二、 开发MCP

MCP的逻辑主要在​src/index.ts中实现。以图片阅读MCP为例,编写代码如下,代码逻辑在此不赘述。 关于你想尝试实现的任何功能,都可以利用AI coding完成

js 复制代码
#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { zodToJsonSchema } from "zod-to-json-schema";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ToolSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import path from "path";
import fs from "fs/promises";
import os from "os";

const ToolInputSchema = ToolSchema.shape.inputSchema;
type ToolInput = z.infer<typeof ToolInputSchema>;

const args = process.argv.slice(2);
if (args.length === 0) {
  console.error(
    "Usage: mcp-server-filesystem <allowed-directory> [additional-directories...]"
  );
  process.exit(1);
}

// Normalize all paths consistently
function normalizePath(p: string): string {
  return path.normalize(p);
}

function expandHome(filepath: string): string {
  if (filepath.startsWith("~/") || filepath === "~") {
    return path.join(os.homedir(), filepath.slice(1));
  }
  return filepath;
}

// Store allowed directories in normalized form
const allowedDirectories = args.map((dir) =>
  normalizePath(path.resolve(expandHome(dir)))
);

// Validate that all directories exist and are accessible
await Promise.all(
  args.map(async (dir) => {
    try {
      const stats = await fs.stat(dir);
      if (!stats.isDirectory()) {
        console.error(`Error: ${dir} is not a directory`);
        process.exit(1);
      }
    } catch (error) {
      console.error(`Error accessing directory ${dir}:`, error);
      process.exit(1);
    }
  })
);

/** 读取图片的工具 */
const ReadImageArgsSchema = z.object({
  path: z.string(),
});

// Create server instance
const server = new Server(
  {
    name: "image-processor",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "read-image",
        description: "通过图片路径读取图片",
        inputSchema: zodToJsonSchema(ReadImageArgsSchema) as ToolInput,
      },
    ],
  };
});

// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === "read-image") {
      const parsed = ReadImageArgsSchema.safeParse(args);
      if (!parsed.success) {
        throw new Error(`Invalid arguments for read_file: ${parsed.error}`);
      }
      // 获取图片路径
      const imagePath = parsed.data.path;
      // 读取图片文件为 Buffer
      const imageBuffer = await fs.readFile(imagePath);
      // 转换为 base64
      const base64String = imageBuffer.toString("base64");
      // 获取文件扩展名并确定 MIME 类型
      const ext = path.extname(imagePath).toLowerCase();
      const mimeType =
        {
          ".png": "image/png",
          ".jpg": "image/jpeg",
          ".jpeg": "image/jpeg",
          ".gif": "image/gif",
          ".webp": "image/webp",
        }[ext] || "application/octet-stream";

      return {
        content: [
          {
            type: "image",
            data: base64String,
            mimeType: mimeType,
          },
        ],
      };
    } else {
      throw new Error(`Unknown tool: ${name}`);
    }
  } catch (error) {
    console.error("Error in request handler:", error);

    if (error instanceof z.ZodError) {
      throw new Error(
        `Invalid arguments: ${error.errors
          .map((e) => `${e.path.join(".")}: ${e.message}`)
          .join(", ")}`
      );
    }
    throw new Error(`Failed to fetch image`);
  }
});

// Start the server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Image Processor Server running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});

三、本地验证

3.1 本地打包构建

本地开发完成后,还需要打包构建,才能接入大模型客户端使用(比如Cursor等) 由于已经在​package.json配置了打包构建的相关信息,执行​npm run build,可以在src的同级目录发现一个新的 build 文件夹,内部包含一个index.js文件。

3.2 验证

方式一: 直接将本地构建的产物接入大模型客户端。在客户端配置文件中增加本地已经构建的MCP入口文件,看是否能正常使用该MCP。(如果仅需要自己本地使用,那么到这一步就可以了,不需要发布流程)

js 复制代码
// args 1为我本地项目的打包构建后的地址,args 2为用户给这个MCP提供的参数,代表提供权限的路径,使用方式与filesystem MCP一致
"image-processor": {
	"command": "node",
	"args": [
		"/Users/ruixingshi/project/image-processor/build/index.js",
		"/Users/ruixingshi/Documents"
	]
}

方式二: 使用​@modelcontextprotocol/inspector 连接本地开发好的MCP,在本地Server中看是否可以正常读取MCP的tool。在控制台执行命令:

js 复制代码
/* 全局安装 @modelcontextprotocol/inspector */
npm install -g @modelcontextprotocol/inspector 

/* 运行: */
npx @modelcontextprotocol/inspector node path/to/server/index.js args...


// 解释: path/to/server/index.js 是你的mcp工程在你终端的相对路径

// args 是需要传入的参数: 例如你写的MCP需要创建文档到你的电脑文档层 就是: /Users/xxx/Documents。 需要改为你自己电脑的路径


// 举例
npx @modelcontextprotocol/inspector /Users/xxx/project/build/index.js /Users/xxx/Documents

运行成功后会启动一个5173端口的界面,启动的本地页面http://localhost:5173

点击Connect之后 Run Tool,就可以进行调试了。

方式三: 在Claude桌面端中调试 目前Claude 注册需要国外手机号验证码,本文作者并未验证,后续更新。

四、发布

可以将本地代码发布为npm包,允许其他用户在大模型客户端上通过配置直接接入,无需手动下载任何代码。

js 复制代码
​npm publish

效果:

写一个记笔记的MCP,效果如下:

思考:

MCP这种以大模型工具为中心的交互范式,未来是有可能颠覆之前大家在各个web页面使用各种工具的范式的,我们需要积极拥抱和探索。

从前端的视角简单类比下:

Claude Desktop < ---------------> 浏览器

MCP server <---------------> 各种站点 & 工具(devtools\mep 等等)

本地数据/远端接口 <---------------> 后端接口

相关推荐
技术程序猿华锋13 分钟前
Void:免费且隐私友好的 AI 编码利器,挑战 Cursor 地位?
c++·人工智能·mfc
奔跑吧邓邓子1 小时前
DeepSeek 赋能自动驾驶仿真测试:解锁高效精准新范式
人工智能·机器学习·自动驾驶·仿真测试·deepseek
深兰科技1 小时前
深兰科技陈海波率队考察南京,加速AI医诊大模型区域落地应用
人工智能·深兰科技·陈海波
Fuliy962 小时前
【自然语言处理】——基于与训练模型的方法【复习篇1】
人工智能·自然语言处理
项目管理打工人2 小时前
高端装备制造企业如何选择适配的项目管理系统提升项目执行效率?附选型案例
大数据·人工智能·驱动开发·科技·硬件工程·团队开发·制造
江苏泊苏系统集成有限公司2 小时前
集成电路制造设备防震基座选型指南:为稳定护航-江苏泊苏系统集成有限公司
人工智能·深度学习·目标检测·机器学习·制造·材料工程·精益工程
吹风看太阳2 小时前
机器学习03-色彩空间:RGB、HSV、HLS
人工智能·机器学习
Ronin-Lotus3 小时前
深度学习篇---Pytorch框架下OC-SORT实现
人工智能·pytorch·python·深度学习·oc-sort
雾迟sec3 小时前
TensorFlow 的基本概念和使用场景
人工智能·python·tensorflow
Blossom.1183 小时前
人工智能在智能健康监测中的创新应用与未来趋势
java·人工智能·深度学习·机器学习·语音识别