mcp-auditor

MCP Auditor

npm version npm downloads License: MIT

English 中文

一个 TypeScript 工具,用于审计 MCP (Model Context Protocol) 服务器的所有交互。通过透明代理方式拦截并记录所有 MCP 服务器的输入/输出操作,生成完整的审计日志,帮助开发者调试、监控和合规审查 MCP 应用。

功能特性

  1. 包装 MCP 服务器 - 连接到现有的 MCP 服务器作为客户端
  2. 暴露工具 - 向外部暴露被包装服务器的所有工具
  3. 暴露资源 - 向外部暴露被包装服务器的所有资源
  4. 暴露提示词 - 向外部暴露被包装服务器的所有提示词(Prompts)
  5. 代理功能 - 透明地转发所有 MCP 操作(工具、资源、提示词)
  6. 全面日志记录 - 记录所有与被包装服务器的输入/输出交互到指定日志文件
  7. Stdio 传输 - 作为独立的 MCP 服务器运行,支持 stdio 通信

使用模式

本工具支持两种使用模式:

模式 1: 作为库使用(编程方式)

在你的 TypeScript/Node.js 代码中使用 MCPWrapper 类来包装和调用 MCP 服务器。

模式 2: 作为 MCP 服务器运行(独立服务器) ⭐推荐

作为独立的 MCP 服务器运行,可以被 Claude Desktop 或其他 MCP 客户端连接。

👉 服务器模式详细文档: 查看 SERVER.md

项目结构

mcp-auditor/
├── src/
│   ├── core/              # 核心包装功能
│   │   ├── wrapper.ts     # MCPWrapper 核心类
│   │   ├── logger.ts      # 日志记录器
│   │   └── types.ts       # TypeScript 类型定义
│   ├── server/            # 服务器专用代码
│   │   ├── server.ts      # MCP 服务器实现 ⭐
│   │   └── config.ts      # 服务器配置加载
│   └── index.ts           # 主入口文件
├── examples/
│   ├── library/           # 库使用示例
│   │   ├── basic-usage.ts    # 基础使用示例
│   │   └── test-wrapper.ts   # 测试脚本
│   └── server/            # 服务器示例
│       ├── server-wrapper.ts # 代理服务器示例
│       └── config-example.ts # 配置示例
├── docs/                  # 文档
│   ├── README.md          # 英文文档
│   ├── README.zh.md       # 中文文档
│   └── SERVER.md          # 服务器模式文档 ⭐
├── logs/                  # 日志文件目录
├── dist/                  # 编译输出
├── config.example.json    # 服务器配置示例
└── package.json

安装

作为库使用(推荐):

npm install mcp-auditor

全局 CLI 安装:

npm install -g mcp-auditor

从源码安装:

git clone https://github.com/algovate/mcp-auditor.git
cd mcp-auditor
npm install
npm run build

快速开始

🚀 方式 1: 作为 MCP 服务器运行(推荐)

# 1. 安装依赖并构建
npm install
npm run build

# 2. 配置环境变量
export MCP_WRAPPED_SERVER_COMMAND=npx
export MCP_WRAPPED_SERVER_ARGS="-y,@modelcontextprotocol/server-filesystem,/tmp"
export MCP_LOG_FILE=./logs/mcp-server.log

# 3. 启动服务器
npm start

在 Claude Desktop 中使用

在 Claude Desktop 配置文件中添加 (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "wrapped-filesystem": {
      "command": "node",
      "args": ["/path/to/mcp-auditor/dist/server/server.js"],
      "env": {
        "MCP_WRAPPED_SERVER_COMMAND": "npx",
        "MCP_WRAPPED_SERVER_ARGS": "-y,@modelcontextprotocol/server-filesystem,/Users/yourname/Documents",
        "MCP_LOG_FILE": "/Users/yourname/logs/mcp-wrapper.log"
      }
    }
  }
}

📖 完整服务器文档: SERVER.md

📚 方式 2: 作为库使用(编程方式)

import { MCPWrapper } from 'mcp-auditor';

