mcp-server-base
MCP Server Base v3.0 — Escala y Empresa (2026)
Servidor moderno de Model Context Protocol que utiliza el stack más reciente:
MCP SDK
1.12+— API de alto nivelMcpServer+StreamableHTTPServerTransport(nuevo) yStdioServerTransportTypeScript 5.7 ESM + módulo
NodeNextZod validación → JSON Schema automático + validación de entorno (
src/config.ts:1)Express 4 + helmet + CORS allowlist + rate-limit + health/ready + Admin UI
Transporte dual: STDIO (Claude Desktop) y Streamable HTTP (remoto, especificación 2025-03, sin estado + reanudación con estado mediante RedisEventStore)
Módulos estructurados de herramientas/recursos/prompts + RAG híbrido (BM25+vector), Web (con caché), integraciones GitHub
Plugin SDK (
src/plugin/index.ts:1) + integraciones (slack/notion/linear), Registry (smithery.yaml, mcpName), Prompt Playground en/adminv3.0 Enterprise: Multi-tenant (
X-Tenant-Id, almacenes con espacios de nombres), SSO OIDC, CRUD de plano de control, modo clúster, stack Prometheus/GrafanaOTEL trazado/métricas (
src/utils/otel.ts:1), Tasks (experimental +create_task), pruebas de carga k6tsxwatch,vitest(178 pruebas, 88% cobertura), apagado elegante,docker-compose(redis, postgres, qdrant, otel-collector, prometheus, grafana)
🚀 Inicio rápido
npm install
npm run build
# STDIO (for Claude Desktop, Cursor, opencode, etc.)
npm start
# HTTP (Streamable HTTP - latest)
npm run start:http
# → http://localhost:3000/mcp
# → health http://localhost:3000/healthDev
npm run dev # stdio watch
npm run dev:http # http watch (Streamable HTTP at http://localhost:3000/mcp)
npm test # unit + e2e (InMemory + HTTP)
npm run test:coverage # coverage 80% thresholds
npm run lint # eslint 9 flat config
npm run format:check # prettier
npm run typecheck # tsc --noEmit
npm run buildCI
.github/workflows/ci.yml se ejecuta en push/PR a main con matriz Node 20+22: lint, format:check, typecheck, test:coverage, build, docker build.
Related MCP server: TokenHub MCP
🔌 Transportes
Transporte | Uso | Comando |
STDIO | Clientes locales (Claude Desktop) |
|
Streamable HTTP | Remoto / Docker / Cloud |
|
Streamable HTTP es el nuevo estándar que reemplaza a SSE (obsoleto desde marzo de 2025).
🧰 Herramientas (40)
Herramienta | Descripción | Entrada |
| Mensaje de eco |
|
| add/sub/mul/div |
|
| Hora actual |
|
| Obtener URL |
|
| Listar archivos bajo ALLOWED_ROOT |
|
| Leer archivo (límite 1MB) |
|
| Escribir archivo + activa recurso cambiado |
|
| Buscar texto dentro de archivos |
|
| Establecer KV en memoria |
|
| Obtener KV |
|
| Eliminar KV |
|
| Listar KVs | — |
| Borrar todo | — |
| SQL mediante alasql (users, notes) |
|
| Listar recuentos de filas de tablas | — |
| Shell (lista blanca, deshabilitado por defecto) |
|
| Demo de elicitación (contacto/preferencias) |
|
| Demo de muestreo (LLM) |
|
| Ingerir texto (fragmentado, incrustado) |
|
| Búsqueda híbrida (vector+BM25) |
|
| Listar documentos | — |
| Limpiar almacén de vectores | — |
| API Brave (simulado si no hay clave) |
|
| API Tavily (simulado si no hay clave) |
|
| Obtención web con caché |
|
| Búsqueda de repositorios en GitHub |
|
| Obtener repositorio de GitHub |
|
| Obtener issue de GitHub |
|
| Crear tarea en segundo plano |
|
| Obtener estado de la tarea |
|
| Obtener resultado de la tarea |
|
| Canales de Slack (plugin) | — |
| Publicar en Slack (plugin) |
|
| Búsqueda en Slack (plugin) |
|
| Búsqueda en Notion (plugin) |
|
| Página de Notion (plugin) |
|
| Crear en Notion (plugin) |
|
| Issues de Linear (plugin) |
|
| Crear en Linear (plugin) |
|
| Issue de Linear (plugin) |
|
📦 Recursos (6)
config://server-info— metadatos del servidor (JSON, ahora incluyefeatures)greeting://{name}— plantilla de saludo dinámicafile:///{+path}— archivo en sandbox (ALLOWED_ROOT), listar + completar,file:///notes.txtmemory://{key}— KV de memoria, listar + completardb://{table}/{id}— fila de BD de demostración (users/notes), listar + completardocs://{id}— fragmento RAG (ingerido medianterag_ingest), listar + completar
💬 Prompts (4)
code-review— argumentos:language,codeexplain-concept— argumentos:concept,levelsummarize— argumentos:text,length(short/medium/long),style(bullets/paragraph/tldr)research— argumentos:topic,depth(overview/deep),audience(beginner/expert/executive)
⚙️ Configuración del cliente
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"mcp-server-base": {
"command": "node",
"args": ["/absolute/path/to/mcp-server/dist/index.js"]
}
}
}Cliente HTTP
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
const client = new Client({ name: 'my-client', version: '1.0.0' });
await client.connect(new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp')));
const tools = await client.listTools();Inspector
npm run inspect
# or
npx @modelcontextprotocol/inspector node dist/index.js
npx @modelcontextprotocol/inspector http://localhost:3000/mcp🐳 Docker
# Single container
docker build -t mcp-server-base .
docker run -p 3000:3000 --env TRANSPORT=http mcp-server-base
# Full stack (app + redis + postgres + qdrant) — see docker-compose.yml
docker compose up -d
docker compose logs -f app
# → http://localhost:3000/health, http://localhost:3000/mcp
# → redis :6379, postgres :5432, qdrant :6333Demo RAG (ingerir → buscar → docs://)
# via MCP tools (Inspector or Client)
# 1. ingest
rag_ingest { "text": "MCP is Model Context Protocol...", "id": "mcp-intro" }
# 2. search
rag_search { "query": "what is MCP?", "topK": 3 }
# 3. read resource
# docs://mcp-intro → returns ingested text📁 Estructura
src/
├── index.ts # entry: stdio + http (helmet/cors/rateLimit/auth/RBAC/OTEL/metrics)
├── server.ts # createMcpServer() factory (v2.1.0, instructions)
├── config.ts # zod env (AUTH, CORS, rateLimit, RAG, cache, integrations, OTEL, admin, tasks)
├── types.ts # Zod schemas
├── middleware/auth.ts # AUTH_MODE none|apiKey|bearer
├── middleware/rateLimit.ts
├── middleware/requestId.ts
├── middleware/rbac.ts # RBAC reader/writer/admin + mcpRbacMiddleware (v2.1)
├── observability/otel-real.ts # OTEL NodeSDK init (v2.1)
├── observability/slo.ts # checkSlo() for /health/ready (v2.1)
├── utils/logger.ts # stderr, JSON/text, redaction, child(requestId)
├── utils/eventStore.ts # InMemoryEventStore
├── utils/redisEventStore.ts # RedisEventStore (scale)
├── utils/cache.ts # MemoryCache (TTL) + defaultCache
├── utils/queue.ts # SimpleQueue
├── utils/metrics.ts # prom-client Registry (v2.1)
├── utils/persistence.ts # save/load backup (v2.1)
├── utils/otel.ts # stub OTEL spans/metrics
├── tools/ # 40 tools: echo, fs, memory, db, shell, rag (hybrid), web, github, elicitation, sampling, tasks
│ ├── filesystem.tool.ts, memory.tool.ts, database.tool.ts, shell.tool.ts
│ ├── rag.tool.ts, web.tool.ts, github.tool.ts, elicitation.tool.ts, sampling.tool.ts, tasks.tool.ts
├── plugin/index.ts # Plugin SDK: definePlugin/registerPlugin (v2.2)
├── integrations/ # slack/notion/linear plugins (v2.2)
├── middleware/tenant.ts # Multi-tenant X-Tenant-Id + scoped stores (v3.0)
├── routes/controlplane.ts# Tenants CRUD + key rotation (v3.0)
├── utils/cluster.ts # Cluster mode horizontal scale (v3.0)
├── resources/ # 6 resources: config, greeting, file, memory, db, docs
├── routes/admin.ts # Admin UI + metrics/spans/stores (v2.0) + /metrics Prometheus (v2.1)
└── prompts/ # 4 prompts: code-review, explain-concept, summarize, researchPara añadir una nueva herramienta: crea src/tools/my.tool.ts → exporta registerMyTool(server) → añádela a src/tools/index.ts.
🔐 Seguridad (Fase 2)
Helmet cabeceras (
x-dns-prefetch-control,x-frame-options,x-content-type-options, etc.) mediantehelmet@7(src/index.ts:1)CORS allowlist (
CORS_ORIGIN=*o lista separada por comas) con manejo de credencialescors(src/config.ts:60)Autenticación
AUTH_MODE=none|apiKey|bearerensrc/middleware/auth.ts:1—401sinX-API-Keyválida oAuthorization: Bearer(health/ready y OPTIONS excluidos)Limitación de tasa
express-rate-limit(por defecto 100/15min) en/mcp—429 Too Many Requests(src/middleware/rateLimit.ts:1)RequestId (
X-Request-IdrandomUUID, cabecera de eco, correlación de registros secundarios) (src/middleware/requestId.ts:1)Validación de entorno Zod (
src/config.ts:1) —parseEnv()validaPORT,AUTH_MODE,API_KEYentre campos, falla rápido en entorno no válidoRegistro estructurado JSON/texto,
[REDACTED]paraauthorization,apiKey,token(src/utils/logger.ts:24)Reanudación
InMemoryEventStore(src/utils/eventStore.ts:1) + mapa de sesiones con estado cuandoRESUMABILITY_ENABLED=true(reproducción medianteLast-Event-ID,GET /mcpstream,DELETEcierre)Endurecimiento de Docker
appuserno root +HEALTHCHECK(Dockerfile:1)Pruebas:
tests/unit/auth.test.ts,tests/unit/logger.test.ts,tests/unit/eventStore.test.ts,tests/e2e/security.test.ts(helmet/auth/rateLimit/resumability) —67 pruebas → 130 total con Fase 5, 90.89% cobertura
🔗 Integraciones (Fase 4)
Caché
MemoryCacheTTL (src/utils/cache.ts:1) —defaultCachepara web/github,SimpleQueue(src/utils/queue.ts:1)RAG vector local (hash embedding 128-dim, coseno, fragmento 500/50) en
src/tools/rag.tool.ts:1—rag_ingest(fragmentado +sendResourceListChanged),rag_search(topK, threshold),rag_list,rag_clear+ recursodocs://{id}Web
src/tools/web.tool.ts:1—brave_search(simulado si no hayBRAVE_API_KEY),tavily_search(simulado),web_fetch(con caché mediantedefaultCache,CACHE_TTL_MS)GitHub
src/tools/github.tool.ts:1—github_search_repos,github_get_repo,github_get_issue(con caché,GITHUB_TOKENpara límite de tasa)Stack
docker-compose.yml:1(app + redis:7 + postgres:16 + qdrant:v1.12.4) con healthchecksDemo
rag_ingest → rag_search → docs://E2E verificado entests/integrations.test.ts:1(21 pruebas)
🏢 Escala y Empresa (Fase 5 — v3.0) — NUEVO
Multi-tenant
src/middleware/tenant.ts:1— cabeceraX-Tenant-Id(o?tenant=),tenantMiddlewarerechaza400cuandoTENANT_REQUIRED=truey falta, memoria con ámbito de tenantgetTenantMemory(tid)(almacenes aislados), claves de caché con espacio de nombrestenant:{id}:key, registrocreateTenant/deleteTenantSSO OIDC
src/middleware/auth.ts:1—AUTH_MODE=oidc: validación estructural de JWT Bearer (3 partes,exp,issvsOIDC_ISSUER,audvsOIDC_AUDIENCE), claims adjuntados areq.oidcClaims; en producción se intercambia por verificación de firma JWKSPlano de control
src/routes/controlplane.ts:1— CRUD/admin/tenants(POST/GET/PATCH/DELETE+ 409 duplicado/400 id inválido),POST /admin/tenants/:id/rotate-key,GET /admin/tenants/:id/storeinspección de aislamiento; protegido por token de administradorEscalado en tiempo de ejecución
src/utils/cluster.ts:1—initCluster()bifurcaCLUSTER_WORKERS(por defecto CPU-1), reinicio automático al salir el worker,CLUSTER_MODE=true; sin estado +RedisEventStorepara escalado horizontal realPila de monitoreo
docker-compose.override.yml:1— Prometheus (prometheus.ymlrecopilaapp:3000/metrics) en :9090 + Grafana en :3001Pruebas
tests/v3_0.test.ts:1(15 pruebas: extracción/aislamiento de tenant/requerido-400, validación de token OIDC + emisor/audiencia + HTTP 401/200, ciclo de vida del plano de control 201/409/400/404/rotate-key/inspección de almacén/deshabilitado-404, cluster no-op, servicios de compose) — total 178
🔌 Ecosistema y DX (Fase 5 — v2.2)
SDK de plugins
src/plugin/index.ts:1—definePlugin({name, version, register}),registerPlugin(server, plugin)(tolerante a duplicados),getRegisteredPlugins(), notificaciones automáticassendToolListChangedIntegraciones
src/integrations/—slackPlugin(listar/publicar/buscar),notionPlugin(buscar/obtener/crear),linearPlugin(listar/crear/obtener) — todos simulados sin tokens (SLACK_TOKEN,NOTION_TOKEN); auto-registrados ensrc/server.ts:1Registro
smithery.yaml:1— configuración de Smithery + nombre del Registro MCPio.github.ahmedalbanna/mcp-server-base, camposmcpName/filesenpackage.json:1RAG híbrido
src/tools/rag.tool.ts:1— modosrag_searchvector|bm25|hybrid(por defecto hybrid, alpha 0.5), BM25 (k1=1.5, b=0.75) normalizado + re-clasificación por coseno; conjunto de evaluacióntests/eval/rag-eval.json(20 Q/A) con p@5 ≥0.8 verificado entests/v2_2.test.ts:1Prompt Playground
src/routes/admin.ts:1—POST /admin/prompts/:name/previewrenderiza prompts en el servidor; interfaz de playground en el panel/adminPruebas
tests/v2_2.test.ts:1(16 pruebas: SDK de plugins define/register/dup/herramientas invocables, archivos de registro, modos híbridos, evaluación p@5, vista previa/UI/contador de playground) — total 163
📈 Escalado y Operabilidad (Fase 5 — v2.0)
MCP versionado
v2.0.0(package.json:1,config.MCP_SERVER_VERSION) con instrucciones por versión menor (src/server.ts:1)OTEL trazado/métricas (
src/utils/otel.ts:1) —createSpan/withSpan,incrementCounter/recordHistogram,getMetrics/getSpans, stub de exportación JSON paraOTEL_EXPORTER_OTLP_ENDPOINT, banderaOTEL_ENABLEDRedisEventStore (
src/utils/redisEventStore.ts:1) — implementación deEventStoreconstoreEvent/replayEventsAfter, respaldo en memoria,eventStoreFactory.create()para escalado horizontal (EVENT_STORE_TYPE=memory|redis,REDIS_URL)Interfaz de administración (
src/routes/admin.ts:1) —GET /admin(panel HTML),/admin/tools|resources|prompts|metrics|spans|stores|health(JSON), protegido medianteADMIN_TOKEN(X-Admin-Token), banderaADMIN_ENABLEDTareas (
src/tools/tasks.tool.ts:1) —delay_taskexperimental (si hay tareas SDK disponibles) + respaldocreate_task/get_task/get_task_result(en memoria, sondeo), infraestructuraSimpleQueue/MemoryCacheBench
k6/load.js:1—http_req_duration p(95)<100ms,stages10→50 VUs,checks >99%,npm run bench/bench:localCompose
docker-compose.yml:1ya incluye redis/postgres/qdrant para escaladoPruebas:
tests/scale.test.ts:1(spans/métricas OTEL, reproducción de RedisEventStore, TTL de caché, cola, HTML/métricas/token/ready de administración, creación/sondeo de tareas, versión, script k6) — 130 en total (ahora 147 con v2.1)Despliegue listo para Fly.io/Cloud Run (sin estado + RedisEventStore), GHCR mediante
release.yml, npm2.0.0
🔒 Endurecimiento y Observabilidad (Fase 5 — v2.1) — NUEVO
OTEL Real
src/observability/otel-real.ts:1—initOtel()importación dinámica de@opentelemetry/sdk-node+OTLPTraceExporter(respaldo de consola),OTEL_ENABLED+OTEL_EXPORTER_OTLP_ENDPOINT,shutdownelegante en SIGTERMSLOs
src/observability/slo.ts:1—checkSlo()(memoria/rag/caché/tiempo de actividad,latencyMs),GET /health→{status, checks, uptime, version, otel, eventStore}+GET /ready→503si no esok,GET /metrics→ Prometheustext/plainmedianteprom-client(mcp_http_requests_total,mcp_http_request_duration_ms,mcp_sessions_active)RBAC
src/middleware/rbac.ts:1—reader < writer < admin(cabeceraX-Role, stub JWT), mapaTOOL_ROLES(31 herramientas),mcpRbacMiddlewareinspecciona el cuerpo detools/call→403sireaderintentawrite_file/shell_execute,GET /admin→ requiereadminRespaldo
src/utils/persistence.ts:1—saveBackup()/loadBackup()/scheduleSave()(debounce de 500ms) aALLOWED_ROOT/.backup.json(getBackupFile()dinámico), registra stub de sincronización Redis cuandoREDIS_URLestá configurado,loadBackup()al inicio ensrc/index.ts:1Métricas
src/utils/metrics.ts:1—Registrydeprom-client+collectDefaultMetrics,httpRequestsTotal/httpRequestDuration/mcpToolCallsTotal/mcpSessionsActive, manejadorGET /metricsPruebas
tests/v2_1.test.ts:1(13 pruebas: comprobaciones SLO, RBAChasRole/X-Role403/200,SLO health/metrics200 + texto Prometheus, span OTEL, guardar/cargar respaldo +scheduleSavemediantememory_set,initOteldeshabilitado/habilitado) +tests/unit/rbac.test.ts:1(4 pruebas) — total 147Logger seguro para stderr, nunca registra secretos (redacción)
Zod → JSON Schema mediante SDK (
src/types.ts:1,src/tools/*.tool.ts)Tiempo de espera en fetch (10s) + errores estructurados
Apagado elegante (
SIGINT/SIGTERM)Health (
GET /health) y ready (GET /ready) separados de MCPSin estado por defecto (
sessionIdGenerator: undefined), con estado cuandoRESUMABILITY_ENABLED=true(src/index.ts:22)Type-safe, TS estricto + ESLint flat + Prettier + husky + lint-staged
Cobertura 85% líneas / 70% ramas aplicada (
vitest.config.ts:1), 178 pruebas: unitarias + e2e HTTP/seguridad/capacidades/integraciones/escalado/v2.1/v2.2/v3.0
📚 Documentación
Documentación completa en docs/:
Arquitectura — diagrama, mapa de módulos, ciclo de vida de solicitudes
Configuración — cada variable de entorno + reglas de validación
Referencia de API — herramientas/recursos/prompts/endpoints
Seguridad — autenticación, RBAC, OIDC, tenencia, lista de verificación de endurecimiento
Plugins — guía del SDK de plugins + distribución de registro
Despliegue — Docker, escalado de clúster/multi-réplica, monitoreo, k6
Pruebas — mapa de suites, patrones, CI
🤝 Contribuciones
Consulta CONTRIBUTING.md — nvm use, npm test, añade herramienta/recurso/prompt, asegúrate de que lint/typecheck/test pasen. Consulta CODE_OF_CONDUCT.md.
📚 Documentación de MCP
This server cannot be deployed
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
A Model Context Protocol server for Wix AI tools
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceA robust server implementing the Model Context Protocol with SSE and STDIO transport, enabling real-time communication and extensible tooling for AI models.402 npm4MIT
- AlicenseBqualityCmaintenanceA production-packaged Model Context Protocol server for coding agents that routes large file, git, web, database, and other tasks through token-budgeted tools and workflows.62 npm1MIT
- AlicenseNot gradedqualityDmaintenanceA production-ready Model Context Protocol suite over Streamable HTTP providing a sandboxed file server with tools, resources, prompts, and both manual and AI-driven clients.MIT
- AlicenseBqualityCmaintenanceEnables running a Model Context Protocol server with a validated echo tool over stdio or Streamable HTTP, including strict schemas, tests, and hardened container deployment.11MIT