EVC Mesh

Tareas, comentarios, memoria compartida y traspasos para equipos de personas y agentes de IA, a través de MCP.

Documentación

Servidor MCP de EVC Mesh

Install via Spark

Servidor de Model Context Protocol (MCP) para EVC Mesh — una plataforma de gestión de tareas para coordinar humanos y agentes de IA.

Conecta agentes de IA (Claude Code, Cursor, Cline, OpenClaw, etc.) a EVC Mesh mediante herramientas MCP para gestión de tareas, memoria persistente, publicación de eventos y coordinación multiagente.

Esta es la copia en desarrollo activo. evc-mesh también incluye un servidor MCP (./cmd/mcp, mismo conjunto de herramientas internal/mcp) que compila e implementa por sí mismo — ambos existen porque las reglas de visibilidad de internal/ de Go impiden que un repositorio importe el paquete del otro, no porque estén destinados a divergir. Las nuevas herramientas y correcciones llegan aquí primero.

Requisitos previos

  • Go 1.22+
  • Instancia de EVC Mesh en ejecución
  • Agente registrado en Mesh con una clave API (agk_...)

Instalación

go install github.com/entire-vc/evc-mesh-mcp@latest

O compilar desde el código fuente:

git clone https://github.com/entire-vc/evc-mesh-mcp.git
cd evc-mesh-mcp
go build -o evc-mesh-mcp .

Docker

docker run -i --rm \
  -e MESH_API_URL \
  -e MESH_AGENT_KEY \
  ghcr.io/entire-vc/evc-mesh-mcp

Se requiere -i — el servidor habla MCP a través de stdio, y Docker solo conecta stdin cuando el contenedor se ejecuta de forma interactiva. Añade -e MESH_MCP_PROFILE=core para cambiar de perfiles (consulta Perfiles de herramientas más abajo). La imagen se publica para linux/amd64 y linux/arm64 desde Dockerfile en este repositorio en cada lanzamiento etiquetado (docs/RELEASING.md).

Perfiles de herramientas

El servidor MCP admite dos perfiles para optimizar el uso de la ventana de contexto:

PerfilHerramientasSobrecarga de contextoMejor para
core25~8K tokens (4% de 200K)Claude Code, Cursor, modelos de contexto pequeño
full63~18K tokens (9% de 200K)Usuarios avanzados, agentes de automatización, operaciones de administración

Se configura mediante la variable de entorno MESH_MCP_PROFILE. Valor predeterminado: full.

Configuración

VariableRequeridaPredeterminadoDescripción
MESH_API_URLSíhttp://localhost:8005URL base de la API de Mesh
MESH_AGENT_KEYSí (stdio)—Clave API del agente (agk_...)
MESH_MCP_PROFILENofullPerfil de herramientas para stdio: core o full (SSE sirve ambos)
MESH_MCP_TRANSPORTNostdioModo de transporte: stdio o sse
MESH_MCP_HOSTNo0.0.0.0Host de enlace del servidor SSE
MESH_MCP_PORTNo8081Puerto de enlace del servidor SSE
MESH_MCP_AUTH_FAIL_RPMNo20Modo SSE: presupuesto por IP para intentos de autenticación contra una clave de agente aún no almacenada en caché en /sse, /core/sse, /mcp, /mcp/core. Si se supera el presupuesto → 429 sin llamar a la API de Mesh. 0 lo desactiva.
MESH_MCP_SESSION_CACHE_TTL_MINNo15Modo SSE: cuánto tiempo se confía en una autenticación exitosa antes de volver a verificar la clave — limita cuánto tiempo sigue funcionando una clave revocada sin reiniciar.
MESH_MCP_AUTH_FAIL_CACHE_SECNo30Modo SSE: cuánto tiempo se recuerda una autenticación fallida (clave incorrecta/desconocida), para que repetir la misma clave incorrecta no llame a la API de Mesh en cada solicitud.
MESH_MCP_PUBLIC_URLNo—Modo SSE: la URL desde la que se puede acceder a la raíz de MCP desde el exterior, p. ej. https://mesh.example.com/mcp. Se usa para el endpoint SSE absoluto y como URL de recurso OAuth (consulta OAuth). Sin configurar: se deriva del host de cada solicitud, lo cual solo es correcto cuando los clientes acceden a este servidor directamente — detrás de un proxy configúrala, o la URL central derivada (/core) no coincidirá con la pública (/mcp/core).
MESH_MCP_OAUTH_ISSUERNoorigen de MESH_MCP_PUBLIC_URLModo SSE: el servidor de autorización OAuth nombrado en los metadatos del recurso protegido — el origen público de tu instancia de Mesh. Configúralo solo si el servidor MCP se sirve desde un origen diferente al de la API de Mesh.
MESH_MCP_OAUTH_CACHE_TTL_SECNo60Modo SSE: cuánto tiempo se confía en un token de acceso OAuth verificado antes de volver a preguntar a la API de Mesh. Deliberadamente mucho más corto que el TTL de la clave de agente para que una concesión revocada deje de funcionar en aproximadamente un minuto.
MESH_MCP_DECIDER_USERNAMENo—Nombre de usuario registrado como decided_by cuando record_owner_decision responde una tarea restringida. Sin configurar: el propietario del espacio de trabajo.
MESH_MCP_LEGACY_TOOL_ALIASESNooff1 también registra los nombres anteriores de las herramientas, para implementaciones cuyos llamadores aún los usan. Déjalo en off para instalaciones nuevas.

