Phocinae MCP

Servidor MCP stdio local do mecanismo de decisão Phocinae: portão de aprovação com falha fechada + classificar/rotear/pontuar.

Documentação

斑海豹 Phocinae logo

phocinae-mcp

Expõe o portão de aprovação de comandos e o protocolo de raciocínio P0 do Phocinae como ferramentas MCP (gate / classify / route / score), conectando agentes de codificação que usam MCP somente leitura. Dois protocolos coexistem: a face moderna (2026-07-28, incluindo server/discover, interação MRTR, Streamable HTTP) e compatibilidade com clientes antigos de 2024-11-05.

PyPI Registry MCP deps

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

▲ Resposta real do `tools/list`: parâmetros e formatos de retorno das quatro ferramentas

Servidor MCP do ecossistema Phocinae: expõe a aprovação de comandos e a capacidade de raciocínio do Phocinae como 4 ferramentas para clientes MCP. Somente biblioteca padrão (Python ≥ 3.8, zero dependências de terceiros), suporta transporte stdio e Streamable HTTP, alinhado ao MCP 2026-07-28 e compatível com clientes antigos de 2024-11-05.

Este repositório é uma versão aprimorada local (baseada no PyPI phocinae-mcp 0.1.1), usada apenas para desenvolvimento local e validação de alinhamento de protocolo, não publicada.

Ferramentas

S07 演示动画

