mcp-server
mcp-server
MCP Server in TypeScript, der die Engineering-Tools des Teams – Bitbucket, Jira, Confluence und ArgoCD – für Editoren mit MCP-Unterstützung (VS Code + Copilot, Claude Code, etc.) bereitstellt.
Es ist eine dünne Schicht (Thin Wrapper): Es kommuniziert nicht direkt mit Bitbucket/Jira/Confluence/ArgoCD und speichert keine Anmeldedaten für diese Dienste. Alles wird in HTTP-Aufrufe gegen das interne Backend eng-api übersetzt, das bereits Verbindungen und Anmeldedaten verwaltet.
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 devVorteil: Kein Entwickler benötigt persönliche Tokens für Bitbucket/Jira/Confluence/ArgoCD. Nur ein API-Key dieses MCP Servers, der individuell widerrufbar ist.
1. Voraussetzungen
Node.js ≥ 22
Netzwerkzugriff auf
ENG_API_BASE_URL(die URL von eng-api)
Related MCP server: Work Integrations MCP
2. Lokal ausführen
npm ci
cp .env.example .env # y rellena los valores (ver sección 3)
npm run dev # hot-reload, lee .env automáticamenteAndere Befehle:
Befehl | Beschreibung |
| Startet im Watch-Modus und liest |
| Kompiliert TypeScript nach |
| Type-Check ohne Ausgabe |
| Startet das Kompilierte (nutzt Umgebungsvariablen; läuft so im Pod) |
| Startet das Kompilierte und liest |
Schnelle Prüfung, ob der Server läuft:
curl http://localhost:3000/healthz
# {"status":"ok","server":"mcp-server","version":"0.1.0"}3. Konfiguration (.env)
Alle Variablen werden aus process.env gelesen. Fehlt eine Pflichtvariable oder hat einen ungültigen Wert, startet der Prozess nicht und erklärt genau, was zu korrigieren ist.
Variable | Pflicht | Standard | Beschreibung |
| ✅ | — | Basis-URL von eng-api, ohne abschließenden Schrägstrich. Muss |
| ✅ | — | Gültige API-Keys der Entwickler für diesen MCP Server (siehe §4) |
| — |
| Timeout pro Aufruf von eng-api (1000–120000) |
| — |
| Zusätzliche Wiederholungsversuche bei 5xx/429/Timeout (0–5) |
| — |
| HTTP-Port des MCP Servers |
| — |
|
|
Beispiel für einen fehlgeschlagenen Start (absichtlich):
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. Authentifizierung: ein API-Key pro Entwickler
Diese Auth-Schicht ist eigenständig für den MCP Server und unabhängig von der, die eng-api gegenüber den Enddiensten verwendet.
Schlüssel generieren
openssl rand -hex 32 # una por cada persona del equipoKonfigurieren
MCP_DEV_API_KEYS akzeptiert vier Formate (mindestens 24 Zeichen pro Key, keine Duplikate):
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 objetoVerwende das beschriftete Format: Die Bezeichnung erscheint in den Logs des MCP Servers und wird an eng-api im Header X-Mcp-Dev weitergegeben, sodass nachvollziehbar ist, wer welche Operation ausgelöst hat (z. B. ein argocd_sync_app), ohne den Key offenzulegen.
Verwendung
Der MCP-Client muss bei jeder Anfrage senden:
Authorization: Bearer <API_KEY>(oder alternativ x-api-key: <API_KEY>). Der Vergleich erfolgt timing-sicher über SHA-256-Digests.
Situation | Antwort |
Ohne Key |
|
Ungültiger/widerrufener Key |
|
| Keine Authentifizierung (für Kubernetes-Probes) |
Jemanden widerrufen = seinen Key aus MCP_DEV_API_KEYS entfernen und das Deployment neu starten. Da jeder Entwickler seinen eigenen hat, hat dies keine Auswirkungen auf die anderen. In Produktion den Wert in einem Kubernetes-Secret speichern, niemals in einem ConfigMap.
5. Tool-Katalog
Die Namen haben einen Dienstpräfix und sind handlungsorientiert. Alle unterstützen Paginierung, wo zutreffend (page, pageSize von 1 bis 100, standardmäßig 25).
Bitbucket (schreibgeschützt)
Tool | Argumente | Eng-API-Endpunkt |
|
|
|
|
|
|
|
|
|
Jira
Tool | Argumente | Eng-API-Endpunkt |
|
|
|
|
|
|
|
|
|
Confluence (schreibgeschützt)
Tool | Argumente | Eng-API-Endpunkt |
|
|
|
|
|
|
ArgoCD
Tool | Argumente | Eng-API-Endpunkt |
|
|
|
|
|
|
|
|
|
Annotationen (Hinweise für den MCP-Client)
Tool |
|
|
|
|
Alle Lese-Tools | ✅ | ❌ | ✅ | ✅ |
| ❌ | ❌ | ❌ | ✅ |
| ❌ | ✅ | ❌ | ✅ |
argocd_sync_app erfordert den exakten Namen der App (keine Platzhalter oder Standardwerte) und prune/dryRun stehen auf false, es sei denn, sie werden explizit angefordert.
Die Routen von eng-api befinden sich alle in src/client/routes.ts. Wenn eng-api einen Pfad ändert, wird nur diese Datei angepasst.
6. VS Code konfigurieren (jeder Entwickler mit seinem eigenen Key)
Erstelle .vscode/mcp.json in deinem Workspace (oder die benutzerspezifische mcp.json, wenn du sie für alle Projekte haben möchtest):
{
"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 fragt beim ersten Mal nach dem Key und speichert ihn verschlüsselt; wird niemals committet. Öffne anschließend den Chat im Agent-Modus und du siehst die 11 Tools unter dem Server eng.
Für Claude Code (CLI) lautet das Äquivalent:
claude mcp add --transport http eng https://<host-del-mcp-server>/mcp \
--header "Authorization: Bearer <TU_API_KEY>"Lokal ersetze die URL durch http://localhost:3000/mcp.
7. Testen mit MCP Inspector
npm run build && npm run start:local # en una terminal
npx @modelcontextprotocol/inspector # en otraIn der UI des Inspectors:
Transport Type:
Streamable HTTPURL:
http://localhost:3000/mcpBei Authentication setze Header Name auf
Authorizationund den Bearer Token auf deinen API-KeyConnect → Tab Tools → List Tools → teste eines aus
Man kann auch direkt mit curl testen (nützlich in CI oder von einem Pod aus):
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'Ein Tool aufrufen:
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.0Multi-Stage-Image basierend auf node:22-alpine: Das finale Image enthält nur dist/ + Produktionsabhängigkeiten, läuft als Benutzer node (ohne Root) und enthält einen HEALTHCHECK, der /healthz mit Node selbst aufruft (ohne curl/wget).
Für Kubernetes (die Manifests befinden sich nicht in diesem Repo):
Der Server ist zustandslos: Er speichert keine Sitzungen im Arbeitsspeicher, sodass er auf N Replikate ohne Sticky Sessions skaliert.
Probes:
livenessProbe→GET /healthz,readinessProbe→GET /readyz(beide ohne Authentifizierung).MCP_DEV_API_KEYSkommt in einSecret;ENG_API_BASE_URLund die Timeouts können in einConfigMap.Behandelt
SIGTERM, indem es den HTTP-Server anmutig herunterfährt (maximal 10 s Drain-Zeit).
9. Hinzufügen eines neuen Dienstes oder Tools
Das Muster ist so ausgelegt, dass das Hinzufügen eines Dienstes nichts Bestehendes berührt. Beispiel mit einem hypothetischen Grafana:
1. Füge seine Routen in src/client/routes.ts hinzu:
grafana: {
listDashboards: (): string => "/grafana/dashboards",
getDashboard: (uid: string): string => `/grafana/dashboards/${seg(uid)}`,
},2. Erstelle src/tools/grafana.ts nach dem gleichen Schema wie die anderen:
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. Registriere es in TOOL_REGISTRARS in src/server.ts:
const TOOL_REGISTRARS = [ …, registerGrafanaTools ];Das war's. registerEngTool bietet dir kostenlos: Zod-Validierung, Formatierung der Antwort, Kürzung großer Payloads, Fehlererfassung und Übersetzung in handlungsorientierte Meldungen sowie Logging mit requestId.
Styleregeln für neue Tools:
Name
servicio_accion_objeto, in Kleinbuchstaben.Jedes Schema-Feld mit
.describe()und einem konkreten Beispiel – das ist das Einzige, was das Modell liest, um zu entscheiden, wie es aufgerufen wird.Ehrliche Annotationen: Wenn es schreibt,
readOnlyHint: false; wenn es etwas löschen kann,destructiveHint: true.Keine gefährlichen Standardwerte bei destruktiven Operationen: erfordere exakte Kennungen.
Paginierung (
...paginationShape+paginationQuery(args)) bei allem, was Listen zurückgibt.Erstelle niemals URLs manuell in
tools/: immer überengApiRoutes.
10. Fehlerbehandlung
Kein Tool gibt einen nackten "Error 500" zurück. Jeder Fehler enthält was fehlgeschlagen ist, was zu überprüfen ist und eine requestId, um ihn mit den Logs von eng-api abzugleichen. Reales Beispiel:
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"}Situation | Verhalten des MCP Servers |
Timeout / Netzwerkfehler | Wiederholt mit exponentiellem Backoff + Jitter ( |
| Wiederholt (beachtet |
| Keine Wiederholung: die Parameter sind ungültig |
| Stellt klar, dass es nicht dein MCP-API-Key ist, sondern die Anmeldedaten/Berechtigungen von eng-api |
| Schlägt vor, die genauen Identifikatoren und die Pfade in |
| Statuskonflikt (z.B. ein bereits laufender ArgoCD-Sync): Status abfragen und später erneut versuchen |
Nicht-JSON-Antwort | Meistens ein Proxy, der HTML zurückgibt: Der Pfad existiert wahrscheinlich nicht |
Riesige Payload | Wird auf 120.000 Zeichen gekürzt mit einem Hinweis, |
11. Projektstruktur
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.tsDesignentscheidungen:
Streamable HTTP im stateless-Modus (
sessionIdGenerator: undefined,enableJsonResponse: true): Pro Anfrage wird einMcpServer+ Transport erstellt. Kein gemeinsamer Zustand zwischen Entwicklern, keine Sticky Sessions, horizontale Skalierung und die Antworten sind reines JSON (freundlicher zu Ingress/Proxies als SSE).Nur
POST /mcp:GET/DELETEantworten mit405, da es im stateless-Modus keinen Server→Client-Stream und keine zu schließende Sitzung gibt.Nachverfolgbarkeit: Jede Anfrage enthält eine
X-Request-Id(die des Clients wird respektiert, falls gesendet) und einenX-Mcp-Dev-Header mit dem Entwickler-Tag, beide werden an eng-api weitergegeben.
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