Ejecución sin credenciales

En modo stdio, el servidor también se inicia cuando MESH_AGENT_KEY no está configurado. Entonces responde initialize y tools/list como de costumbre, y cada llamada a una herramienta devuelve instrucciones para configurar MESH_API_URL y MESH_AGENT_KEY. Esto permite que los clientes y catálogos MCP inspeccionen la lista de herramientas antes de tener una clave. Si hay una clave configurada pero la autenticación falla al inicio (API inaccesible, clave rechazada), el servidor sigue ejecutándose: las herramientas se listan, y cada llamada reintenta la autenticación y devuelve el motivo hasta que tenga éxito.

Anotaciones de herramientas

Cada herramienta declara las pistas MCP readOnlyHint, destructiveHint, idempotentHint y openWorldHint, para que los clientes puedan distinguir las herramientas de solo lectura (get_*, list_*, recall, search_docs, …) de las que modifican o eliminan datos (update_*, move_task, forget, …).

Métricas del cliente

Cada initialize se registra con el clientInfo.name y la versión del cliente, y se cuenta en la métrica de Prometheus mesh_mcp_initialize_total{client,profile} (expuesta en /metrics en modo SSE; los nombres de clientes se normalizan y limitan).

Claude Code (modo stdio)

Añade a .mcp.json de tu proyecto:

{
  "mcpServers": {
    "evc-mesh": {
      "command": "evc-mesh-mcp",
      "env": {
        "MESH_API_URL": "https://your-mesh-instance.example.com",
        "MESH_AGENT_KEY": "agk_your-workspace_your-key",
        "MESH_MCP_PROFILE": "core"
      }
    }
  }
}

Cursor

Añade a la configuración MCP de Cursor (Configuración → Servidores MCP):

{
  "evc-mesh": {
    "command": "evc-mesh-mcp",
    "env": {
      "MESH_API_URL": "https://your-mesh-instance.example.com",
      "MESH_AGENT_KEY": "agk_your-workspace_your-key",
      "MESH_MCP_PROFILE": "core"
    }
  }
}

Modo SSE (multiagente, servidor compartido)

Para conectar múltiples agentes a través de un endpoint MCP compartido:

MESH_API_URL=https://your-mesh-instance.example.com \
MESH_MCP_PORT=8081 \
evc-mesh-mcp --transport sse

El modo SSE sirve dos perfiles simultáneamente en diferentes rutas:

RutaPerfilDescripción
/sse + /messagefullLas 63 herramientas (compatible con versiones anteriores)
/core/sse + /core/messagecore25 herramientas esenciales

El mismo proceso también sirve el transporte Streamable HTTP (sin estado, una clave de agente por solicitud, enviada en el encabezado Authorization: Bearer o X-Agent-Key — el parámetro de consulta se rechaza allí):

RutaPerfil
/mcpfull
/corecore

Autenticación por conexión mediante:

  • Encabezado Authorization: Bearer agk_...
  • Encabezado X-Agent-Key: agk_...
  • Parámetro de consulta ?agent_key=agk_... (solo conexión SSE)
  • Authorization: Bearer mot_... — un token de acceso OAuth emitido por tu instancia de Mesh (consulta más abajo); solo el encabezado, nunca la cadena de consulta, y solo en los endpoints Streamable HTTP (las conexiones SSE necesitan una clave de agente)