async function main() {
  // 创建审计器实例
  const wrapper = new MCPWrapper({
    serverCommand: 'npx',
    serverArgs: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
    logFilePath: './logs/mcp-wrapper.log',
    logToolCalls: true,
    logToolResults: true
  });

  // 连接到 MCP 服务器
  await wrapper.connect();

  // 获取可用工具
  const tools = wrapper.getTools();
  console.log('可用工具:', tools.map(t => t.name));

  // 调用工具
  const result = await wrapper.callTool('list_directory', {
    path: '/tmp'
  });
  console.log('结果:', result);

  // 断开连接
  await wrapper.disconnect();
}

main().catch(console.error);

2. 作为代理服务器

创建一个 MCP 服务器来包装另一个 MCP 服务器:

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { MCPWrapper } from 'mcp-auditor';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';

async function main() {
  // 创建审计器
  const wrapper = new MCPWrapper({
    serverCommand: 'npx',
    serverArgs: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
    logFilePath: './logs/proxy.log'
  });

  await wrapper.connect();

  // 创建代理服务器
  const server = new Server({
    name: 'mcp-proxy',
    version: '1.0.0'
  }, {
    capabilities: { tools: {} }
  });

  // 暴露被包装服务器的工具
  server.setRequestHandler(ListToolsRequestSchema, async () => {
    return { tools: wrapper.getTools() };
  });

  // 代理工具调用
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    return await wrapper.callTool(
      request.params.name,
      request.params.arguments as Record<string, unknown>
    );
  });

  // 启动服务器
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch(console.error);

API 文档

MCPWrapper 类

构造函数

new MCPWrapper(config: MCPWrapperConfig)

方法

连接管理: | 方法 | 描述 | 返回值 | |——|——|——–| | connect() | 连接到被包装的 MCP 服务器 | Promise<void> | | disconnect() | 断开连接并关闭日志记录器 | Promise<void> | | isConnected() | 检查是否已连接 | boolean |

工具操作: | 方法 | 描述 | 返回值 | |——|——|——–| | getTools() | 获取所有可用工具的列表 | Tool[] | | getTool(name) | 通过名称获取特定工具 | Tool \| undefined | | hasTool(name) | 检查工具是否存在 | boolean | | callTool(toolName, params?) | 调用工具 | Promise<CallToolResult> |

资源操作: | 方法 | 描述 | 返回值 | |——|——|——–| | getResources() | 获取所有可用资源的列表 | Resource[] | | getResource(uri) | 通过 URI 获取特定资源 | Resource \| undefined | | hasResource(uri) | 检查资源是否存在 | boolean | | readResource(uri) | 读取资源 | Promise<ReadResourceResult> |

提示词操作: | 方法 | 描述 | 返回值 | |——|——|——–| | getPrompts() | 获取所有可用提示词的列表 | Prompt[] | | getPromptDefinition(name) | 通过名称获取特定提示词定义 | Prompt \| undefined | | hasPrompt(name) | 检查提示词是否存在 | boolean | | getPrompt(name, args?) | 获取带参数的提示词 | Promise<GetPromptResult> |

日志记录: | 方法 | 描述 | 返回值 | |——|——|——–| | getLogger() | 获取日志记录器实例 | MCPLogger |

MCPWrapperConfig 接口

interface MCPWrapperConfig {
  // 必需参数
  serverCommand: string;        // MCP 服务器命令或可执行文件路径
  logFilePath: string;          // 日志文件路径
  
  // 可选参数
  serverArgs?: string[];        // 传递给 MCP 服务器的参数
  serverEnv?: Record<string, string>;  // 环境变量
  logToolCalls?: boolean;       // 是否记录工具调用(默认:true)
  logToolResults?: boolean;     // 是否记录工具结果(默认:true)
  logAppend?: boolean;          // 是否追加到日志文件(默认:true)
  logFormat?: 'structured' | 'jsonrpc';  // 日志格式(默认:'structured')
}

MCPLogger 类

方法

通用日志: | 方法 | 描述 | |——|——| | logEntry(entry) | 记录结构化日志条目 | | log(level, message, data?) | 记录普通消息 | | logError(error, context?) | 记录错误 | | close() | 关闭日志记录器 |

工具日志: | 方法 | 描述 | |——|——| | logToolCall(toolName, params) | 记录工具调用请求 | | logToolResult(toolName, result, error?) | 记录工具结果 |

资源日志: | 方法 | 描述 | |——|——| | logResourceListRequest() | 记录资源列表请求 | | logResourceListResponse(resources) | 记录资源列表响应 | | logResourceReadRequest(uri) | 记录资源读取请求 | | logResourceReadResponse(uri, result, error?) | 记录资源读取响应 |

