网站Logo 简单生活

Node.js MCP项目完整教程:从创建到发布使用

zb2947244682
1
2025-08-20

第一步:项目初始化

1. 创建项目目录

mkdir my-mcp-server
cd my-mcp-server
npm init -y

2. 安装依赖

# 安装MCP SDK
npm install @modelcontextprotocol/sdk

# 安装开发依赖
npm install --save-dev typescript @types/node ts-node nodemon

3. 创建TypeScript配置

创建 tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

第二步:编写MCP服务器代码

1. 创建主服务器文件

创建 src/index.ts:

#!/usr/bin/env node

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  Tool,
} from "@modelcontextprotocol/sdk/types.js";

class MyMCPServer {
  private server: Server;

  constructor() {
    this.server = new Server(
      {
        name: "my-mcp-server",
        version: "1.0.0",
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    this.setupHandlers();
  }

  private setupHandlers() {
    // 列出可用工具
    this.server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "echo",
            description: "Echo back the input text",
            inputSchema: {
              type: "object",
              properties: {
                text: {
                  type: "string",
                  description: "Text to echo back",
                },
              },
              required: ["text"],
            },
          },
          {
            name: "get_time",
            description: "Get current time",
            inputSchema: {
              type: "object",
              properties: {},
            },
          },
          {
            name: "calculate",
            description: "Perform basic mathematical calculations",
            inputSchema: {
              type: "object",
              properties: {
                expression: {
                  type: "string",
                  description: "Mathematical expression to evaluate (e.g., '2 + 3 * 4')",
                },
              },
              required: ["expression"],
            },
          },
        ],
      };
    });

    // 处理工具调用
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      switch (name) {
        case "echo":
          return {
            content: [
              {
                type: "text",
                text: `Echo: ${args.text}`,
              },
            ],
          };

        case "get_time":
          return {
            content: [
              {
                type: "text",
                text: `Current time: ${new Date().toISOString()}`,
              },
            ],
          };

        case "calculate":
          try {
            // 简单的数学表达式计算(仅支持基本运算)
            const result = this.safeEval(args.expression);
            return {
              content: [
                {
                  type: "text",
                  text: `${args.expression} = ${result}`,
                },
              ],
            };
          } catch (error) {
            return {
              content: [
                {
                  type: "text",
                  text: `Error calculating "${args.expression}": ${error.message}`,
                },
              ],
              isError: true,
            };
          }

        default:
          throw new Error(`Unknown tool: ${name}`);
      }
    });
  }

  private safeEval(expression: string): number {
    // 简单的安全数学表达式评估
    const sanitized = expression.replace(/[^0-9+\-*/().\s]/g, '');
    if (sanitized !== expression) {
      throw new Error('Invalid characters in expression');
    }
    return Function('"use strict"; return (' + sanitized + ')')();
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("My MCP Server running on stdio");
  }
}

const server = new MyMCPServer();
server.run().catch((error) => {
  console.error("Server error:", error);
  process.exit(1);
});

第三步:配置构建脚本

1. 更新 package.json

{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "description": "A sample MCP server with basic tools",
  "main": "dist/index.js",
  "bin": {
    "my-mcp-server": "./dist/index.js"
  },
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "ts-node src/index.ts",
    "watch": "nodemon --exec ts-node src/index.ts",
    "prepublishOnly": "npm run build"
  },
  "keywords": ["mcp", "model-context-protocol", "ai", "tools"],
  "author": "Your Name <your.email@example.com>",
  "license": "MIT",
  "files": [
    "dist/**/*",
    "README.md",
    "package.json"
  ],
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.4.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "@types/node": "^20.0.0",
    "ts-node": "^10.0.0",
    "nodemon": "^3.0.0"
  }
}

2. 创建 README.md

# My MCP Server

A sample Model Context Protocol (MCP) server that provides basic utility tools.

## Features

- **echo**: Echo back input text
- **get_time**: Get current timestamp
- **calculate**: Perform basic mathematical calculations

## Installation

```bash
npm install -g my-mcp-server

Usage with Cursor

Add to your Cursor MCP configuration:

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "npx",
      "args": ["my-mcp-server"]
    }
  }
}

Development

# Install dependencies
npm install

# Run in development mode
npm run dev

# Build for production
npm run build

# Start built version
npm start

License

MIT


## 第四步:本地测试

### 1. 构建项目
```bash
npm run build

2. 测试运行

# 开发模式测试
npm run dev

# 或者测试构建后的版本
npm start

第五步:发布到npm

1. 注册npm账户

如果还没有npm账户:

npm adduser

如果已有账户:

npm login

2. 发布包

# 确保版本号正确
npm version patch  # 或 minor, major

# 发布
npm publish

3. 验证发布

# 检查包是否发布成功
npm view my-mcp-server

第六步:配置到Cursor

1. 找到Cursor配置文件

  • macOS: ~/Library/Application Support/Cursor/User/globalStorage/rooveterinaryinc.cursor-mcp/settings.json
  • Windows: %APPDATA%\Cursor\User\globalStorage\rooveterinaryinc.cursor-mcp\settings.json
  • Linux: ~/.config/Cursor/User/globalStorage/rooveterinaryinc.cursor-mcp\settings.json

2. 添加MCP服务器配置

在配置文件中添加:

{
  "mcpServers": {
    "my-mcp-server": {
      "command": "npx",
      "args": ["my-mcp-server"]
    }
  }
}

3. 重启Cursor

重启Cursor客户端以加载新的MCP服务器。

第七步:使用和验证

1. 在Cursor中验证

  • 打开Cursor
  • 在聊天中,AI应该能够使用您的自定义工具
  • 尝试询问需要使用您工具的问题,如:"帮我计算 15 * 24 + 8"

2. 调试技巧

如果遇到问题:

# 检查MCP服务器是否正常运行
npx my-mcp-server

# 查看Cursor的开发者工具中的错误信息
# Cursor菜单 -> View -> Developer Tools

高级功能扩展

1. 添加更多工具

setupHandlers() 方法中添加新的工具定义和处理逻辑。

2. 添加资源支持

// 在server capabilities中添加
capabilities: {
  tools: {},
  resources: {},
}

// 添加资源处理器
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "file://example.txt",
        name: "Example file",
        description: "An example resource",
        mimeType: "text/plain",
      },
    ],
  };
});

3. 错误处理和日志

// 添加更好的错误处理和日志
import { createLogger } from './logger';

const logger = createLogger('my-mcp-server');

// 在错误处理中使用
catch (error) {
  logger.error('Tool execution failed', { tool: name, error: error.message });
  throw error;
}

注意事项

  1. 安全性: 如果您的工具执行系统命令或访问文件,请确保进行适当的输入验证
  2. 性能: 对于耗时操作,考虑添加超时和进度反馈
  3. 版本管理: 使用语义化版本号管理您的包
  4. 文档: 保持README和代码注释的更新

现在您已经有了一个完整的MCP服务器,可以扩展更多功能来满足您的特定需求!

动物装饰