OAuth (conectores remotos)

Los clientes que inician sesión de usuarios con OAuth — directorios de conectores remotos, MCP Inspector, editores que siguen la especificación de autorización MCP — se conectan a los endpoints Streamable HTTP sin una clave precompartida. Tu instancia de Mesh es el servidor de autorización (registro dinámico de clientes, PKCE, consentimiento del usuario); este servidor es el servidor de recursos y hace dos cosas:

  • Desafíos. Una solicitud sin credencial, o con un token de acceso OAuth que la API de Mesh rechaza (expirado, revocado, nunca emitido), recibe 401 y

    WWW-Authenticate: Bearer resource_metadata="https://mesh.example.com/.well-known/oauth-protected-resource/mcp", scope="mesh"
    

    que es donde un cliente inicia el flujo de autorización. Una clave de agente rechazada sigue respondiendo 403. Solo un veredicto de la API de Mesh (un 4xx distinto de 408/429) hace que un token sea inválido: si la API de Mesh no se puede alcanzar o responde con un error que no dice nada sobre el token (5xx, 429), la respuesta es 503 con Retry-After, para que un token válido no se descarte por una interrupción.

  • Sirve los metadatos (RFC 9728) en la ruta bien conocida derivada de la URL de cada endpoint:

    EndpointMetadatos
    https://mesh.example.com/mcp (full)/.well-known/oauth-protected-resource/mcp
    https://mesh.example.com/mcp/core (core)/.well-known/oauth-protected-resource/mcp/core
    {
      "resource": "https://mesh.example.com/mcp",
      "authorization_servers": ["https://mesh.example.com"],
      "scopes_supported": ["mesh"],
      "bearer_methods_supported": ["header"]
    }
    

    resource es MESH_MCP_PUBLIC_URL (barra final, consulta y fragmento eliminados; se añade /core para el perfil core), así que configúralo con la URL que tus usuarios pegan en el cliente. El servidor de autorización se predetermina al origen de esa URL; anúlalo con MESH_MCP_OAUTH_ISSUER.

Un token OAuth actúa como un agente conector en el espacio de trabajo que el usuario eligió cuando otorgó acceso, con los permisos de ese agente — las mismas herramientas, el mismo modelo de permisos que una clave de agente. Los tokens verificados se almacenan en caché durante un minuto (MESH_MCP_OAUTH_CACHE_TTL_SEC). El presupuesto por IP (MESH_MCP_AUTH_FAIL_RPM) lo gastan los tokens rechazados, no las verificaciones, por lo que muchos usuarios detrás de una misma dirección no se ven limitados por sus propios refrescos de token. El token no está vinculado a una audiencia: cualquier token de acceso válido de tu instancia de Mesh se acepta, que es la intención mientras el servidor de autorización y este servidor pertenezcan a la misma implementación. Las claves de agente (agk_...) en Authorization o X-Agent-Key funcionan exactamente como antes, y el modo stdio no se ve afectado.

Tu proxy inverso debe enviar /.well-known/oauth-protected-resource* a este servidor en lugar del catch-all de la aplicación web: una aplicación de una sola página responde a cada ruta desconocida con 200 text/html, que un cliente no puede distinguir de metadatos faltantes.

Protocolo de Contexto de Agente (ACP)

Al inicio de la sesión, sigue estos 5 pasos en orden:

1. heartbeat(status="online")              → register as alive
2. get_project_knowledge(project_id)       → load accumulated decisions & conventions
3. get_my_rules(project_id)                → understand constraints
4. get_context(project_id)                 → see recent activity + project knowledge
5. get_my_tasks()                          → check assigned work

Al final de la sesión:

publish_event(type="summary", memory={persist: true})  → broadcast + persist
session_report(model, tokens_in, tokens_out)           → report metrics

Herramientas MCP — Perfil Core (25)

ACP e Identidad

HerramientaDescripción
heartbeatEnviar heartbeat. Llama al inicio de la sesión con status=online. La respuesta incluye mesh_version (el git-SHA de compilación del binario en ejecución, o "dev" para una compilación local sin fijar) — forma económica de comprobar si una corrección realmente llegó al binario instalado sin acceder al host.
get_project_knowledgeObtener TODO el conocimiento permanente (decisiones, convenciones). Paso 2 de ACP
get_my_rulesObtener TODAS las reglas de gobernanza (flujo de trabajo + asignación). Paso 3 de ACP
get_contextObtener actividad reciente + conocimiento del proyecto. Paso 4 de ACP
get_my_tasksObtener tareas asignadas. Paso 5 de ACP