提示词日志: | 方法 | 描述 | |——|——| | logPromptListRequest() | 记录提示词列表请求 | | logPromptListResponse(prompts) | 记录提示词列表响应 | | logPromptGetRequest(name, args?) | 记录提示词获取请求 | | logPromptGetResponse(name, result, error?) | 记录提示词获取响应 |

服务器日志: | 方法 | 描述 | |——|——| | logServerRequest(method, params?) | 记录服务器请求 | | logServerResponse(method, result, error?) | 记录服务器响应 |

日志格式

MCP Auditor 支持两种日志格式:

1. 结构化格式(默认)

包含时间戳、方向和元数据的详细审计日志。最适合调试和分析。

const wrapper = new MCPWrapper({
  serverCommand: 'npx',
  serverArgs: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
  logFilePath: './logs/audit.log',
  logFormat: 'structured'  // 默认
});

每个条目包含:

interface LogEntry {
  timestamp: string;              // ISO 8601 时间戳
  direction: 'input' | 'output';  // 数据流方向
  type: 'tool_call' | 'tool_result' | 'resource_list' | 'resource_read' | 'prompt_list' | 'prompt_get' | 'server_request' | 'server_response' | 'error';
  data: any;                      // 日志数据
}

日志示例

工具调用 (输入):

{
  "timestamp": "2024-01-15T10:30:00.000Z",
  "direction": "input",
  "type": "tool_call",
  "data": {
    "toolName": "read_file",
    "params": {
      "path": "/tmp/example.txt"
    }
  }
}

工具结果 (输出):

{
  "timestamp": "2024-01-15T10:30:00.123Z",
  "direction": "output",
  "type": "tool_result",
  "data": {
    "toolName": "read_file",
    "result": {
      "content": [
        {
          "type": "text",
          "text": "文件内容..."
        }
      ]
    }
  }
}

2. JSON-RPC 格式

原始 JSON-RPC 协议消息。最适合协议调试和网络分析。

const wrapper = new MCPWrapper({
  serverCommand: 'npx',
  serverArgs: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
  logFilePath: './logs/jsonrpc.log',
  logFormat: 'jsonrpc'  // 原始 JSON-RPC 消息
});

每行是一个完整的 JSON-RPC 消息:

请求:

{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}

响应:

{"jsonrpc":"2.0","id":1,"result":{"tools":["read_file","write_file"...]}}

工具调用:

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"read_file","arguments":{"path":"/tmp/file.txt"}}}

错误:

{"jsonrpc":"2.0","id":2,"error":{"code":-32603,"message":"文件未找到","data":{"context":"readFile"}}}

JSON-RPC 格式特点:

使用场景

1. 调试 MCP 服务器

记录所有 I/O 操作,方便调试和问题排查:

const wrapper = new MCPWrapper({
  serverCommand: 'your-mcp-server',
  logFilePath: './logs/debug.log',
  logToolCalls: true,
  logToolResults: true
});

2. 监控工具使用

跟踪哪些工具被调用、频率和参数:

const wrapper = new MCPWrapper({
  serverCommand: 'your-mcp-server',
  logFilePath: './logs/monitoring.log'
});

// 日志会记录所有工具调用
await wrapper.callTool('some_tool', params);

3. 创建代理服务器

在多个 MCP 服务器之间路由请求,或添加额外功能层。

4. 审计和合规

保留所有 MCP 交互的完整审计日志。

运行示例

基础使用示例

npm run build
npm run dev examples/library/basic-usage.ts

代理服务器示例

npm run build
npm run dev examples/server/server-wrapper.ts

开发

# 安装依赖
npm install

# 构建
npm run build

# 监视模式(自动重新编译)
npm run watch

# 运行开发模式
npm run dev examples/basic-usage.ts

技术栈

注意事项

  1. 确保被包装的 MCP 服务器可以正常启动和运行
  2. 日志文件会自动创建目录(如果不存在)
  3. 使用 logAppend: false 时,每次启动都会覆盖日志文件
  4. 记得在使用完毕后调用 disconnect() 以正确关闭连接和日志文件

许可证

MIT

贡献

欢迎提交 Issue 和 Pull Request!