▲ **Animação de demonstração sintética** (modelo repo docs/gallery [S07](https://huggingface.co/Phocinae/Phocinae-Largha-150M-v1/blob/main/docs/gallery)): as imagens são renderizadas quadro a quadro, os dados da cena são fictícios, mas o **processo de decisão da ferramenta `route` "uma passagem direta seleciona a ferramenta a ser usada entre as candidatas"** que ela demonstra é consistente com a implementação real (a captura de tela do terminal acima é o mesmo fluxo executado de verdade).

FerramentaFunçãoEntradaSaída
gateDecide se um comando shell pode ser executadocommand, cwd?, server?decision ∈ allow/deny/ask + layer/reason
classifyClassifica um estado em um dos rótulos candidatosstate, labels, server?choice (índice) + label
routeSeleciona a ferramenta mais adequada entre as candidatasstate, tools, server?choice + tool
scorePontua um estado de 2 a 10 conforme critériosstate, criteria, server?score + range

fail-closed: quando o serviço P0 do Phocinae (/v1/systemone) está indisponível, expira ou responde de forma anômala, gate sempre retorna deny (com motivo), e classify/route/score retornam isError: true.

Transporte

stdio (padrão)

python3 -m phocinae_mcp --server http://127.0.0.1:8155

O cliente MCP inicia o processo como subprocesso, usando stdin/stdout para quadros JSON-RPC linha a linha. Garantia de pureza do stdout: o stdout emite apenas quadros JSON-RPC; todos os logs (inicialização, avisos, exceções internas das ferramentas) vão apenas para o stderr (prefixo phocinae-mcp[level]:). Impressões durante a importação do guard.py também são redirecionadas para o stderr, sem poluir o canal do protocolo.

Streamable HTTP (novo, 2026-07-28)

python3 -m phocinae_mcp --transport http --host 127.0.0.1 --port 8255
# --port 0 → 随机端口(测试用);端口号打印在 stderr
  • Somente bind em loopback: --host aceita apenas 127.0.0.1 / localhost / ::1; outros endereços recusam a inicialização diretamente (exit 2);
  • Endpoint POST /mcp; notificações → 202 Accepted (body vazio); requisições → 200 JSON de objeto único;
  • Validação obrigatória de cabeçalhos (Server Validation): MCP-Protocol-Version é obrigatório e deve ser suportado (caso contrário 400 + -32020/-32022), Mcp-Method é obrigatório e deve ser igual ao method do body (tools/call, resources/read também exigem Mcp-Name igual a name/uri); violações → 400 -32020; Accept sem application/json / text/event-stream → 406; método desconhecido → 404 -32601; GET/DELETE → 405 (em 2026-07-28, o fluxo GET e o endpoint de término de sessão foram removidos);
  • Sem cabeçalho de sessão (Mcp-Session-Id), sem buffer de recuperação SSE — serviço sem estado, pode ser reiniciado arbitrariamente.

Variáveis de ambiente: PHOCINAE_MCP_TRANSPORT=stdio|http, PHOCINAE_MCP_HTTP_PORT podem substituir as opções de linha de comando.

Alinhamento de protocolo (2026-07-28)

Dois protocolos coexistem, despacho por requisição:

  • Requisições com params._meta (incluindo a chave io.modelcontextprotocol/*), bem como server/discover, resources/* → face moderna;
  • Handshake initialize, requisições sem _meta → face antiga (comportamento 2024-11-05, consistente com o 0.1.x original).

Itens complementares da face moderna:

ItemImplementação
server/discoverObrigatório: supportedVersions, capabilities, _meta.serverInfo, instructions, ttlMs=3600000, cacheScope=public
Validação _metaPor requisição, obrigatório protocolVersion + clientCapabilities; ausência → -32602; versão não suportada → -32022 (data.supported/data.requested)
resultTypeTodos os resultados carregam (complete / input_required)
ttlMs/cacheScopediscover, tools/list, resources/* (conteúdo estático, cache compartilhado public)
Interação multi-turno (MRTR)Quando gate retorna ask e o cliente declara a capacidade elicitation → resultType=input_required + inputRequests.gate_confirmation (elicitation/create, form) + requestState; recibo accept/decline/cancel → allow/deny/não autorizado; requestState é HMAC-SHA256 anti-adulteração + expiração de 10 minutos + comparação de impressão digital da requisição (tool+command), adulteração/expiração reenvia a interação automaticamente
resourcesresources/list + resources/read expõem o texto completo da política de aprovação phocinae://policy/gate-approval (text/markdown, incluindo a cadeia de decisão L0/L1/fail-closed, limites, obrigações de tratamento de ask)
Métodos removidosNa face moderna, initialize/ping/shutdown/logging/setLevel/subscriptions/listen → -32601 (data anexa supportedVersions)
Schema de ferramentas mais rígidomaxLength (command/state 20000, cwd 4096, server 2048, itens de lista 2000), minItems/maxItems (1–100), enum (decision/layer), outputSchema declaração completa (classify/route/score additionalProperties:false); o servidor executa validação síncrona com o mesmo critério (exceder limite → -32602)
Reescrita de descriptionAs quatro ferramentas foram reescritas na estrutura "quando usar / quando não usar"
LogsTodos vão para o stderr; em _meta, gate controlado por io.modelcontextprotocol/logLevel (a partir de info, campo de protocolo de log de nível MCP)

Compatibilidade: o handshake initialize de clientes antigos retorna capacidades de 2024-11-05; tools/list/tools/call sem _meta respondem no modo antigo (sem erro) — zero quebra para clientes antigos.

Execução

gate 工具真实判定

▲ Decisão real do `tools/call`: L0 decide comandos seguros/perigosos, apenas a zona cinzenta chama o 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 o guard.py do phocinae-guard (tabela determinística L0 + orquestração L1), detecta automaticamente o ../phocinae-guard/guard.py no mesmo nível; se não encontrar, o gate degrada para duas perguntas HTTP puras noul+score (engine: "http:noul+score"). Ao importar o guard, não escreve __pycache__ (reutilização somente leitura).

Testes

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 um cliente MCP, via stdio executa sequencialmente o fluxo antigo initialize → notifications/initialized → ping → tools/list → tools/call com a matriz completa de ferramentas (incluindo ramos de falha) → shutdown; na era moderna discover → tools/list → matriz completa de ferramentas (gate allow/deny/ask, MRTR aceitar/recusar/cancelar/adulterar, fail-closed, exceder schema, -32602/-32022/-32601, resources) → notificação. Também audita o stdout linha a linha (cada linha deve ser um quadro JSON-RPC, zero vazamento de logs, sem traceback).
  • test_http.py: matriz de validação de cabeçalhos HTTP (-32020/-32022/406/405/404/202) + fluxo completo MRTR + resources.
  • Os dois testes compartilham tests/mock_systemone.py (serviço P0 mock determinístico, sem executar modelo).

Diretório

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 服务

Declaração de segurança (mesmo critério do ecossistema Phocinae)

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

▲ `test_mcp.py` 42/42 + `test_http.py` 18/18: quadros com UTF-8 forçado, independente de locale (este é um defeito real presente no 0.1.x)

  • O resultado ask de gate exige que o integrador apresente o comando e o motivo a um humano; sem aprovação explícita, não deve executar (na face moderna, via interação de elicitação; na era antiga, via texto do resultado);
  • O resultado da decisão não constitui qualquer promessa de responsabilidade legal; fail-closed é o único padrão;
  • O texto completo da política de aprovação está no recurso phocinae://policy/gate-approval (resources/read).