Gestión de tareas

HerramientaDescripción
list_projectsListar proyectos del espacio de trabajo
list_tasksListar tareas con filtros (estado, prioridad, asignado, búsqueda)
get_taskObtener detalles de la tarea con comentarios/artefactos/dependencias opcionales
create_taskCrear una nueva tarea
update_taskActualizar campos de la tarea
move_taskCambiar el estado de la tarea usando slugs
assign_taskAsignar/desasignar una tarea
get_task_contextObtener todo sobre una tarea en una sola llamada
add_vcs_linkVincular una tarea a una solicitud de extracción, commit o rama

Comunicación

HerramientaDescripción
add_commentAñadir comentario a una tarea (markdown). La respuesta incluye un array delivery por mención @ que informa si realmente llegó al destinatario (cola de tareas/notificación) o se omitió/falló y por qué
publish_eventPublicar evento + sugerencia de memoria opcional para persistencia

Memoria

HerramientaDescripción
recallBuscar memoria por palabras clave
rememberGuardar conocimiento (UPSERT por clave)
forgetEliminar una entrada de memoria
recall_with_graphBuscar memoria, expandiendo resultados a través del grafo de conocimiento
set_project_knowledgeEscribir un hecho estructurado del proyecto (upsert por clave)
get_canonical_updatesObtener decisiones canónicas registradas desde un momento dado
record_owner_decisionRegistrar una decisión del propietario del espacio de trabajo como conocimiento canónico del proyecto

Qué garantiza recall sobre su resultado

limit es un límite estricto. La respuesta nunca contiene más de limit elementos, y total siempre es igual al número de elementos realmente devueltos. Nada se añade a la página después de que se haya dimensionado — ni filas fijadas, ni vecinos expandidos del grafo.

Las filas que fallan scope/tags/tags_any se descartan, nunca se devuelven sin marcar. Esto se mantiene independientemente de cómo llegó una fila al resultado: recuperación ordinaria, fijación, o expansión del grafo. Una fila fijada está exenta del ranquin, no de la elegibilidad — "fijada" significa "no permitas que el ranquin entierre esto", no "muestra esto a un llamador que pidió un ámbito diferente".

Los vecinos del grafo están marcados y limitados. Con RECALL_GRAPH_ENABLED=true, recall también ejecuta una expansión del grafo de conocimiento e incorpora hop > 0 vecinos, cada uno con graph_boost: true y provenance: via:graph. Ocupan como máximo limit/4 de la página (al menos 1 cuando limit >= 2, ninguno cuando limit < 2) y toman sus ranuras finales, desplazando los resultados de recuperación más débiles en lugar de añadirse encima. Cuando la expansión no devuelve nada utilizable, la página es exactamente el resultado base — la reserva es un techo, no una cuota. graph_boost_count informa cuántas ranuras se gastaron realmente.

La reserva existe porque los resultados base llevan score (RRF entre los brazos de recuperación) y los vecinos llevan composite_score de un recorrido separado — campos diferentes en escalas diferentes. Ordenar la unión por una clave común no los equilibra; en la práctica cada vecino observado se clasifica por debajo de cada resultado base, por lo que una fusión-ordenación ingenua deshabilitaría silenciosamente el impulso del grafo. La reserva hace ese intercambio explícito y ajustable.

Los ajustes preestablecidos nunca te anulan. recall clasifica la consulta y puede aplicar un perfil (por ejemplo, multi-sesión amplía la página). Un perfil solo completa los parámetros que no proporcionaste; un limit explícito siempre gana.

Utilidad

HerramientaDescripción
report_errorInformar de un error en una tarea
session_reportInformar métricas de sesión (modelo, tokens, coste)

Herramientas MCP — Perfil completo (añade 38 más, 63 en total)

Herramientas de tareas adicionales

HerramientaDescripción
get_projectObtener detalles del proyecto con estados y campos personalizados
create_subtaskCrear subtarea bajo un padre (status_slug opcional; por defecto el estado predeterminado del proyecto, no el del padre)
add_dependencyAñadir dependencia entre tareas
checkout_taskBloqueo atómico de tareas para coordinación multi-agente
release_taskLiberar bloqueo atómico de tareas
extend_checkoutExtender un bloqueo de tarea existente para trabajos de mayor duración
set_human_gateCongelar una tarea hasta que una persona nombrada responda a una pregunta registrada
clear_human_gateLiberar una compuerta humana

