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 logo

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.

PyPI Registry MCP deps

MCP 协议自述(真实 JSON-RPC 帧)

▲ 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

S07 演示动画

▲ **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).

HerramientaFunciónEntradaSalida
gateDetermina si un comando shell puede ejecutarsecommand, cwd?, server?decision ∈ allow/deny/ask + layer/reason
classifyClasifica un estado en una de las etiquetas candidatasstate, labels, server?choice (índice) + label
routeSelecciona la herramienta más adecuada entre las candidatasstate, tools, server?choice + tool
scorePuntúa un estado de 2 a 10 según estándaresstate, 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: --host solo acepta 127.0.0.1 / localhost / ::1; otras direcciones rechazan el inicio directamente (exit 2);
  • Endpoint POST /mcp; notificaciones → 202 Accepted (cuerpo vacío); solicitudes → 200 objeto JSON único;
  • Validación de encabezados obligatoria (Server Validation): MCP-Protocol-Version debe estar presente y ser compatible (de lo contrario 400 + -32020/-32022), Mcp-Method debe estar presente y coincidir con el método del cuerpo (tools/call, resources/read también deben incluir Mcp-Name igual a name/uri); incumplimiento → 400 -32020; si Accept no incluye application/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 clave io.modelcontextprotocol/*), así como server/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:

ElementoImplementación
server/discoverObligatorio: supportedVersions, capabilities, _meta.serverInfo, instructions, ttlMs=3600000, cacheScope=public
Validación de _metaPor solicitud, obligatorio protocolVersion + clientCapabilities; ausente → -32602; versión no compatible → -32022 (data.supported/data.requested)
resultTypeTodos los resultados lo llevan (complete / input_required)
ttlMs/cacheScopediscover, 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
resourcesresources/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 eliminadosEn la cara moderna, initialize/ping/shutdown/logging/setLevel/subscriptions/listen → -32601 (data adjunta supportedVersions)
Esquema de herramientas ajustadomaxLength (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ónLas cuatro herramientas se reescriben con la estructura «cuándo usar / cuándo no usar»
RegistrosTodo 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

gate 工具真实判定

▲ 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)

stdio 与 HTTP 两套协议冒烟真实运行

▲ `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 ask de gate requiere 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).