在实际AI落地项目中,最大的痛点不是训练模型,而是把AI能力接入到现有的工具链中。比如:
OpenClaw MCP Server就是为解决这些问题而生的。它的核心能力是:把OpenClaw的AI能力通过标准MCP协议暴露出来,让任何MCP客户端都能调用。
本文以Linux服务器(Ubuntu 22.04)为例,手把手完成从安装到调用的完整流程。
首先确认系统环境和依赖:
# 检查Node.js版本(需要>=18)
node --version
# 正常输出:v18.x.x 或更高
# 检查npm版本
npm --version
# 正常输出:9.x.x 或更高
# 如果版本过低,更新Node.js
# 方法一:使用nvm(推荐)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install 20
nvm use 20
# 方法二:直接安装
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs
# 创建工作目录
mkdir -p ~/mcp-projects && cd ~/mcp-projects
# 初始化项目
npm init -y
# 安装OpenClaw作为依赖
npm install openclaw --save
# 或者全局安装(推荐,方便命令行调用)
npm install -g openclaw
# 验证安装
openclaw --version
# 输出类似:openclaw/0.x.x linux-x64 node-v20.x.x
在项目根目录创建mcp-config.json:
{
"server": {
"host": "0.0.0.0",
"port": 18790,
"mode": "mcp"
},
"mcp": {
"name": "openclaw-mcp-server",
"version": "1.0.0",
"description": "OpenClaw AI能力MCP服务器",
"capabilities": [
"chat.complete",
"chat.stream",
"embedding.generate",
"file.read",
"file.write",
"exec.run"
]
},
"llm": {
"provider": "openai",
"model": "gpt-4o",
"apiBase": "https://api.openai.com/v1",
"apiKey": "${OPENAI_API_KEY}",
"temperature": 0.7,
"maxTokens": 4096
},
"auth": {
"type": "bearer",
"token": "${MCP_AUTH_TOKEN}"
},
"cors": {
"enabled": true,
"origins": ["http://localhost:3000", "http://127.0.0.1:3000"]
}
}
server.port:MCP Server监听端口,默认18790llm.apiKey:使用环境变量避免硬编码敏感信息cors.origins:允许的跨域来源,生产环境要精确配置capabilities:声明当前Server支持的能力,客户端会据此决定能调什么# 创建.env文件(加入.gitignore)
cat > .env << 'EOF'
OPENAI_API_KEY=sk-your-api-key-here
MCP_AUTH_TOKEN=your-secure-token-here
LOG_LEVEL=info
EOF
# 环境变量加载(推荐使用dotenv)
npm install dotenv --save
# 或者在系统层面设置(永久生效)
echo 'export OPENAI_API_KEY=sk-your-api-key-here' >> ~/.bashrc
echo 'export MCP_AUTH_TOKEN=your-secure-token-here' >> ~/.bashrc
source ~/.bashrc
创建server.js:
const { Server } = require('openclaw');
const dotenv = require('dotenv');
const fs = require('fs');
// 加载.env环境变量
dotenv.config();
// 读取MCP配置
const config = JSON.parse(fs.readFileSync('./mcp-config.json', 'utf8'));
// 创建MCP Server实例
const server = new Server({
name: config.mcp.name,
version: config.mcp.version,
capabilities: config.mcp.capabilities,
llm: config.llm,
auth: config.auth,
});
// 注册MCP工具处理器
server.registerToolHandler(async (toolName, params, context) => {
switch (toolName) {
case 'chat.complete':
// 聊天补全工具
return await handleChatComplete(params, context);
case 'chat.stream':
// 流式聊天工具
return await handleChatStream(params, context);
case 'embedding.generate':
// 向量嵌入工具
return await handleEmbedding(params, context);
case 'file.read':
// 文件读取工具
return await handleFileRead(params, context);
case 'file.write':
// 文件写入工具
return await handleFileWrite(params, context);
case 'exec.run':
// 命令执行工具
return await handleExecRun(params, context);
default:
throw new Error(`Unknown tool: ${toolName}`);
}
});
// 工具处理器实现
async function handleChatComplete(params, context) {
const { messages, model, temperature, maxTokens } = params;
const response = await context.llm.chat.complete({
model: model || config.llm.model,
messages,
temperature: temperature || config.llm.temperature,
maxTokens: maxTokens || config.llm.maxTokens,
});
return response;
}
async function handleChatStream(params, context) {
const { messages, model } = params;
// 流式返回,需要客户端支持SSE
return context.llm.chat.stream({
model: model || config.llm.model,
messages,
});
}
async function handleEmbedding(params, context) {
const { texts, model } = params;
return await context.llm.embedding.generate({
model: model || 'text-embedding-3-small',
texts,
});
}
async function handleFileRead(params, context) {
const { path, encoding } = params;
// 安全检查:防止路径遍历攻击
const safePath = resolveSecurePath(path);
const content = fs.readFileSync(safePath, encoding || 'utf8');
return { content, path: safePath };
}
async function handleFileWrite(params, context) {
const { path, content, encoding } = params;
const safePath = resolveSecurePath(path);
fs.writeFileSync(safePath, content, encoding || 'utf8');
return { success: true, path: safePath };
}
async function handleExecRun(params, context) {
const { command, timeout, cwd } = params;
const { exec } = require('child_process');
return new Promise((resolve, reject) => {
exec(command, { timeout: timeout || 30000, cwd: cwd || process.cwd() },
(error, stdout, stderr) => {
if (error) reject(error);
else resolve({ stdout, stderr });
});
});
}
// 路径安全检查函数
function resolveSecurePath(userPath) {
const baseDir = '/var/www/mcp-files';
const resolved = path.resolve(baseDir, userPath);
if (!resolved.startsWith(baseDir)) {
throw new Error('Access denied: path traversal attempt detected');
}
return resolved;
}
// 启动服务器
server.listen({
host: config.server.host,
port: config.server.port,
cors: config.cors,
}).then(() => {
console.log(`✅ OpenClaw MCP Server 已启动`);
console.log(` 地址: http://${config.server.host}:${config.server.port}`);
console.log(` 模式: MCP`);
console.log(` 支持的能力: ${config.mcp.capabilities.join(', ')}`);
}).catch((err) => {
console.error('❌ 启动失败:', err);
process.exit(1);
});
// 优雅退出
process.on('SIGTERM', () => {
console.log('收到SIGTERM信号,正在关闭服务器...');
server.close().then(() => {
console.log('服务器已关闭');
process.exit(0);
});
});
# 全局安装PM2
npm install -g pm2
# 创建PM2配置文件 ecosystem.config.js
module.exports = {
apps: [{
name: 'openclaw-mcp-server',
script: './server.js',
cwd: '/root/mcp-projects',
env: {
NODE_ENV: 'production',
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
MCP_AUTH_TOKEN: process.env.MCP_AUTH_TOKEN,
},
env_production: {
NODE_ENV: 'production',
},
instances: 1, // 单实例,生产环境可改多实例
autorestart: true, // 崩溃自动重启
watch: false, // 生产环境关闭watch
max_memory_restart: '500M', // 内存超500M自动重启
log_date_format: 'YYYY-MM-DD HH:mm:ss',
error_file: './logs/error.log',
out_file: './logs/out.log',
time: true,
}]
};
# 创建日志目录
mkdir -p logs
# 启动服务
pm2 start ecosystem.config.js --env production
# 查看运行状态
pm2 list
pm2 logs openclaw-mcp-server
# 设置开机自启
pm2 startup
pm2 save
# Step 1: 在VSCode中安装Cline插件
# 打开VSCode -> 扩展 -> 搜索"Cline" -> 安装
# Step 2: 配置Cline使用MCP Server
# 打开Cline设置(设置图标 -> Extensions -> Cline)
# 在 settings.json 中添加:
{
"cline": {
"mcpServers": {
"openclaw": {
"type": "http",
"url": "http://121.43.27.184:18790/mcp",
"headers": {
"Authorization": "Bearer your-secure-token-here"
},
"timeout": 60000
}
}
}
}
配置完成后,在Cline的MCP Servers面板应该能看到openclaw显示为Connected状态。
# 使用curl测试(注意:MCP使用SSE协议,这里用简单HTTP测试)
curl -X POST http://127.0.0.1:18790/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-secure-token-here" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'
# 预期响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{"name": "chat.complete", "description": "..."},
{"name": "embedding.generate", "description": "..."},
{"name": "file.read", "description": "..."},
{"name": "file.write", "description": "..."},
{"name": "exec.run", "description": "..."}
]
}
}
# 添加Nginx配置
sudo tee /etc/nginx/conf.d/mcp-proxy.conf << 'EOF'
server {
listen 8083;
server_name _;
location /mcp {
proxy_pass http://127.0.0.1:18790;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# MCP流式响应需要关闭buffer
proxy_buffering off;
proxy_cache off;
# 超时配置(MCP请求可能较长)
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}
EOF
# 测试并重载Nginx
sudo nginx -t
sudo nginx -s reload
# 现在可以通过 http://121.43.27.184:8083/mcp 访问
| 指标 | 未接入MCP | 接入MCP后 | 提升 |
|---|---|---|---|
| 代码审查耗时 | 手动5分钟/次 | AI自动 30秒/次 | 10x |
| 知识库查询 | 打开浏览器+搜索 | IDE内直接提问 | 即时 |
| 文件批量处理 | 逐个手动操作 | AI批量自动化 | 50x+ |
| 命令执行 | 复制粘贴命令 | 自然语言转命令 | 5x |
在Cursor中接入MCP Server后,可以直接这样用:
问: "帮我检查/home/www/project目录下的所有.js文件,把有语法错误的列出来,并给出修复建议"
AI响应:
- 读取所有.js文件(通过MCP file.read工具)
- 语法检查(通过MCP exec.run运行node --check)
- 汇总结果并给出建议
整个过程在Cursor内完成,不需要切换到终端。
| 客户端 | 插件 | 支持的功能 | 配置难度 |
|---|---|---|---|
| VSCode | Cline / Continue | 全部 | ⭐⭐ |
| Cursor | 内置MCP | 全部 | ⭐ |
| Windsurf | Cline | 全部 | ⭐⭐ |
| OpenClaw | 内置 | 全部 | ⭐ |
| 其他 | MCP客户端SDK | 取决于SDK | ⭐⭐⭐ |
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
| Connection refused | 端口被占用/服务未启动 | 检查PM2状态,确认端口监听netstat -tlnp | grep 18790 |
| 401 Unauthorized | Token不匹配 | 确认服务端和客户端的token一致 |
| CORS error | 跨域配置问题 | 检查config中cors.origins是否包含客户端地址 |
| tool not found | 能力未声明 | 在capabilities中添加对应工具名 |
| path traversal denied | 文件路径安全检查拦截 | 确认路径在允许的基础目录内 |
{
"server": {
"host": "127.0.0.1", // 只监听本地,生产环境用Nginx代理
"port": 18790,
"mode": "mcp"
},
"auth": {
"type": "bearer",
"token": "${MCP_AUTH_TOKEN}",
"rateLimit": {
"windowMs": 60000,
"maxRequests": 100
}
},
"cors": {
"enabled": true,
"origins": ["https://your-production-domain.com"]
},
"logging": {
"level": "warn",
"accessLog": false // 关闭访问日志,减少IO
}
}
# 启动服务
pm2 start ecosystem.config.js --env production
# 查看状态
pm2 list
pm2 logs openclaw-mcp-server --lines 50
# 重启服务
pm2 restart openclaw-mcp-server
# 停止服务
pm2 stop openclaw-mcp-server
# 开机自启
pm2 save && pm2 startup
# Nginx重载配置
sudo nginx -t && sudo nginx -s reload