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-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.
▲ 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
▲ **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).
| Ferramenta | Função | Entrada | Saída |
|---|---|---|---|
gate | Decide se um comando shell pode ser executado | command, cwd?, server? | decision ∈ allow/deny/ask + layer/reason |
classify | Classifica um estado em um dos rótulos candidatos | state, labels, server? | choice (índice) + label |
route | Seleciona a ferramenta mais adequada entre as candidatas | state, tools, server? | choice + tool |
score | Pontua um estado de 2 a 10 conforme critérios | state, 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:
--hostaceita apenas127.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 →200JSON de objeto único; - Validação obrigatória de cabeçalhos (Server Validation):
MCP-Protocol-Versioné obrigatório e deve ser suportado (caso contrário400+-32020/-32022),Mcp-Methodé obrigatório e deve ser igual ao method do body (tools/call,resources/readtambém exigemMcp-Nameigual aname/uri); violações →400 -32020;Acceptsemapplication/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 chaveio.modelcontextprotocol/*), bem comoserver/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:
| Item | Implementação |
|---|---|
server/discover | Obrigatório: supportedVersions, capabilities, _meta.serverInfo, instructions, ttlMs=3600000, cacheScope=public |
Validação _meta | Por requisição, obrigatório protocolVersion + clientCapabilities; ausência → -32602; versão não suportada → -32022 (data.supported/data.requested) |
resultType | Todos os resultados carregam (complete / input_required) |
ttlMs/cacheScope | discover, 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 |
| resources | resources/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 removidos | Na face moderna, initialize/ping/shutdown/logging/setLevel/subscriptions/listen → -32601 (data anexa supportedVersions) |
| Schema de ferramentas mais rígido | maxLength (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 description | As quatro ferramentas foram reescritas na estrutura "quando usar / quando não usar" |
| Logs | Todos 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
▲ 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)
▲ `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
askdegateexige 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).