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 installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceA 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.2831MIT
- Alicense-qualityDmaintenanceAn 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.376MIT
- 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
Related MCP Connectors
A MCP server built for developers enabling Git based project management with project and personal…
MCP server for interacting with the Supabase platform
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ElJijuna/mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server