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
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:
| Perfil | Herramientas | Sobrecarga de contexto | Mejor para |
|---|---|---|---|
| core | 25 | ~8K tokens (4% de 200K) | Claude Code, Cursor, modelos de contexto pequeño |
| full | 63 | ~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
| Variable | Requerida | Predeterminado | Descripción |
|---|---|---|---|
MESH_API_URL | Sí | http://localhost:8005 | URL base de la API de Mesh |
MESH_AGENT_KEY | Sí (stdio) | — | Clave API del agente (agk_...) |
MESH_MCP_PROFILE | No | full | Perfil de herramientas para stdio: core o full (SSE sirve ambos) |
MESH_MCP_TRANSPORT | No | stdio | Modo de transporte: stdio o sse |
MESH_MCP_HOST | No | 0.0.0.0 | Host de enlace del servidor SSE |
MESH_MCP_PORT | No | 8081 | Puerto de enlace del servidor SSE |
MESH_MCP_AUTH_FAIL_RPM | No | 20 | Modo 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_MIN | No | 15 | Modo 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_SEC | No | 30 | Modo 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_URL | No | — | 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_ISSUER | No | origen de MESH_MCP_PUBLIC_URL | Modo 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_SEC | No | 60 | Modo 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_USERNAME | No | — | 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_ALIASES | No | off | 1 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:
| Ruta | Perfil | Descripción |
|---|---|---|
/sse + /message | full | Las 63 herramientas (compatible con versiones anteriores) |
/core/sse + /core/message | core | 25 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í):
| Ruta | Perfil |
|---|---|
/mcp | full |
/core | core |
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
401yWWW-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 (un4xxdistinto de408/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 es503conRetry-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:
Endpoint Metadatos https://mesh.example.com/mcp(full)/.well-known/oauth-protected-resource/mcphttps://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"] }resourceesMESH_MCP_PUBLIC_URL(barra final, consulta y fragmento eliminados; se añade/corepara 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 conMESH_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
| Herramienta | Descripción |
|---|---|
heartbeat | Enviar 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_knowledge | Obtener TODO el conocimiento permanente (decisiones, convenciones). Paso 2 de ACP |
get_my_rules | Obtener TODAS las reglas de gobernanza (flujo de trabajo + asignación). Paso 3 de ACP |
get_context | Obtener actividad reciente + conocimiento del proyecto. Paso 4 de ACP |
get_my_tasks | Obtener tareas asignadas. Paso 5 de ACP |
Gestión de tareas
| Herramienta | Descripción |
|---|---|
list_projects | Listar proyectos del espacio de trabajo |
list_tasks | Listar tareas con filtros (estado, prioridad, asignado, búsqueda) |
get_task | Obtener detalles de la tarea con comentarios/artefactos/dependencias opcionales |
create_task | Crear una nueva tarea |
update_task | Actualizar campos de la tarea |
move_task | Cambiar el estado de la tarea usando slugs |
assign_task | Asignar/desasignar una tarea |
get_task_context | Obtener todo sobre una tarea en una sola llamada |
add_vcs_link | Vincular una tarea a una solicitud de extracción, commit o rama |
Comunicación
| Herramienta | Descripción |
|---|---|
add_comment | Añ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_event | Publicar evento + sugerencia de memoria opcional para persistencia |
Memoria
| Herramienta | Descripción |
|---|---|
recall | Buscar memoria por palabras clave |
remember | Guardar conocimiento (UPSERT por clave) |
forget | Eliminar una entrada de memoria |
recall_with_graph | Buscar memoria, expandiendo resultados a través del grafo de conocimiento |
set_project_knowledge | Escribir un hecho estructurado del proyecto (upsert por clave) |
get_canonical_updates | Obtener decisiones canónicas registradas desde un momento dado |
record_owner_decision | Registrar 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
| Herramienta | Descripción |
|---|---|
report_error | Informar de un error en una tarea |
session_report | Informar métricas de sesión (modelo, tokens, coste) |
Herramientas MCP — Perfil completo (añade 38 más, 63 en total)
Herramientas de tareas adicionales
| Herramienta | Descripción |
|---|---|
get_project | Obtener detalles del proyecto con estados y campos personalizados |
create_subtask | Crear subtarea bajo un padre (status_slug opcional; por defecto el estado predeterminado del proyecto, no el del padre) |
add_dependency | Añadir dependencia entre tareas |
checkout_task | Bloqueo atómico de tareas para coordinación multi-agente |
release_task | Liberar bloqueo atómico de tareas |
extend_checkout | Extender un bloqueo de tarea existente para trabajos de mayor duración |
set_human_gate | Congelar una tarea hasta que una persona nombrada responda a una pregunta registrada |
clear_human_gate | Liberar una compuerta humana |
Comentarios y artefactos
| Herramienta | Descripción |
|---|---|
list_comments | Listar comentarios de tareas |
upload_artifact | Subir archivo/código/registro a una tarea |
list_artifacts | Listar artefactos de tareas |
get_artifact | Obtener 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
| Herramienta | Descripción |
|---|---|
publish_summary | Publicar resumen de trabajo (envoltorio de conveniencia) |
subscribe_events | Configurar entrega de webhooks para eventos |
poll_tasks | Sondeo largo para nuevas asignaciones de tareas |
Agente y equipo
| Herramienta | Descripción |
|---|---|
register_sub_agent | Registrar un sub-agente |
list_sub_agents | Listar sub-agentes (opcionalmente recursivo) |
get_team_directory | Obtener directorio del equipo del espacio de trabajo |
update_agent_profile | Actualizar rol, capacidades, perfil del agente |
Gobernanza y configuración
| Herramienta | Descripción |
|---|---|
get_project_rules | Obtener todas las reglas del proyecto |
get_assignment_rules | Obtener reglas de asignación |
get_workflow_rules | Obtener reglas de flujo de trabajo con permisos del llamador |
import_workspace_config | Importar configuración del espacio de trabajo desde YAML |
export_workspace_config | Exportar configuración del espacio de trabajo como YAML |
Tareas recurrentes
| Herramienta | Descripción |
|---|---|
create_recurring_task | Crear programación de tareas recurrentes |
list_recurring_schedules | Listar programaciones recurrentes |
get_recurring_history | Obtener historial de instancias para una programación |
trigger_recurring_now | Activar la siguiente instancia inmediatamente |
update_recurring_schedule | Cambiar o desactivar una programación recurrente |
delete_recurring_schedule | Eliminar una programación recurrente (las instancias existentes permanecen) |
Documentos y conocimiento
| Herramienta | Descripción |
|---|---|
list_docs | Listar documentos de un proyecto (solo metadatos) |
get_doc | Leer un documento (esquema por defecto, cuerpo a petición) |
search_docs | Búsqueda de texto completo en los documentos de un proyecto |
create_doc | Crear un documento |
update_doc | Editar un documento (concurrencia optimista mediante base_version) |
comment_doc | Comentar un documento o un pasaje citado |
list_doc_comments | Leer los hilos de comentarios de un documento |
get_canonical | Consultar 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
- evc-mesh — Plataforma principal (API + interfaz web)
- evc-mesh-openclaw-skill — Habilidad OpenClaw (scripts bash)