使用说明
MCP服务器 - 模型上下文协议服务器
一个使用TypeScript和Node.js构建的、可投入生产的模型上下文协议(MCP)服务器。其特点包括模块化架构、动态插件加载、实时WebSocket事件处理、大型语言模型(LLM)集成以及多语言插件支持。
特点/特性
- 模块化架构 - 使用依赖注入(DI)容器实现清晰的职责分离
- 动态插件系统 - 在运行时加载TypeScript、Python、C和C++插件
- 实时事件 - 用于实时MCP事件流的WebSocket处理器
- 大型语言模型(LLM)集成 - OpenAI和Anthropic提供商提供提示工程支持
- Redis 缓存 - 与Redis集成实现快速数据缓存
- 任务计划程序 - 内置作业调度器用于后台任务
- 请求验证 - 基于Zod的中间件,用于类型安全的验证
- 错误处理 - 带日志记录功能的集中式错误中间件
- Docker 准备就绪 - 完整的Docker和docker-compose设置
- Kubernetes 已就绪 - 包含K8s部署清单
- 持续集成/持续交付(CI/CD) - GitHub Actions 工作流用于自动化测试
- 多语言 - 支持Python、C和C++的外部插件
技术栈
- 运行时Node.js 20+(版本)
- 语言TypeScript 5.6+
- 框架Express.js
- WebSocketws
- 验证佐德
- 记录日志温斯顿
- 缓存Redis
- LLMOpenAI,Anthropic
- 部署Docker,Kubernetes,Vercel
快速入门
先决条件
- Node.js 20+(版本)
- npm 或 yarn
- Docker(可选)
- Redis(可选)
安装
git clone https://github.com/raunak0400/MCP_SERVER.git
cd MCP_SERVER
npm install
配置
复制示例环境文件:
cp .env.example .env
编辑 .env 根据您的配置:
NODE_ENV=development
PORT=3000
LOG_LEVEL=info
REDIS_URL=redis://localhost:6379
OPENAI_API_KEY=sk-your-openai-key
ANTHROPIC_API_KEY=sk-ant-your-key
LLM_PROVIDER=openai
发展
npm run dev
构建
npm run build
生产
npm start
Docker 部署
构建并运行
docker build -t mcp-server .
docker run -p 3000:3000 mcp-server
Docker Compose
docker-compose up -d
项目结构
.
├── src/
│ ├── config/ # Configuration management
│ ├── core/ # Core services (DI, events, MCP server)
│ ├── routes/ # API route handlers
│ ├── services/ # Business logic services
│ ├── middleware/ # Express middleware
│ ├── handlers/ # WebSocket and event handlers
│ ├── controllers/ # Request controllers
│ ├── types/ # TypeScript type definitions
│ ├── utils/ # Utility functions
│ ├── plugins/ # Plugin system
│ │ ├── internal/ # TypeScript plugins
│ │ └── external/ # Python, C, C++ plugins
│ ├── llm/ # LLM integration
│ │ ├── openai.ts # OpenAI provider
│ │ ├── anthropic.ts # Anthropic provider
│ │ └── service.ts # LLM service
│ └── cache/ # Redis cache
├── scripts/ # Utility scripts
├── docs/ # Documentation
├── tests/ # Test suites
└── infra/ # Infrastructure configs
API 端点
健康检查
GET /health
执行MCP插件
POST /mcp/execute
Content-Type: application/json
{
"plugin": "sample",
"action": "echo",
"payload": { "message": "hello" }
}
插件开发
TypeScript 插件
创建一个插件在 src/plugins/internal/:
import { Plugin } from '../../types/index.js'
const plugin: Plugin = {
name: 'myPlugin',
actions: {
doSomething: async (payload) => {
return { result: 'done' }
}
}
}
export default plugin
Python 插件
在(某处)创建一个插件 src/plugins/external/python/:
import json
import sys
def process(data):
return {"processed": data}
if __name__ == "__main__":
payload = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
result = process(payload)
print(json.dumps(result))
添加到 manifest.json:
{
"name": "myPythonPlugin",
"command": "python",
"args": ["src/plugins/external/python/myplugin.py"]
}
大型语言模型(LLM)的使用
import { LLMService } from './llm'
const llm = new LLMService({
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY,
model: 'gpt-4',
temperature: 0.7,
maxTokens: 1000
})
const response = await llm.generateCompletion('Explain MCP protocol')
WebSocket 事件
连接到 ws://localhost:3000 接收实时事件:
const ws = new WebSocket('ws://localhost:3000')
ws.on('message', (data) => {
const event = JSON.parse(data)
console.log(event.type, event)
})
事件类型:
started- 服务器已启动pluginLoaded- 插件已注册pluginExecuted- 插件操作已执行
测试
npm test
贡献;助力
欢迎投稿!请阅读 CONTRIBUTING.md(贡献指南文件) 详情见下文。
- 为仓库创建分支
- 创建你的特性分支(
git checkout -b feature/amazing) - 提交您的更改(
git commit -m 'Add amazing feature') - 推送至分支(
git push origin feature/amazing) - 提交拉取请求(或:发起合并请求)
安全
看见 SECURITY.md 翻译为中文是:“安全指南/安全文件” 用于安全策略。
支持
如需支持,请参阅 SUPPORT.md 翻译为中文是:“支持文档.md” 或 “支持文件.md”(其中“.md”通常表示Markdown格式的文件) 或者提出一个问题。
许可证
这个项目采用MIT许可证授权——详见 许可证 详情请查阅文件。
致谢
- 模型上下文协议规范
- OpenAI和Anthropic提供大型语言模型(LLM)API
- Express.js 社区
- TypeScript 团队
路线图
- [ ] 添加认证系统
- [ ] 实施速率限制
- [ ] 添加更多大型语言模型(LLM)提供商(Gemini、Mistral)
- [ ] 创建插件市场
- [ ] 添加监控和指标
- [ ] 实现插件沙箱化
- 添加GraphQL API支持
- [ ] 创建管理员仪表板
建筑学
系统设计
MCP服务器采用分层架构模式,各层职责分明:
┌─────────────────────────────────────────┐
│ API Layer (Express) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Routes │ │ WebSocket │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Middleware Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ │
│ │Validation│ │ Auth │ │Error │ │
│ └──────────┘ └──────────┘ └──────┘ │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Application Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ │
│ │Controllers│ │ Services │ │ LLM │ │
│ └──────────┘ └──────────┘ └──────┘ │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Core Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ │
│ │ DI │ │ Events │ │ MCP │ │
│ │Container │ │ Bus │ │Server│ │
│ └──────────┘ └──────────┘ └──────┘ │
└─────────────────────────────────────────┘
│
┌─────────────────────────────────────────┐
│ Infrastructure Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────┐ │
│ │ Redis │ │ Logger │ │Plugin│ │
│ │ Cache │ │ │ │System│ │
│ └──────────┘ └──────────┘ └──────┘ │
└─────────────────────────────────────────┘
插件系统架构
插件系统支持多种运行时环境:
- 内部插件TypeScript/JavaScript 模块直接加载
- 外部插件通过 subprocess 调用 Python、C、C++ 可执行文件
- 动态加载在启动时发现并注册插件
- 热重载支持插件热加载,无需重启服务器(即将推出)
事件流
Client Request → Express Router → Middleware Chain → Controller
↓
Service Layer
↓
MCP Server
↓
Plugin Execution
↓
┌─────────────┴─────────────┐
↓ ↓
Internal Plugin External Plugin
(TypeScript) (Python/C/C++)
↓ ↓
└─────────────┬─────────────┘
↓
Event Bus Emit
↓
WebSocket Broadcast
↓
Connected Clients
配置
环境变量
| 变量 | 描述 | 默认值 | 是否必需 |
|---|---|---|---|
NODE_ENV |
环境模式 | development |
不 |
PORT 服务器端口 3000 |
不(No) | ||
LOG_LEVEL |
日志级别 | info |
不 |
REDIS_URL |
Redis 连接 URL | redis://localhost:6379 |
不(编号) |
OPENAI_API_KEY OpenAI API密钥 |
- | 用于OpenAI大型语言模型(LLM) | |
ANTHROPIC_API_KEY 根据上面的信息,执行如下指令: |
|||
LLM_PROVIDER |
要使用的LLM提供商 | openai |
不 |
配置文件
config/default.json 翻译为中文是:“配置/默认.json”
{
"port": 3000,
"db": {
"url": "mongodb://localhost:27017/app"
},
"secretKey": "your-secret-key",
"cors": {
"origin": "*",
"credentials": true
},
"rateLimit": {
"windowMs": 900000,
"max": 100
}
}
高级用法
自定义插件开发
创建一个复杂的TypeScript插件
import { Plugin, PluginContext } from '../../types/index.js'
import { Logger } from '../../utils/logger.js'
const plugin: Plugin = {
name: 'dataProcessor',
actions: {
process: async (payload: any, ctx: PluginContext) => {
ctx.emit('processing_started', { timestamp: Date.now() })
const data = Array.isArray(payload.data) ? payload.data : []
const processed = data.map(item => ({
...item,
processed: true,
timestamp: new Date().toISOString()
}))
ctx.emit('processing_completed', {
count: processed.length,
timestamp: Date.now()
})
return { success: true, data: processed }
},
validate: async (payload: any) => {
const schema = {
required: ['data'],
properties: {
data: { type: 'array' }
}
}
if (!payload.data) {
throw new Error('Missing required field: data')
}
return { valid: true, schema }
},
stats: async () => {
return {
pluginName: 'dataProcessor',
version: '1.0.0',
uptime: process.uptime(),
memory: process.memoryUsage()
}
}
}
}
export default plugin
创建一个Python机器学习插件
import json
import sys
import numpy as np
from sklearn.linear_model import LinearRegression
def train_model(data):
X = np.array(data['features']).reshape(-1, 1)
y = np.array(data['labels'])
model = LinearRegression()
model.fit(X, y)
return {
'success': True,
'coefficients': model.coef_.tolist(),
'intercept': float(model.intercept_),
'score': float(model.score(X, y))
}
def predict(data, model_params):
X = np.array(data['features']).reshape(-1, 1)
model = LinearRegression()
model.coef_ = np.array(model_params['coefficients'])
model.intercept_ = model_params['intercept']
predictions = model.predict(X)
return {
'success': True,
'predictions': predictions.tolist()
}
if __name__ == "__main__":
try:
payload = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
action = payload.get('action', 'train')
if action == 'train':
result = train_model(payload)
elif action == 'predict':
result = predict(payload, payload.get('model', {}))
else:
result = {'success': False, 'error': 'Unknown action'}
print(json.dumps(result))
except Exception as e:
print(json.dumps({'success': False, 'error': str(e)}))
sys.exit(1)
大型语言模型(LLM)集成示例
基本聊天完成(或“基础对话完成”)
import { LLMService } from './llm'
const llm = new LLMService({
provider: 'openai',
apiKey: process.env.OPENAI_API_KEY!,
model: 'gpt-4',
temperature: 0.7,
maxTokens: 1000
})
const response = await llm.generateCompletion(
'Explain the Model Context Protocol in simple terms'
)
console.log(response)
带上下文的聊天
import { PromptBuilder } from './llm'
const messages = new PromptBuilder()
.system('You are a helpful coding assistant')
.user('How do I create a REST API in Express?')
.build()
const response = await llm.chat({ messages })
console.log(response.choices[0].message.content)
小样本学习
import { PromptBuilder } from './llm'
const examples = [
{ input: 'translate: hello', output: 'hola' },
{ input: 'translate: goodbye', output: 'adiós' },
{ input: 'translate: thank you', output: 'gracias' }
]
const prompt = PromptBuilder.createFewShotPrompt(
examples,
'translate: good morning'
)
const response = await llm.generateCompletion(prompt)
console.log(response)
流式响应
const stream = await llm.chat({
messages: [{ role: 'user', content: 'Write a poem about coding' }],
stream: true
})
for await (const chunk of stream) {
process.stdout.write(chunk)
}
Redis 缓存
基本缓存操作
import { redisClient, connectRedis } from './cache/redis'
await connectRedis()
await redisClient.set('user:1', JSON.stringify({ name: 'John' }))
const user = await redisClient.get('user:1')
await redisClient.setEx('session:abc', 3600, 'session-data')
await redisClient.del('user:1')
旁路缓存模式(或称为旁路缓存策略)
async function getUser(id: string) {
const cached = await redisClient.get(`user:${id}`)
if (cached) {
return JSON.parse(cached)
}
const user = await database.findUser(id)
await redisClient.setEx(
`user:${id}`,
3600,
JSON.stringify(user)
)
return user
}
WebSocket 客户端示例
Node.js 客户端
const WebSocket = require('ws')
const ws = new WebSocket('ws://localhost:3000')
ws.on('open', () => {
console.log('Connected to MCP Server')
})
ws.on('message', (data) => {
const event = JSON.parse(data.toString())
console.log('Event:', event)
switch(event.type) {
case 'pluginLoaded':
console.log(`Plugin loaded: ${event.name}`)
break
case 'pluginExecuted':
console.log(`Plugin executed: ${event.name}.${event.action}`)
break
case 'started':
console.log('Server started')
break
}
})
ws.on('error', (error) => {
console.error('WebSocket error:', error)
})
ws.on('close', () => {
console.log('Disconnected from MCP Server')
})
浏览器客户端
const ws = new WebSocket('ws://localhost:3000')
ws.addEventListener('open', () => {
console.log('Connected to MCP Server')
})
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data)
console.log('Received:', data)
if (data.type === 'pluginExecuted') {
updateUI(data)
}
})
ws.addEventListener('error', (error) => {
console.error('Error:', error)
})
ws.addEventListener('close', () => {
console.log('Connection closed')
setTimeout(reconnect, 5000)
})
Kubernetes 部署
部署清单
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
labels:
app: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: mcp-server:1.0.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
- name: PORT
value: "3000"
- name: REDIS_URL
valueFrom:
configMapKeyRef:
name: mcp-config
key: redis-url
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: mcp-secrets
key: openai-key
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
服务清单/服务声明
apiVersion: v1
kind: Service
metadata:
name: mcp-server-service
spec:
type: LoadBalancer
selector:
app: mcp-server
ports:
- protocol: TCP
port: 80
targetPort: 3000
ConfigMap(在中文中通常直接保留原名,不进行翻译,但可解释为“配置映射”)
apiVersion: v1
kind: ConfigMap
metadata:
name: mcp-config
data:
redis-url: "redis://redis-service:6379"
log-level: "info"
秘密
apiVersion: v1
kind: Secret
metadata:
name: mcp-secrets
type: Opaque
data:
openai-key: <base64-encoded-key>
anthropic-key: <base64-encoded-key>
性能优化
缓存策略
- 查询结果缓存缓存数据库查询结果5-15分钟
- 大型语言模型(LLM)响应缓存缓存相似提示以减少API成本
- 静态内容使用CDN来托管静态资源
- 连接池重用数据库和Redis连接
负载均衡
使用Nginx或云负载均衡器来分配流量:
upstream mcp_backend {
least_conn;
server mcp-server-1:3000;
server mcp-server-2:3000;
server mcp-server-3:3000;
}
server {
listen 80;
location / {
proxy_pass http://mcp_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
监控与日志记录
日志级别
- 错误需要立即关注的关键问题
- 警告针对潜在有害情况的警告信息
- 信息一般信息消息
- 调试详细的调试信息
日志格式
{
"timestamp": "2025-10-19T10:30:45.123Z",
"level": "info",
"message": "Plugin executed successfully",
"plugin": "sample",
"action": "echo",
"duration": 45
}
需要监控的指标
- 请求速率每秒请求数
- 响应时间平均延迟和第95百分位延迟
- 错误率请求失败的百分比
- 插件执行时间每个插件所花费的时间
- 内存使用量当前内存使用量
- CPU使用率CPU利用率百分比
- WebSocket 连接活动连接数
- 缓存命中率Redis缓存有效性
安全最佳实践
API安全
- API密钥使用环境变量,切勿提交到代码库
- 速率限制实现用户级别的速率限制
- 输入验证使用Zod模式验证所有输入
- **CORS(跨源资源共享)**配置适当的CORS策略
- Helmet.js默认启用安全头
- HTTPS在生产环境中始终使用TLS
插件沙盒化
- 资源限制为外部插件设置CPU和内存限制
- 超时配置执行超时时间
- 权限模型限制文件系统和网络访问
- **输入净化(或输入验证/输入清理)**验证插件输入
数据保护
- 静态数据加密对数据库中的敏感数据进行加密
- 传输过程中的加密对所有通信使用TLS
- 密钥管理使用密钥管理工具(Vault、AWS Secrets Manager)
- 访问控制实施基于角色的访问控制(RBAC)
故障排除
常见问题
服务器无法启动
Error: EADDRINUSE: address already in use :::3000
解决方案更改端口或终止使用3000端口的进程
lsof -ti:3000 | xargs kill -9
Redis 连接失败
Error: Redis connection to localhost:6379 failed
解决方案确保 Redis 正在运行
docker run -d -p 6379:6379 redis:7-alpine
插件加载失败
Error: Plugin not found
解决方案检查插件路径和manifest.json文件
ls -la src/plugins/
cat src/plugins/manifest.json
大型语言模型API错误
Error: OpenAI API error: 401 Unauthorized
解决方案验证.env文件中的API密钥
grep OPENAI_API_KEY .env
调试模式
启用调试日志记录:
LOG_LEVEL=debug npm run dev
性能基准
响应时间
| 终点 | 平均值(毫秒) | p95(毫秒) | p99(毫秒) |
|---|---|---|---|
| GET /health | 5 | 8 | 12 |
| POST /mcp/execute | 45 | 120 | 250 |
| 大语言模型聊天 | 1500 | 3000 | 5000 |
| 插件(内部) | 15 | 35 | 60 |
| 插件(外部) | 80 | 200 | 400 |
吞吐量
- 每秒最大请求数5,000(含缓存)
- 并发WebSocket连接一万
- 插件执行次数/秒1,000
迁移指南
从v0.x到v1.0
- 更新 package.json 中的依赖项
- 将插件结构迁移到新格式
- 更新环境变量
- 运行数据库迁移
- 更新 Docker 配置
常见问题解答(FAQ)
问:我可以将这个与其它大型语言模型(LLM)提供商一起使用吗?
A: 是的,您可以扩展LLM服务以支持额外的提供商,如Google Gemini、Mistral或本地模型。
问:如何在Go或Rust中创建一个插件?
A: 将你的Go/Rust代码编译成可执行文件,并在manifest.json中注册它,类似于C/C++插件的注册方式。
问:是否支持水平扩展?
A: 是的,服务器是无状态的,可以水平扩展。使用Redis来共享状态。
问:我可以将应用部署到无服务器平台上吗?
A: 是的,但需要做一些修改。通过配置更改,可以支持Vercel和AWS Lambda。
问:我该如何实现身份验证?
A: 在 src/middleware/auth.ts 中实现基于 JWT 的认证中间件。
问:插件执行的超时时间是多少?
A: 默认值为30秒。可在服务中针对每个插件进行配置。
社区
贡献;做出贡献
我们欢迎投稿!以下是您能提供帮助的方式:
- 报告错误提交一个包含复现步骤的问题
- 功能请求通过问题提交新功能建议
- 代码贡献提交拉取请求
- 文档改进文档和示例
- 测试为现有代码编写测试
行为准则
请阅读我们的 行为准则 在贡献之前。
贡献者
感谢所有为使这个项目更加完善而做出贡献的人!
资源
文档
外部链接
更新日志
看 CHANGELOG.md 翻译成中文是“变更日志文件” 查看版本历史和发布说明。
许可证
这个项目采用MIT许可证授权——详见 许可证 文件中有详细信息。
赞助商
有兴趣赞助这个项目吗?请联系我们!
联系
- 作者raunak0400(此用户名或特定标识通常不直接翻译,保持原样)
- GitHub: @raunak0400(这个用户名或标签在中文中通常保持不变,直接翻译可能无实际意义,故保留原样)
- 仓库(或代码库): MCP_SERVER 可以翻译为“MCP服务器”
- 问题: 问题追踪器
- 讨论: GitHub 讨论区
由MCP服务器团队用心打造 | 如果你觉得这个仓库有帮助,请给它点个星⭐!