Comentarios y artefactos

HerramientaDescripción
list_commentsListar comentarios de tareas
upload_artifactSubir archivo/código/registro a una tarea
list_artifactsListar artefactos de tareas
get_artifactObtener detalles del artefacto (download_path; bytes mediante la descarga en dos pasos a continuación)

Descargar un artefacto

Descargar un artefacto son dos GET. Paso 1: GET /api/v1/artifacts//download con el encabezado X-Agent-Key: -> 200 JSON {"url": ""}. Paso 2: GET esa url SIN encabezados -> 200, los bytes del archivo. Errores comunes: en el paso 1 solo se acepta X-Agent-Key (X-API-Key y Authorization: Bearer dan 401); en el paso 2 cualquier encabezado adicional, especialmente Authorization, rompe la firma presignada (400). El download_path del artefacto es la ruta del paso 1. Nunca obtengas browser_only_url con una clave de agente: es una página humana y responde 401 por diseño.

Bus de eventos

HerramientaDescripción
publish_summaryPublicar resumen de trabajo (envoltorio de conveniencia)
subscribe_eventsConfigurar entrega de webhooks para eventos
poll_tasksSondeo largo para nuevas asignaciones de tareas

Agente y equipo

HerramientaDescripción
register_sub_agentRegistrar un sub-agente
list_sub_agentsListar sub-agentes (opcionalmente recursivo)
get_team_directoryObtener directorio del equipo del espacio de trabajo
update_agent_profileActualizar rol, capacidades, perfil del agente

Gobernanza y configuración

HerramientaDescripción
get_project_rulesObtener todas las reglas del proyecto
get_assignment_rulesObtener reglas de asignación
get_workflow_rulesObtener reglas de flujo de trabajo con permisos del llamador
import_workspace_configImportar configuración del espacio de trabajo desde YAML
export_workspace_configExportar configuración del espacio de trabajo como YAML

Tareas recurrentes

HerramientaDescripción
create_recurring_taskCrear programación de tareas recurrentes
list_recurring_schedulesListar programaciones recurrentes
get_recurring_historyObtener historial de instancias para una programación
trigger_recurring_nowActivar la siguiente instancia inmediatamente
update_recurring_scheduleCambiar o desactivar una programación recurrente
delete_recurring_scheduleEliminar una programación recurrente (las instancias existentes permanecen)

Documentos y conocimiento

HerramientaDescripción
list_docsListar documentos de un proyecto (solo metadatos)
get_docLeer un documento (esquema por defecto, cuerpo a petición)
search_docsBúsqueda de texto completo en los documentos de un proyecto
create_docCrear un documento
update_docEditar un documento (concurrencia optimista mediante base_version)
comment_docComentar un documento o un pasaje citado
list_doc_commentsLeer los hilos de comentarios de un documento
get_canonicalConsultar hechos y decisiones seleccionados para un tema

Arquitectura

AI Agent (Claude Code / Cursor / Cline / OpenClaw)
    ↕ MCP (stdio or SSE)
EVC Mesh MCP Server (core or full profile)
    ↕ REST API (HTTP)
EVC Mesh API Server
    ↕
PostgreSQL / Redis / NATS / S3

El servidor MCP es un proxy ligero — traduce llamadas de herramientas MCP en solicitudes REST API. No se necesita acceso directo a la base de datos.

Ejecutar el servidor HTTP compartido

Para atender a varios agentes desde un solo proceso, ejecuta el servidor en modo SSE junto a tu API Mesh (la misma imagen funciona: docker run -e MESH_MCP_TRANSPORT=sse -e MESH_API_URL=... -p 8081:8081 ghcr.io/entire-vc/evc-mesh-mcp) y colócalo detrás de tu proxy inverso. Expone tanto SSE (/sse, /core/sse) como HTTP Streamable (/mcp, /core); cada conexión o solicitud se autentica con su propia clave de agente. El servidor no tiene base de datos propia: llama a la API REST de Mesh, así que actualízalo después de la API Mesh con la que habla.

La herramienta heartbeat devuelve mesh_version, el commit desde el que se construyó el binario en ejecución, y --version también lo imprime.

Relacionado

Licencia

MIT