mcp-server
Provides tools for ArgoCD application management, including listing applications, getting application status, and triggering application syncs.
Provides read-only tools for Bitbucket repositories, including listing pull requests, retrieving pull request details, and fetching commits.
Offers read-only access to Confluence, enabling search for pages and retrieval of page content in various formats.
Allows searching Jira issues with JQL or simple filters, retrieving issue details with optional comments, and creating new issues.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-servershow me the open pull requests in my Bitbucket repo"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server
MCP Server in TypeScript that exposes the team's engineering tools —Bitbucket, Jira, Confluence and ArgoCD— to editors with MCP support (VS Code + Copilot, Claude Code, etc.).
It is a thin wrapper: it does not talk to Bitbucket/Jira/Confluence/ArgoCD, nor does it store credentials for those services. It translates everything into HTTP calls against the internal backend eng-api, which already has connections and credentials resolved.
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 devAdvantage: no dev needs personal tokens for Bitbucket/Jira/Confluence/ArgoCD. Only an API key for this MCP Server, individually revocable.
1. Requirements
Node.js ≥ 22
Network access to
ENG_API_BASE_URL(the eng-api URL)
Related MCP server: Work Integrations MCP
2. Run locally
npm ci
cp .env.example .env # y rellena los valores (ver sección 3)
npm run dev # hot-reload, lee .env automáticamenteOther commands:
Command | What it does |
| Starts in watch mode reading |
| Compiles TypeScript to |
| Type-check without emitting |
| Starts the compiled version (uses environment variables; this is what runs in the pod) |
| Starts the compiled version reading |
Quick check that it's alive:
curl http://localhost:3000/healthz
# {"status":"ok","server":"mcp-server","version":"0.1.0"}3. Configuration (.env)
All variables are read from process.env. If a required one is missing or has an invalid value, the process does not start and explains exactly what to fix.
Variable | Required | Default | Description |
| ✅ | — | Base URL of eng-api, without trailing slash. Must be |
| ✅ | — | Valid API keys for devs against this MCP Server (see §4) |
| — |
| Timeout per call to eng-api (1000–120000) |
| — |
| Additional retries on 5xx/429/timeout (0–5) |
| — |
| HTTP port of the MCP Server |
| — |
|
|
Example of a failed startup (on purpose):
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. Authentication: one API key per dev
This auth layer is specific to the MCP Server and independent of what eng-api uses towards the final services.
Generate keys
openssl rand -hex 32 # una por cada persona del equipoConfigure them
MCP_DEV_API_KEYS accepts four formats (minimum 24 characters per key, no duplicates):
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 objetoUse the tagged format: the tag appears in the MCP Server logs and is propagated to eng-api in the X-Mcp-Dev header, so you can audit who triggered each operation (e.g., an argocd_sync_app) without exposing the key.
Use them
The MCP client must send in each request:
Authorization: Bearer <API_KEY>(or, alternatively, x-api-key: <API_KEY>). The comparison is timing-safe over SHA-256 digests.
Situation | Response |
Without key |
|
Invalid/revoked key |
|
| No auth (for Kubernetes probes) |
Revoke someone = remove their key from MCP_DEV_API_KEYS and restart the Deployment. Since each dev has their own, it does not affect others. In production, store the value in a Kubernetes Secret, never in a ConfigMap.
5. Tool catalog
Names have a service prefix and are action-oriented. All support pagination where applicable (page, pageSize from 1 to 100, default 25).
Bitbucket (read-only)
Tool | Arguments | eng-api endpoint |
|
|
|
|
|
|
|
|
|
Jira
Tool | Arguments | eng-api endpoint |
|
|
|
|
|
|
|
|
|
Confluence (read-only)
Tool | Arguments | eng-api endpoint |
|
|
|
|
|
|
ArgoCD
Tool | Arguments | eng-api endpoint |
|
|
|
|
|
|
|
|
|
Annotations (hints for the MCP client)
Tool |
|
|
|
|
All read-only ones | ✅ | ❌ | ✅ | ✅ |
| ❌ | ❌ | ❌ | ✅ |
| ❌ | ✅ | ❌ | ✅ |
argocd_sync_app requires the exact app name (no wildcards or default values) and prune/dryRun default to false unless explicitly requested.
All eng-api routes live in src/client/routes.ts. If eng-api changes a path, only that file needs to be touched.
6. Configure VS Code (each dev, with their own key)
Create .vscode/mcp.json in your workspace (or the user mcp.json, if you want it in all projects):
{
"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 will ask for the key the first time and store it encrypted; it is never committed. Then, open the chat in Agent mode and you will see the 11 tools under the eng server.
For Claude Code (CLI), the equivalent is:
claude mcp add --transport http eng https://<host-del-mcp-server>/mcp \
--header "Authorization: Bearer <TU_API_KEY>"Locally, replace the URL with http://localhost:3000/mcp.
7. Test it with MCP Inspector
npm run build && npm run start:local # en una terminal
npx @modelcontextprotocol/inspector # en otraIn the Inspector UI:
Transport Type:
Streamable HTTPURL:
http://localhost:3000/mcpIn Authentication, set Header Name to
Authorizationand the Bearer Token to your API keyConnect → Tools tab → List Tools → try any
It can also be tested directly with curl (useful in CI or from a 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'Call a 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.0Multi-stage image on node:22-alpine: the final stage only contains dist/ + production dependencies, runs as user node (no root) and includes a HEALTHCHECK that hits /healthz with Node itself (no curl/wget).
For Kubernetes (manifests are not in this repo):
The server is stateless: it does not store sessions in memory, so it scales to N replicas without sticky sessions.
Probes:
livenessProbe→GET /healthz,readinessProbe→GET /readyz(both without auth).MCP_DEV_API_KEYSgoes in aSecret;ENG_API_BASE_URLand timeouts can go in aConfigMap.Handles
SIGTERMby gracefully shutting down the HTTP server (drain of 10 s max).
9. How to add a new service or tool
The pattern is designed so that adding a service does not touch anything existing. Example with a hypothetical Grafana:
1. Add its routes in src/client/routes.ts:
grafana: {
listDashboards: (): string => "/grafana/dashboards",
getDashboard: (uid: string): string => `/grafana/dashboards/${seg(uid)}`,
},2. Create src/tools/grafana.ts following the same template as the others:
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. Register it in TOOL_REGISTRARS in src/server.ts:
const TOOL_REGISTRARS = [ …, registerGrafanaTools ];That's it. registerEngTool already gives you for free: Zod validation, response formatting, truncation of huge payloads, error capture and translation into actionable messages, and logging with requestId.
Style rules for new tools:
Name
service_action_object, in lowercase.Each schema field with
.describe()and a concrete example — that's the only thing the model reads to decide how to call it.Honest annotations: if it writes,
readOnlyHint: false; if it can delete something,destructiveHint: true.No dangerous defaults in destructive operations: require exact identifiers.
Pagination (
...paginationShape+paginationQuery(args)) on everything that returns lists.Never build URLs by hand in
tools/: always throughengApiRoutes.
10. Error handling
No tool returns a bare "Error 500". Each error includes what failed, what to check and a requestId to cross-reference with eng-api logs. Real example:
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 | What the MCP Server does |
Timeout / network error | Retries with exponential backoff + jitter ( |
| Retries (respects |
| Does not retry: the parameters are invalid |
| Clarifies that it is not your MCP API key, but the eng-api credentials/permissions |
| Suggests verifying exact identifiers and the routes in |
| State conflict (e.g., an ArgoCD sync already in progress): check the state and retry later |
Non-JSON response | Usually a proxy returning HTML: the route probably does not exist |
Giant payload | Truncated to 120,000 characters with a notice to reduce |
11. Project structure
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.tsDesign decisions:
Streamable HTTP in stateless mode (
sessionIdGenerator: undefined,enableJsonResponse: true): aMcpServer+ transport is created per request. No shared state between devs, no sticky sessions, scales horizontally, and responses are plain JSON (kinder to ingress/proxies than SSE).Only
POST /mcp:GET/DELETErespond with405, because in stateless there is no server→client stream or session to close.Traceability: each request carries an
X-Request-Id(respects the client's if sent) and anX-Mcp-Devwith the dev's label, both propagated to 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