mcp-server
mcp-server
MCP Server en TypeScript que expone las herramientas de ingeniería del equipo —Bitbucket, Jira, Confluence y ArgoCD— a los editores con soporte MCP (VS Code + Copilot, Claude Code, etc.).
Es una capa delgada (thin wrapper): no habla con Bitbucket/Jira/Confluence/ArgoCD, ni guarda credenciales de esos servicios. Todo lo traduce a llamadas HTTP contra el backend interno eng-api, que ya tiene resueltas conexiones y credenciales.
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 devVentaja: ningún dev necesita tokens personales de Bitbucket/Jira/Confluence/ArgoCD. Solo una API key de este MCP Server, revocable individualmente.
1. Requisitos
Node.js ≥ 22
Acceso de red a
ENG_API_BASE_URL(la URL de eng-api)
Related MCP server: Work Integrations MCP
2. Correr localmente
npm ci
cp .env.example .env # y rellena los valores (ver sección 3)
npm run dev # hot-reload, lee .env automáticamenteOtros comandos:
Comando | Qué hace |
| Arranca en modo watch leyendo |
| Compila TypeScript a |
| Type-check sin emitir |
| Arranca lo compilado (usa variables del entorno; es lo que corre en el pod) |
| Arranca lo compilado leyendo |
Comprobación rápida de que está vivo:
curl http://localhost:3000/healthz
# {"status":"ok","server":"mcp-server","version":"0.1.0"}3. Configuración (.env)
Todas las variables se leen de process.env. Si falta una obligatoria o tiene un valor inválido, el proceso no arranca y explica exactamente qué corregir.
Variable | Obligatoria | Default | Descripción |
| ✅ | — | URL base de eng-api, sin barra final. Debe ser |
| ✅ | — | API keys válidas de los devs contra este MCP Server (ver §4) |
| — |
| Timeout por llamada a eng-api (1000–120000) |
| — |
| Reintentos adicionales ante 5xx/429/timeout (0–5) |
| — |
| Puerto HTTP del MCP Server |
| — |
|
|
Ejemplo de arranque fallido (a propósito):
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. Autenticación: una API key por dev
Esta capa de auth es propia del MCP Server e independiente de la que eng-api use hacia los servicios finales.
Generar keys
openssl rand -hex 32 # una por cada persona del equipoConfigurarlas
MCP_DEV_API_KEYS acepta cuatro formatos (mínimo 24 caracteres por key, sin duplicados):
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 objetoUsa el formato etiquetado: la etiqueta aparece en los logs del MCP Server y se propaga a eng-api en el header X-Mcp-Dev, así que se puede auditar quién disparó cada operación (por ejemplo, un argocd_sync_app) sin exponer la key.
Usarlas
El cliente MCP debe enviar en cada petición:
Authorization: Bearer <API_KEY>(o, como alternativa, x-api-key: <API_KEY>). La comparación es timing-safe sobre digests SHA-256.
Situación | Respuesta |
Sin key |
|
Key inválida/revocada |
|
| Sin auth (para los probes de Kubernetes) |
Revocar a alguien = quitar su key de MCP_DEV_API_KEYS y reiniciar el Deployment. Como cada dev tiene la suya, no afecta al resto. En producción, guarda el valor en un Secret de Kubernetes, nunca en un ConfigMap.
5. Catálogo de tools
Los nombres llevan prefijo del servicio y son orientados a acción. Todos soportan paginación donde aplica (page, pageSize de 1 a 100, por defecto 25).
Bitbucket (solo lectura)
Tool | Argumentos | Endpoint eng-api |
|
|
|
|
|
|
|
|
|
Jira
Tool | Argumentos | Endpoint eng-api |
|
|
|
|
|
|
|
|
|
Confluence (solo lectura)
Tool | Argumentos | Endpoint eng-api |
|
|
|
|
|
|
ArgoCD
Tool | Argumentos | Endpoint eng-api |
|
|
|
|
|
|
|
|
|
Anotaciones (hints para el cliente MCP)
Tool |
|
|
|
|
Todos los de lectura | ✅ | ❌ | ✅ | ✅ |
| ❌ | ❌ | ❌ | ✅ |
| ❌ | ✅ | ❌ | ✅ |
argocd_sync_app exige el nombre exacto de la app (sin comodines ni valores por defecto) y prune/dryRun van en false salvo que se pidan explícitamente.
Las rutas de eng-api viven todas en src/client/routes.ts. Si eng-api cambia un path, se toca solo ese archivo.
6. Configurar VS Code (cada dev, con su propia key)
Crea .vscode/mcp.json en tu workspace (o el mcp.json de usuario, si lo quieres en todos los proyectos):
{
"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 pedirá la key la primera vez y la guardará cifrada; no se commitea nunca. Después, abre el chat en modo Agent y verás los 11 tools bajo el servidor eng.
Para Claude Code (CLI), el equivalente es:
claude mcp add --transport http eng https://<host-del-mcp-server>/mcp \
--header "Authorization: Bearer <TU_API_KEY>"En local, sustituye la URL por http://localhost:3000/mcp.
7. Probarlo con MCP Inspector
npm run build && npm run start:local # en una terminal
npx @modelcontextprotocol/inspector # en otraEn la UI del Inspector:
Transport Type:
Streamable HTTPURL:
http://localhost:3000/mcpEn Authentication, pon Header Name
Authorizationy el Bearer Token con tu API keyConnect → pestaña Tools → List Tools → prueba cualquiera
También se puede probar con curl directamente (útil en CI o desde un 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'Llamar a un tool:
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.0Imagen multi-stage sobre node:22-alpine: la final solo lleva dist/ + dependencias de producción, corre como usuario node (sin root) e incluye un HEALTHCHECK que golpea /healthz con el propio Node (sin curl/wget).
Para Kubernetes (los manifiestos no están en este repo):
El servidor es stateless: no guarda sesiones en memoria, así que escala a N réplicas sin sticky sessions.
Probes:
livenessProbe→GET /healthz,readinessProbe→GET /readyz(ambos sin auth).MCP_DEV_API_KEYSva en unSecret;ENG_API_BASE_URLy los timeouts pueden ir en unConfigMap.Maneja
SIGTERMcerrando el servidor HTTP con gracia (drenaje de 10 s como máximo).
9. Cómo añadir un servicio o tool nuevo
El patrón está pensado para que añadir un servicio no toque nada existente. Ejemplo con un hipotético Grafana:
1. Añade sus rutas en src/client/routes.ts:
grafana: {
listDashboards: (): string => "/grafana/dashboards",
getDashboard: (uid: string): string => `/grafana/dashboards/${seg(uid)}`,
},2. Crea src/tools/grafana.ts siguiendo el mismo molde que los demás:
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. Regístralo en TOOL_REGISTRARS de src/server.ts:
const TOOL_REGISTRARS = [ …, registerGrafanaTools ];Eso es todo. registerEngTool ya te da gratis: validación Zod, formateo de la respuesta, truncado de payloads enormes, captura de errores y traducción a mensajes accionables, y logging con requestId.
Reglas de estilo para tools nuevos:
Nombre
servicio_accion_objeto, en minúsculas.Cada campo del schema con
.describe()y un ejemplo concreto — es lo único que el modelo lee para decidir cómo llamarlo.Anotaciones honestas: si escribe,
readOnlyHint: false; si puede borrar algo,destructiveHint: true.Nada de defaults peligrosos en operaciones destructivas: exige identificadores exactos.
Paginación (
...paginationShape+paginationQuery(args)) en todo lo que devuelva listas.Nunca construyas URLs a mano en
tools/: siempre a través deengApiRoutes.
10. Manejo de errores
Ningún tool devuelve un "Error 500" pelado. Cada error incluye qué falló, qué revisar y un requestId para cruzarlo con los logs de eng-api. Ejemplo real:
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"}Situación | Qué hace el MCP Server |
Timeout / error de red | Reintenta con backoff exponencial + jitter ( |
| Reintenta (respeta |
| No reintenta: los parámetros son inválidos |
| Aclara que no es tu API key del MCP, sino las credenciales/permisos de eng-api |
| Sugiere verificar identificadores exactos y las rutas de |
| Conflicto de estado (p. ej. un sync de ArgoCD ya en curso): consulta el estado y reintenta luego |
Respuesta no-JSON | Suele ser un proxy devolviendo HTML: la ruta probablemente no existe |
Payload gigante | Se trunca a 120 000 caracteres con un aviso para reducir |
11. Estructura del proyecto
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.tsDecisiones de diseño:
Streamable HTTP en modo stateless (
sessionIdGenerator: undefined,enableJsonResponse: true): se crea unMcpServer+ transport por petición. Sin estado compartido entre devs, sin sticky sessions, escala horizontalmente y las respuestas son JSON plano (más amables con ingress/proxies que SSE).Solo
POST /mcp:GET/DELETEresponden405, porque en stateless no hay stream servidor→cliente ni sesión que cerrar.Trazabilidad: cada petición lleva un
X-Request-Id(se respeta el del cliente si lo manda) y unX-Mcp-Devcon la etiqueta del dev, ambos propagados a 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