Portcall
{"type":"text"}
Portcall
Una pasarela de plugins pequeña que sirve servidores MCP locales a través de HTTP.
El nombre es un juego de palabras náutico: port call — port (puerto / puerto de red) + call (escala de un barco / petición).
Qué es
Portcall escucha en un puerto HTTP y monta uno o más servidores MCP en rutas separadas:
/vault/mcp → mcpvault (Obsidian vault)
/healthz → liveness + mount listCada montaje es un endpoint MCP independiente. Los clientes los registran por separado: no hay agregación de herramientas, por lo que no hay colisiones de nombres ni esquema de espacios de nombres que mantener.
Exponer el puerto más allá de localhost está deliberadamente fuera de alcance. Pon un túnel, un proxy inverso o nada delante; Portcall se vincula a 127.0.0.1 por defecto y no le importa lo que haya río arriba.
Related MCP server: mcp-unify
Por qué no un puente stdio
La forma obvia de poner un servidor MCP stdio en HTTP es un puente genérico como supergateway. Eso funciona, pero tiene un problema estructural: cada petición o sesión lanza un proceso hijo, y es fácil equivocarse al recolectar esos hijos.
En supergateway concretamente, el hijo solo se reclama desde transport.onclose o transport.onerror. Nada llama a transport.close() en una petición sin estado completada normalmente, por lo que onclose nunca se dispara y cada petición exitosa pierde un proceso — solo las peticiones fallidas se limpian. Su modo con estado no pierde (un temporizador de sesión cierra el transporte), pero mantiene un flujo SSE GET de larga duración, que algunos proxies manejan mal.
Envolver el comando en npx lo empeora: npx bifurca el servidor real, por lo que matar al hijo mata al envoltorio y deja huérfano al nieto.
La respuesta de Portcall es no lanzar nada cuando no es necesario.
Adaptadores
Adaptador | Para | Cómo |
| Servidores que exportan una fábrica como biblioteca | Llama a la fábrica en el mismo proceso. No existe ningún proceso hijo, por lo que no hay nada que recolectar. |
| Servidores de terceros que solo hablan stdio | Aún no implementado. Cuando llegue, debe reclamar al hijo en la finalización normal, no solo en caso de error, y manejar los asesinatos de grupos de procesos para comandos envoltorio. |
inProcess es el caso interesante y cubre los servidores que merece la pena autoalojar. @bitbonsai/mcpvault, por ejemplo, exporta createServer(vaultPath, options) que devuelve un Server del SDK v2 de MCP; su entrada bin es esencialmente serveStdio(() => createServer(...)). Portcall llama a la misma función directamente y se salta stdio por completo.
El SDK crea una instancia de servidor nueva por petición y la elimina con la petición, por lo que no hay estado de sesión que expire ni manejadores que se acumulen.
Versiones del protocolo
Portcall está construido sobre @modelcontextprotocol/server v2, que atiende dos eras de protocolo desde un único manejador:
Moderno (
2026-07-28) — sobre por petición. Las peticiones llevan las cabecerasMCP-Protocol-Version,Mcp-Methody (para llamadas a herramientas)Mcp-Name, además de un bloqueparams._meta. No hay protocolo de inicioinitializeni sesión de larga duración; el descubrimiento esserver/discover.Legado (era 2025) — se sirve sin estado por defecto.
GETyDELETE(operaciones de sesión de 2025) responden405. EstablecePORTCALL_MODERN_ONLY=truepara rechazar el tráfico heredado por completo.
Debido a que la era moderna es por petición, no hay un flujo SSE permanente que mantener abierto. Eso evita una clase de problema de proxy: algunos proxies inversos retienen las cabeceras de respuesta hasta que llega el primer byte del cuerpo, lo que detiene indefinidamente un flujo SSE recién abierto pero silencioso. Para los flujos que sí ocurren, PORTCALL_KEEPALIVE_MS controla el intervalo de comentarios SSE; redúcelo si un proxy delante está almacenando en búfer.
Configuración
Todos los valores específicos del host provienen del entorno.
Variable | Por defecto | Significado |
| (obligatorio) | Ruta absoluta al almacén de Obsidian que se va a servir |
|
| Puerto TCP |
|
| Interfaz de enlace |
| (sin definir) | Token estático de portador. Sin definir significa sin autenticación |
| (sin definir) | Monta también el plugin nombrado en |
| (sin definir) | Sirve cada montaje bajo |
|
| Intervalo de keepalive SSE; |
|
| Rechaza las peticiones de la era 2025 en lugar de servirlas |
PORTCALL_TOKEN protege cada montaje con Authorization: Bearer <token>. Ten en cuenta que algunos clientes MCP — entre ellos la interfaz de conector personalizado de Claude — no ofrecen forma de establecer una cabecera de petición, por lo que para esos el token debe aplicarse río arriba (u omitirse, con el acceso controlado en la capa de red).
PORTCALL_PATH_PREFIX es el recurso para exactamente esos clientes: mueve cada montaje bajo un segmento que elijas, de modo que /vault/mcp se convierte en /<prefijo>/vault/mcp y la propia URL lleva el secreto. De ello se derivan dos cosas, y el servidor las aplica ambas:
Las respuestas
404dicen solonot_found. Nunca enumeran lo que está montado.El listado de montajes sale del
/healthzpúblico y pasa a/<prefix>/healthz. El/healthzsimple sigue respondiendo, por lo que las sondas de actividad siguen funcionando, pero no revela rutas.
Trata un prefijo de ruta como más débil que una cabecera. Las URL llegan a los registros de acceso del proxy, a los informes de errores y a cualquier cosa que registre un destino, y una filtrada otorga el mismo acceso que un token filtrado. Sube el listón: no es autenticación.
Qué plugins están montados, y dónde, se declara en plugins.config.ts.
Ejecución
Requiere Node 24 (ver .nvmrc).
npm install
npm run build
cp .env.example .env # then set PORTCALL_VAULT_PATH
npm startTanto npm start como npm run dev cargan .env si existe y arrancan sin él si no existe, por lo que un demonio puede inyectar el entorno directamente. Las variables ya establecidas en el entorno no se sobrescriben.
npm run dev ejecuta el punto de entrada a través de tsx con watch. Un demonio debería ejecutar la salida compilada, no tsx.
Comprueba que está activo:
curl -s localhost:7100/healthzPruebas
npm test # builds, then runs unit and integration tests
npm run typecheckSin dependencias de prueba: el ejecutor es node:test, y tsx (ya necesario para npm run dev) carga el TypeScript.
Las pruebas de integración son de caja negra. Lanzan el servidor compilado contra un almacén desechable en un puerto efímero y lo manejan a través de HTTP real, por lo que ejercitan el mismo artefacto que ejecuta un demonio: enrutamiento, el alias /mcp, autenticación de portador y ambas eras de protocolo. Las pruebas unitarias cubren la resolución de montajes y la comprobación del portador, donde una regresión silenciosa parecería un cliente muerto en lugar de un error.
Estructura
src/
server.ts HTTP entry point, wiring, health, shutdown
routes.ts mount resolution and URL normalisation
auth.ts bearer token check
config.ts environment parsing
log.ts structured logging
types.ts the Plugin interface
adapters/
inProcess.ts library-factory adapter
plugins/
vault.ts mcpvault
plugins.config.ts which plugins mount at which paths
test/
integration.test.ts black-box tests against the built server
routes.test.ts mount resolution
auth.test.ts bearer token check
helpers.ts server harness and MCP request buildersLicencia
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Stateless MCP gateway and OTel span-streaming bridge for hosted MCP servers.
The MCP server that finds MCP servers. Aggregates Official Registry, Glama, and Smithery.
MCP Gateway: wrap any MCP server with cold-start retries, uptime SLA, and per-execution MPP billing.
Create, deploy, and operate MCP servers directly from your GitHub repositories.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA universal MCP server that acts as a unified gateway for dynamically connecting and managing multiple MCP servers via a single HTTP endpoint.7 npm6MIT
- AlicenseNot gradedqualityCmaintenanceUnifies multiple MCP servers behind a single endpoint with lazy loading, auto-cleanup, Python plugins, and role-based filtering.2MIT

FlowMCP Serverofficial
AlicenseNot gradedqualityDmaintenanceProvides LocalServer and RemoteServer implementations for running MCP servers locally via stdio or remotely via HTTP/SSE, with simple and advanced deployment options.1MIT- FlicenseNot gradedqualityDmaintenanceA configurable MCP gateway that runs multiple Streamable HTTP MCP servers and exposes all their tools through a single endpoint, enabling tool aggregation and routing for MCP clients.1-