Phocinae MCP
Servidor MCP stdio local del motor de decisión Phocinae: compuerta de aprobación con cierre seguro + clasificar/enrutar/puntuar.
Documentación
phocinae-mcp
Expone la puerta de aprobación de comandos y el protocolo de razonamiento P0 de la foca manchada como herramientas MCP (gate / classify / route / score), integrando agentes de codificación que solo leen MCP. Coexisten dos protocolos: la cara moderna (2026-07-28, incluye server/discover, interacción MRTR, Streamable HTTP) y compatibilidad con clientes antiguos de 2024-11-05.
▲ Respuesta real de `tools/list`: parámetros y formas de retorno de las cuatro herramientas
Servidor MCP del ecosistema de la foca manchada: expone la aprobación de comandos y las capacidades de razonamiento de la foca manchada como 4 herramientas para clientes MCP. Solo biblioteca estándar (Python ≥ 3.8, cero dependencias de terceros), soporta transporte stdio y Streamable HTTP, alineado con MCP 2026-07-28 y compatible con clientes antiguos de 2024-11-05.
Este repositorio es una versión mejorada local (basada en PyPI phocinae-mcp 0.1.1), solo para desarrollo local y validación de alineación de protocolo, no se publica.
Herramientas
▲ **Animación de demostración sintética** (modelo repo docs/gallery [S07](https://huggingface.co/Phocinae/Phocinae-Largha-150M-v1/blob/main/docs/gallery)): las imágenes se renderizan cuadro a cuadro y los datos de escena son ficticios, pero el **proceso de decisión de la herramienta `route` «una pasada hacia adelante para elegir cuál herramienta usar entre las candidatas»** que demuestra es consistente con la implementación real (la captura de terminal en la parte superior de esta página es el mismo flujo ejecutado realmente).
| Herramienta | Función | Entrada | Salida |
|---|---|---|---|
gate | Determina si un comando shell puede ejecutarse | command, cwd?, server? | decision ∈ allow/deny/ask + layer/reason |
classify | Clasifica un estado en una de las etiquetas candidatas | state, labels, server? | choice (índice) + label |
route | Selecciona la herramienta más adecuada entre las candidatas | state, tools, server? | choice + tool |
score | Puntúa un estado de 2 a 10 según estándares | state, criteria, server? | score + range |
Fail-closed: cuando el servicio P0 de la foca manchada (/v1/systemone) no está disponible, expira o responde de forma anómala, gate siempre devuelve deny (con motivo), y classify/route/score devuelven isError: true.
Transporte
stdio (predeterminado)
python3 -m phocinae_mcp --server http://127.0.0.1:8155
El cliente MCP lo inicia como subproceso, comunicándose por stdin/stdout con tramas JSON-RPC línea a línea.
Garantía de pureza de stdout: stdout solo emite tramas JSON-RPC; todos los registros (inicio, advertencias, excepciones internas de herramientas) van solo por stderr (prefijo phocinae-mcp[level]:). Las impresiones en la fase de importación de guard.py también se redirigen a stderr, sin contaminar el canal de protocolo.
Streamable HTTP (nuevo, 2026-07-28)
python3 -m phocinae_mcp --transport http --host 127.0.0.1 --port 8255
# --port 0 → 随机端口(测试用);端口号打印在 stderr
- Solo enlace de bucle local:
--hostsolo acepta127.0.0.1/localhost/::1; otras direcciones rechazan el inicio directamente (exit 2); - Endpoint
POST /mcp; notificaciones →202 Accepted(cuerpo vacío); solicitudes →200objeto JSON único; - Validación de encabezados obligatoria (Server Validation):
MCP-Protocol-Versiondebe estar presente y ser compatible (de lo contrario400+-32020/-32022),Mcp-Methoddebe estar presente y coincidir con el método del cuerpo (tools/call,resources/readtambién deben incluirMcp-Nameigual aname/uri); incumplimiento →400 -32020; siAcceptno incluyeapplication/json/text/event-stream→406; método desconocido →404 -32601;GET/DELETE→405(2026-07-28 eliminó el flujo GET y el endpoint de terminación de sesión); - Sin encabezado de sesión (
Mcp-Session-Id), sin búfer de recuperación SSE — servicio sin estado, se puede reiniciar libremente.
Variables de entorno: PHOCINAE_MCP_TRANSPORT=stdio|http, PHOCINAE_MCP_HTTP_PORT
pueden reemplazar los interruptores de línea de comandos.
Alineación de protocolo (2026-07-28)
Coexisten dos generaciones, despacho por solicitud:
- Solicitudes con
params._meta(incluida la claveio.modelcontextprotocol/*), así comoserver/discover,resources/*→ cara moderna; - Handshake
initialize, solicitudes sin_meta→ generación antigua (comportamiento 2024-11-05, consistente con la versión original 0.1.x).
Elementos complementarios de la cara moderna:
| Elemento | Implementación |
|---|---|
server/discover | Obligatorio: supportedVersions, capabilities, _meta.serverInfo, instructions, ttlMs=3600000, cacheScope=public |
Validación de _meta | Por solicitud, obligatorio protocolVersion + clientCapabilities; ausente → -32602; versión no compatible → -32022 (data.supported/data.requested) |
resultType | Todos los resultados lo llevan (complete / input_required) |
ttlMs/cacheScope | discover, tools/list, resources/* (contenido estático, caché compartida public) |
| Interacción multi-ronda (MRTR) | Cuando gate devuelve ask y el cliente declara la capacidad elicitation → resultType=input_required + inputRequests.gate_confirmation (elicitation/create, form) + requestState; recibo accept/decline/cancel → allow/deny/no autorizado; requestState es HMAC-SHA256 a prueba de manipulación + expiración de 10 minutos + comparación de huella de solicitud (tool+command), manipulación/expiración reenvía automáticamente la interacción |
| resources | resources/list + resources/read exponen el texto completo de la política de aprobación phocinae://policy/gate-approval (text/markdown, incluye cadena de decisión L0/L1/fail-closed, umbrales, obligaciones de manejo de ask) |
| Métodos eliminados | En la cara moderna, initialize/ping/shutdown/logging/setLevel/subscriptions/listen → -32601 (data adjunta supportedVersions) |
| Esquema de herramientas ajustado | maxLength (command/state 20000, cwd 4096, server 2048, elemento de lista 2000), minItems/maxItems (1–100), enum (decision/layer), outputSchema declaración completa (classify/route/score additionalProperties:false); el servidor ejecuta la misma validación sincrónicamente (fuera de límite → -32602) |
| Reescritura de descripción | Las cuatro herramientas se reescriben con la estructura «cuándo usar / cuándo no usar» |
| Registros | Todo por stderr; en _meta, controlado por io.modelcontextprotocol/logLevel (desde info, campo de protocolo de registro a nivel MCP) |
Compatibilidad: el handshake initialize de clientes antiguos devuelve capacidades 2024-11-05; tools/list/tools/call sin _meta responden según la generación antigua (sin error) — cero ruptura para clientes antiguos.
Ejecución
▲ Decisión real de `tools/call`: L0 determina comandos seguros/peligrosos, solo la zona gris llama al modelo
# stdio(默认)
python3 -m phocinae_mcp [--server http://127.0.0.1:8155] [--timeout 5]
[--guard /path/to/guard.py] [--l1-enabled] [--model <name>]
# Streamable HTTP
python3 -m phocinae_mcp --transport http [--host 127.0.0.1] [--port 8255]
python3 -m phocinae_mcp --version
--guard: reutiliza guard.py de phocinae-guard (tabla determinista L0 + orquestación L1), detecta automáticamente ../phocinae-guard/guard.py en el mismo nivel; si no se encuentra, la puerta se degrada a dos preguntas HTTP puras noul+score (engine: "http:noul+score"). Al importar guard no se escribe __pycache__ (reutilización de solo lectura).
Pruebas
python3 tests/test_mcp.py # stdio 双代全流程冒烟 → tests/mcp_smoke.txt
python3 tests/test_http.py # Streamable HTTP 冒烟 → tests/http_smoke.txt
test_mcp.py: simula un cliente MCP, ejecuta secuencialmente por stdio la generación antigua initialize → notifications/initialized → ping → tools/list → tools/call matriz completa de herramientas (incluidas ramas de fallo) → shutdown; generación moderna discover → tools/list → matriz completa de herramientas (gate allow/deny/ask, MRTR aceptar/rechazar/cancelar/manipular, fail-closed, límites de esquema,-32602/-32022/-32601, resources) → notificaciones. También audita stdout línea por línea (cada línea debe ser una trama JSON-RPC, cero fugas de registros, sin traceback).test_http.py: matriz de validación de encabezados HTTP (-32020/-32022/406/405/404/202) + cadena completa MRTR + resources.- Ambas pruebas comparten
tests/mock_systemone.py(servicio P0 mock determinista, sin ejecutar modelos).
Directorio
phocinae_mcp/
├── server.py 主程序:双代分派、MRTR、CLI(stdio/http)
├── http_transport.py Streamable HTTP(新增)
├── protocol.py 2026-07-28 共享件(新增):版本/错误码/_meta 校验/
│ resultType/ttlMs/cacheScope/HMAC requestState/策略文本/日志门控
├── tools.py 四工具 + 收紧后的 schema(description 重写)
├── backend.py 斑海豹 P0 客户端(原版不动)
├── guard_bridge.py guard.py 复用桥(+stdout 纯净性防护)
└── __init__.py / __main__.py
tests/
├── test_mcp.py stdio 全流程冒烟 → mcp_smoke.txt
├── test_http.py HTTP 冒烟 → http_smoke.txt
└── mock_systemone.py 确定性 mock P0 服务
Declaración de seguridad (mismo criterio que el ecosistema de la foca manchada)
▲ `test_mcp.py` 42/42 + `test_http.py` 18/18: tramas forzadas a UTF-8, independiente de locale (este es un defecto real en 0.1.x)
- El resultado
askdegaterequiere que el integrador presente el comando y el motivo a un humano, y no ejecute sin aprobación explícita (la cara moderna usa interacción de elicitación, la generación antigua usa texto de resultado); - Los resultados de decisión no constituyen ninguna promesa de responsabilidad legal; fail-closed es el único predeterminado;
- El texto completo de la política de aprobación está en el recurso
phocinae://policy/gate-approval(resources/read).