mcp-server
mcp-server
MCP-сервер на TypeScript, который предоставляет инженерные инструменты команды — Bitbucket, Jira, Confluence и ArgoCD — редакторам с поддержкой MCP (VS Code + Copilot, Claude Code и т.д.).
Это тонкая обёртка: он не общается напрямую с Bitbucket/Jira/Confluence/ArgoCD и не хранит учётные данные этих сервисов. Всё транслируется в HTTP-вызовы внутреннего бэкенда eng-api, который уже имеет настроенные соединения и учётные данные.
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. Только API-ключ этого MCP-сервера, отзываемый индивидуально.
1. Требования
Node.js ≥ 22
Сетевой доступ к
ENG_API_BASE_URL(URL eng-api)
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Другие команды:
Команда | Что делает |
| Запуск в режиме watch с чтением |
| Компиляция TypeScript в |
| Проверка типов без сборки |
| Запуск скомпилированного кода (использует переменные окружения; то, что работает в поде) |
| Запуск скомпилированного кода с чтением |
Быстрая проверка, что сервер работает:
curl http://localhost:3000/healthz
# {"status":"ok","server":"mcp-server","version":"0.1.0"}3. Конфигурация (.env)
Все переменные читаются из process.env. Если обязательная переменная отсутствует или имеет недопустимое значение, процесс не запускается и объясняет, что именно нужно исправить.
Переменная | Обязательная | По умолчанию | Описание |
| ✅ | — | Базовый URL eng-api, без косой черты в конце. Должен быть |
| ✅ | — | Допустимые API-ключи разработчиков для этого MCP-сервера (см. §4) |
| — |
| Тайм-аут на один вызов eng-api (1000–120000) |
| — |
| Дополнительные повторные попытки при 5xx/429/тайм-ауте (0–5) |
| — |
| HTTP-порт MCP-сервера |
| — |
|
|
Пример неудачного запуска (намеренно):
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-сервера и независим от того, как 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-сервера и передаётся в 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. Поскольку у каждого разработчика свой ключ, это не влияет на остальных. В production храните значение в Secret Kubernetes, никогда в 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 в вашем workspace (или пользовательский 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, и вы увидите 11 инструментов под сервером eng.
Для 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В UI Inspector:
Transport Type:
Streamable HTTPURL:
http://localhost:3000/mcpВ Authentication укажите Header Name
Authorizationи Bearer Token с вашим API-ключомConnect → вкладка Tools → List Tools → протестируйте любой
Также можно протестировать напрямую через curl (полезно в CI или из пода):
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/ + зависимости production, запускается от пользователя node (без root) и включает HEALTHCHECK, который обращается к /healthz через сам Node (без curl/wget).
Для Kubernetes (манифесты не в этом репозитории):
Сервер stateless: не хранит сессии в памяти, поэтому масштабируется до 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. Зарегистрируйте его в TOOL_REGISTRARS в src/server.ts:
const TOOL_REGISTRARS = [ …, registerGrafanaTools ];Всё. registerEngTool уже предоставляет бесплатно: валидацию Zod, форматирование ответа, обрезку огромных полезных нагрузок, перехват ошибок и перевод в действенные сообщения, а также логирование с requestId.
Правила стиля для новых инструментов:
Имя
сервис_действие_объект, в нижнем регистре.Каждое поле схемы с
.describe()и конкретным примером — это единственное, что модель читает, чтобы решить, как его вызвать.Честные аннотации: если пишет,
readOnlyHint: false; если может что-то удалить,destructiveHint: true.Никаких опасных значений по умолчанию в деструктивных операциях: требуйте точные идентификаторы.
Пагинация (
...paginationShape+paginationQuery(args)) во всём, что возвращает списки.Никогда не конструируйте URL вручную в
tools/: всегда черезengApiRoutes.
10. Обработка ошибок
Ни один инструмент не возвращает голую ошибку "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 Server |
Тайм-аут / ошибка сети | Повторяет с экспоненциальной задержкой + джиттер ( |
| Повторяет (учитывает |
| Не повторяет: параметры недействительны |
| Уточняет, что это не ваш API-ключ MCP, а учётные данные/разрешения 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 в stateless-режиме (
sessionIdGenerator: undefined,enableJsonResponse: true): создаётсяMcpServer+ transport на каждый запрос. Нет общего состояния между разработчиками, нет sticky sessions, горизонтальное масштабирование, ответы — простой JSON (более дружелюбны к ingress/прокси, чем SSE).Только
POST /mcp:GET/DELETEотвечают405, потому что в stateless нет потока сервер→клиент или сессии для закрытия.Отслеживаемость: каждый запрос содержит
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