mcp-server
mcp-server
MCP Server 用 TypeScript 编写,将团队的工程工具——Bitbucket、Jira、Confluence 和 ArgoCD——暴露给支持 MCP 的编辑器(VS Code + Copilot、Claude Code 等)。
它是一个薄层封装:不与 Bitbucket/Jira/Confluence/ArgoCD 直接通信,也不保存这些服务的凭据。所有操作都转换为对内部后端 eng-api 的 HTTP 调用,该后端已处理连接和凭据。
VS Code (dev A) ─┐
VS Code (dev B) ─┼─► MCP Server ───► eng-api ───► Bitbucket / Jira / Confluence / ArgoCD
VS Code (dev C) ─┘ (este repo) (credenciales viven aquí)
Streamable HTTP HTTP
+ API key por dev优势: 开发者无需 Bitbucket/Jira/Confluence/ArgoCD 的个人令牌。只需要这个 MCP Server 的 API 密钥,且可单独撤销。
1. 要求
Node.js ≥ 22
能够访问
ENG_API_BASE_URL(eng-api 的 URL)
Related MCP server: Work Integrations MCP
2. 本地运行
npm ci
cp .env.example .env # y rellena los valores (ver sección 3)
npm run dev # hot-reload, lee .env automáticamente其他命令:
命令 | 作用 |
| 以监听模式启动,读取 |
| 将 TypeScript 编译到 |
| 仅类型检查,不输出 |
| 启动编译后的代码(使用环境变量;这是 Pod 中运行的命令) |
| 启动编译后的代码,读取 |
快速检查服务是否运行:
curl http://localhost:3000/healthz
# {"status":"ok","server":"mcp-server","version":"0.1.0"}3. 配置(.env)
所有变量从 process.env 读取。如果缺少必填变量或值无效,进程将不会启动,并准确说明需要修改什么。
变量 | 必填 | 默认值 | 描述 |
| ✅ | — | eng-api 的基础 URL,末尾无斜杠。必须为 |
| ✅ | — | 针对此 MCP Server 的有效开发者 API 密钥(参见 §4) |
| — |
| 每次调用 eng-api 的超时时间(1000–120000) |
| — |
| 遇到 5xx/429/超时时的额外重试次数(0–5) |
| — |
| MCP Server 的 HTTP 端口 |
| — |
|
|
故意启动失败的示例:
Configuración inválida: el MCP Server no puede arrancar.
- Falta la variable obligatoria ENG_API_BASE_URL. Debe apuntar a la URL base de eng-api, ej. https://eng-api.internal.example/api/v1
Revisa tu archivo .env (usa .env.example como plantilla) o el ConfigMap/Secret del Deployment.4. 认证:每个开发者一个 API 密钥
这个认证层是 MCP Server 自身 的,与 eng-api 对最终服务使用的认证无关。
生成密钥
openssl rand -hex 32 # una por cada persona del equipo配置密钥
MCP_DEV_API_KEYS 接受四种格式(每个密钥至少 24 个字符,无重复):
MCP_DEV_API_KEYS=<key1>,<key2> # CSV simple
MCP_DEV_API_KEYS=alice:<key1>,bob:<key2> # CSV etiquetado ← recomendado
MCP_DEV_API_KEYS=["<key1>","<key2>"] # JSON array
MCP_DEV_API_KEYS={"alice":"<key1>","bob":"<key2>"} # JSON objeto使用带标签格式:标签会出现在 MCP Server 的日志中,并传播到 eng-api 的 X-Mcp-Dev 头部,因此可以审计谁触发了某个操作(例如 argocd_sync_app),而无需暴露密钥。
使用密钥
MCP 客户端必须在每次请求中发送:
Authorization: Bearer <API_KEY>(或者,作为替代,使用 x-api-key: <API_KEY>)。比较是时间安全的,基于 SHA-256 摘要。
情况 | 响应 |
缺少密钥 |
|
无效/已撤销的密钥 |
|
| 无需认证(用于 Kubernetes 探针) |
撤销某人的密钥 = 从 MCP_DEV_API_KEYS 中移除其密钥,然后重启 Deployment。由于每个开发者都有自己的密钥,不会影响其他人。在生产环境中,将值保存在 Kubernetes 的 Secret 中,切勿放在 ConfigMap 中。
5. 工具目录
工具名称以服务为前缀,并面向操作。所有支持分页的地方(page、pageSize 范围 1 到 100,默认为 25)都支持分页。
Bitbucket(只读)
工具 | 参数 | eng-api 端点 |
|
|
|
|
|
|
|
|
|
Jira
工具 | 参数 | eng-api 端点 |
|
|
|
|
|
|
|
|
|
Confluence(只读)
工具 | 参数 | eng-api 端点 |
|
|
|
|
|
|
ArgoCD
工具 | 参数 | eng-api 端点 |
|
|
|
|
|
|
|
|
|
注释(给 MCP 客户端的提示)
工具 |
|
|
|
|
所有读取工具 | ✅ | ❌ | ✅ | ✅ |
| ❌ | ❌ | ❌ | ✅ |
| ❌ | ✅ | ❌ | ✅ |
argocd_sync_app 要求提供应用的精确名称(无通配符或默认值),且 prune/dryRun 默认为 false,除非明确指定。
eng-api 的路由全部位于 src/client/routes.ts。如果 eng-api 更改了路径,只需修改该文件。
6. 配置 VS Code(每个开发者使用自己的密钥)
在你的工作区创建 .vscode/mcp.json(或用户级别的 mcp.json,如果你想在所有项目中使用):
{
"inputs": [
{
"type": "promptString",
"id": "eng-mcp-api-key",
"description": "Tu API key personal del MCP Server de ingeniería",
"password": true
}
],
"servers": {
"eng": {
"type": "http",
"url": "https://<host-del-mcp-server>/mcp",
"headers": {
"Authorization": "Bearer ${input:eng-mcp-api-key}"
}
}
}
}VS Code 首次会要求输入密钥,并加密保存;切勿提交到版本控制。之后,在 Agent 模式下打开聊天,你会看到 eng 服务器下的 11 个工具。
对于 Claude Code(CLI),等效配置如下:
claude mcp add --transport http eng https://<host-del-mcp-server>/mcp \
--header "Authorization: Bearer <TU_API_KEY>"在本地,将 URL 替换为 http://localhost:3000/mcp。
7. 使用 MCP Inspector 测试
npm run build && npm run start:local # en una terminal
npx @modelcontextprotocol/inspector # en otra在 Inspector 的 UI 中:
Transport Type:
Streamable HTTPURL:
http://localhost:3000/mcp在 Authentication 中,设置 Header Name 为
Authorization,Bearer Token 为你的 API 密钥Connect → 选项卡 Tools → List Tools → 测试任意一个
也可以直接用 curl 测试(在 CI 或 Pod 中很有用):
KEY=<tu-api-key>
curl -s -X POST http://localhost:3000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'调用一个工具:
curl -s -X POST http://localhost:3000/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $KEY" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
"name":"bitbucket_list_prs",
"arguments":{"workspace":"acme","repoSlug":"web-frontend","state":"OPEN","pageSize":10}}}'8. Docker
docker build -t mcp-server:0.1.0 .
docker run --rm -p 3000:3000 \
-e ENG_API_BASE_URL="https://<eng-api>/api/v1" \
-e MCP_DEV_API_KEYS="alice:<key1>,bob:<key2>" \
mcp-server:0.1.0多阶段构建镜像,基于 node:22-alpine:最终镜像只包含 dist/ 和运行时依赖,以 node 用户身份运行(非 root),并包含一个 HEALTHCHECK,使用 Node 自身(无需 curl/wget)访问 /healthz。
对于 Kubernetes(清单不在本仓库中):
服务器是无状态的:不在内存中保存会话,因此可以扩展到 N 个副本无需粘性会话。
探针:
livenessProbe→GET /healthz,readinessProbe→GET /readyz(两者均无需认证)。MCP_DEV_API_KEYS放在Secret中;ENG_API_BASE_URL和超时设置可以放在ConfigMap中。处理
SIGTERM信号,优雅关闭 HTTP 服务器(最多 10 秒的排空时间)。
9. 如何添加新服务或工具
此模式旨在使添加新服务不触及任何现有代码。以假设的 Grafana 为例:
1. 在 src/client/routes.ts 中添加其路由:
grafana: {
listDashboards: (): string => "/grafana/dashboards",
getDashboard: (uid: string): string => `/grafana/dashboards/${seg(uid)}`,
},2. 创建 src/tools/grafana.ts,遵循与其他工具相同的模板:
export function registerGrafanaTools(server: McpServer, deps: ToolDeps): void {
registerEngTool(server, deps, {
name: "grafana_list_dashboards", // prefijo de servicio + acción
title: "Grafana: listar dashboards",
description: "Qué hace y cuándo usarlo.",
inputSchema: { query: z.string().optional().describe('Texto a buscar. Ejemplo: "latencia checkout".'),
...paginationShape },
annotations: readOnlyAnnotations("Grafana: listar dashboards"),
describeOperation: (args) => `listar dashboards de Grafana`, // encaja tras "al …"
execute: (args, { client, context }) =>
client.get(engApiRoutes.grafana.listDashboards(), {
query: { query: args.query, ...paginationQuery(args) },
context,
}),
});
}3. 在 src/server.ts 的 TOOL_REGISTRARS 中注册它:
const TOOL_REGISTRARS = [ …, registerGrafanaTools ];仅此而已。registerEngTool 已经免费为你提供了:Zod 验证、响应格式化、大负载截断、错误捕获并转换为可操作消息、以及带有 requestId 的日志记录。
新工具的样式规则:
名称格式:
服务_动作_对象,小写。Schema 中的每个字段必须使用
.describe()并提供具体示例——这是模型决定如何调用它的唯一依据。诚实的注释:如果是写入操作,
readOnlyHint: false;如果可能删除内容,destructiveHint: true。破坏性操作中不要使用危险的默认值:要求精确的标识符。
所有返回列表的工具都要支持分页(
...paginationShape+paginationQuery(args))。切勿在
tools/中手动构建 URL:始终通过engApiRoutes。
10. 错误处理
任何工具都不会返回赤裸裸的“Error 500”。每个错误都包含失败原因、需要检查的内容以及一个 requestId,用于与 eng-api 的日志进行关联。真实示例:
No existe el recurso al obtener el estado de la aplicación boom (404). Verifica los identificadores
exactos (workspace/repo, key de issue, id de página, nombre de app) — distinguen mayúsculas. Si los
identificadores son correctos, la ruta de eng-api puede haber cambiado (src/client/routes.ts).
[requestId=8a4bf9e6-…, intentos=1, upstream=GET /argocd/applications/boom]
Respuesta de eng-api: {"error":"application not found"}情况 | MCP 服务器的行为 |
Timeout / 网络错误 | 使用指数退避 + 抖动重试( |
| 重试(如果存在则遵循 |
| 不重试:参数无效 |
| 澄清这不是你的 MCP API 密钥,而是 eng-api 的凭据/权限 |
| 建议检查精确的标识符和 |
| 状态冲突(例如 ArgoCD 同步已在进行中):检查状态然后重试 |
非 JSON 响应 | 通常是代理返回 HTML:可能路由不存在 |
巨大的负载 | 截断至 120,000 字符并提示减小 |
11. 项目结构
src/
├── index.ts # entrypoint: Express + Streamable HTTP (stateless), /healthz, /readyz
├── config.ts # lectura y validación de env vars, fail-fast
├── auth.ts # middleware de API key (timing-safe)
├── logger.ts # logs JSON de una línea, aptos para Cloud Logging
├── server.ts # createMcpServer(): registra todas las familias de tools
├── client/
│ ├── routes.ts # ÚNICO sitio con las rutas de eng-api
│ ├── errors.ts # EngApiError → mensajes accionables
│ └── engApiClient.ts # fetch + timeout + retry con backoff
└── tools/
├── shared.ts # registerEngTool(), paginación, formateo, errores
├── bitbucket.ts ├── jira.ts ├── confluence.ts └── argocd.ts设计决策:
Streamable HTTP 无状态模式(
sessionIdGenerator: undefined,enableJsonResponse: true):每个请求创建一个McpServer+ transport。开发者之间无共享状态,无粘性会话,水平扩展,响应为纯 JSON(比 SSE 对 ingress/proxy 更友好)。仅
POST /mcp:GET/DELETE返回405,因为在无状态下没有服务器→客户端流或需要关闭的会话。可追溯性:每个请求都带有
X-Request-Id(如果客户端发送则保留)和X-Mcp-Dev(带有开发者标签),两者都会传播到 eng-api。
This server cannot be deployed
Maintenance
Related MCP Connectors
An MCP server that provides an API to LLMs to manage their JumpCloud resources.
A MCP server built for developers enabling Git based project management with project and personal…
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
- SupabaseOAuthcom.supabase
MCP server for interacting with the Supabase platform
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA TypeScript-based MCP server that provides backend API handling and facilitates communication between microservices. Features an organized structure with controllers, routes, and models for easy extensibility and maintenance.398 npm1MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables interaction with Jira to fetch issues by key and perform JQL searches. It provides a foundation for integrating multiple work systems, with planned support for Slack and GitHub.522 npmMIT
- AlicenseBqualityDmaintenanceProduction-ready TypeScript MCP server exposing utility, GitHub, and Microsoft Teams tools over stdio.141MIT
- AlicenseBqualityCmaintenanceLightweight MCP server for Jira, Confluence, and Bitbucket — read, create, and update from your AI IDE.20MIT