9.2 KiB
Enterprise MCP Service Bus — Reference Implementation
Implementação executável da arquitetura descrita em ../README.md, planejada em ../docs/RI-PLANNING.md.
Status: núcleo de enforcement do Marco M1 concluído e testado ponta a ponta (auth real → entitlement → PDP → decisão no Gateway, com OPA e um servidor JWKS reais — não mocks). Ver "O que existe hoje" abaixo. Os demais marcos estão descritos em
docs/RI-PLANNING.md, seção 8.7.
Quickstart (sem Docker)
make install # cria .venv e instala o pacote em modo editável (dev extras inclusos)
make lint # ruff check + ruff format --check
make typecheck # mypy --strict
make test # pytest (38 testes: unit + e2e)
make test precisa do binário opa no PATH (ou OPA_BINARY apontando para ele) para os testes que exercitam o PDP de verdade — ver "Como instalar o OPA" abaixo. Sem ele, esses testes são pulados (pytest.skip), não falham.
Como instalar o OPA (sem Docker)
OPA é um binário Go estático — não precisa de Docker nem de build:
curl -sL -o /tmp/opa "https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static"
chmod +x /tmp/opa
cp /tmp/opa .venv/bin/opa # coloca no PATH do venv
opa version # confirma
Versão usada durante o desenvolvimento desta RI: OPA v1.20.2 (Rego v1 é o padrão — as policies em config/policies/*.rego usam import rego.v1).
Subir a stack completa localmente (sem Docker)
source .venv/bin/activate
opa run --server --addr 127.0.0.1:8181 config/policies/ &
python3 -m example_mcp_servers.sales_domain.server &
# Sem OIDC_JWKS_URL/OIDC_ISSUER, o Gateway roda em modo "sem IdP configurado":
# nega tudo por padrão (ver "Dois modos de deployment" abaixo).
python3 -m emcp_bus.gateway.server
Para autenticação real, seria necessário apontar OIDC_JWKS_URL/OIDC_ISSUER para um IdP OIDC de verdade (Keycloak, EP-01-T01 — não validado nesta sessão, ver abaixo). Os testes automatizados (tests/e2e/conftest.py) substituem isso por um servidor JWKS local real + tokens RS256 reais assinados na hora — válido para provar a lógica de validação de token, não para provar o Keycloak em si.
Quickstart (Docker)
docker compose --profile core up --build
Nota:
docker-compose.ymle os Dockerfiles emdeploy/docker/não foram validados com um daemon Docker real nesta sessão (ambiente semdockerdisponível) — foram escritos e revisados manualmente, e a stack equivalente foi validada rodando os processos diretamente no host. Rodedocker compose --profile core up --buildna primeira vez em um ambiente com Docker e reporte qualquer ajuste necessário. Odocker-compose.ymlatual ainda não inclui OPA/Keycloak como serviços — apenas gateway + sales-domain (perfilcore, herdado do M0); isso é trabalho pendente do M1 (ver tabela abaixo).
Dois modos de deployment (importante)
O Gateway (src/emcp_bus/gateway/server.py) suporta dois modos, sempre deny by default:
- Com OIDC configurado (
OIDC_JWKS_URL+OIDC_ISSUERdefinidos): o próprio middleware de auth do SDKmcp(RequireAuthMiddleware) rejeita qualquer conexão sem bearer token válido antes mesmo do handshakeinitialize— mais estrito que qualquer checagem no nível do handler. - Sem OIDC configurado (padrão se as env vars não estiverem definidas): nenhum middleware de auth é instalado; toda requisição chega aos handlers com
get_access_token() is None, e é a própria lógica do handler (on_list_tools/on_call_tool) que nega por padrão —tools/listvazio,tools/callsempre negado comAccess denied: UNAUTHENTICATED.
Os dois modos são testados explicitamente em tests/e2e/test_governed_gateway.py.
O que existe hoje
| Tarefa | Componente | Status |
|---|---|---|
| EP-00 (completo) | Scaffold, config loader, docker-compose base | ✅ (ver README anterior/git history) |
| EP-01-T02 | Schema de registro de MCP Client | ✅ src/emcp_bus/identity/models.py |
| EP-01-T03 | Middleware de autenticação OIDC/JWT | ✅ validado com JWKS real + tokens RS256 reais (assinatura, expiração, issuer, audience) |
| EP-01-T01 | Keycloak (realm export, serviço no compose) | ❌ não implementado — sem Java neste ambiente para validar; ver "Limitações desta sessão" |
| EP-01-T05 | Lint de shared client | ❌ não implementado (prioridade could) |
| EP-02 (Registry) | Schema de capability manifest | ✅ src/emcp_bus/registry/models.py (schema apenas — pipeline/storage/API ainda não) |
| EP-02-T02/T03/T05 | Publishing pipeline, storage, manifests de exemplo | ❌ não implementado |
| EP-03 (completo) | PDP/OPA: entitlement.rego, transaction.rego, cliente Python, contrato de decisão | ✅ validado com OPA real (binário, não mock) — 9 testes Rego nativos + 6 testes Python de integração |
| EP-04 (completo) | Entitlement Manager: resolve, revoke, versionamento | ✅ validado com OPA real + YAML reais de config/clients/ |
| EP-05-T01 | Gateway skeleton | ✅ (M0) |
| EP-05-T02 | tools/list filtrado por entitlement |
✅ testado (README.md §45 Teste 1) |
| EP-05-T04 | tools/call reautorizado via PDP |
✅ testado (Teste 2, Teste 4 — agent role spoofing sem efeito) |
| EP-05-T06 | Fail-closed (PDP indisponível) | ✅ testado — lifespan() recusa subir se o OPA sync falhar |
| EP-05-T03 | Cache privado de tools/list |
❌ não implementado |
| EP-05-T07 | Anti-bypass (isolamento de rede) | ❌ não implementado (depende de docker-compose real) |
| EP-05-T08 | Consistência header/body (Mcp-Method/Mcp-Name) | ❌ não implementado explicitamente (o SDK já expõe os headers nativamente — ver §22 do README de arquitetura; falta o passo de validação cruzada) |
| EP-06-T01 | Fabric core (roteador por capability) | ❌ ainda roteamento estático (uma única URL fixa), não por Registry |
| EP-06-T02 | MCP Server de exemplo — Sales | ✅ (M0) |
| EP-06-T03 | MCP Server de exemplo — Finance | ❌ não implementado — os testes de negação para tools finance.* passam porque o PDP nega antes de qualquer tentativa de roteamento ao backend, então a ausência do servidor Finance real não invalida esses testes, mas nenhum cenário de sucesso em Finance foi exercitado |
| EP-06-T04 | Adapter REST genérico | ❌ não implementado |
| EP-08-T01 | Tracing OTel | ✅ (M0) |
| EP-08-T02/T03/T04 | Eventos de auditoria (IC/NOC/GRL), correlação, stack de observabilidade | ❌ não implementado — hoje só existe o trace OTel, sem taxonomia de eventos nem sink de auditoria |
39 testes automatizados, todos reais (sem mocks do núcleo de segurança): OPA de verdade (subprocess), JWKS HTTP real + JWT RS256 reais, YAML reais de config/.
Limitações desta sessão
Nenhum docker nem java disponíveis no ambiente onde esta RI foi escrita:
- Docker: não validado (ver nota acima). Risco considerado baixo — o Dockerfile usa a mesma instalação (
pip install -e .) já validada localmente. - Keycloak: não implementado nem validado — precisa de JVM. A lógica de validação de OAuth2/OIDC (
TokenValidator, EP-01-T03) é padrão-agnóstica de IdP (qualquer provedor OIDC compliant funciona) e foi validada com um servidor JWKS real + tokens RS256 reais, o que prova a lógica de validação mas não prova a integração específica com Keycloak (realm config, client credentials grant, claims exatas que o Keycloak emite). EP-01-T01 continua pendente.
Versões fixadas
Ver pyproject.toml. Confirmadas via pip index versions/download direto em 2026-09-11 (não citadas de memória — ver docs/RI-PLANNING.md, EP-16-T04):
mcp2.2.0 (SDK v2 — API mudou significativamente da v1; ver comentários emsrc/emcp_bus/gateway/server.py)pydantic2.13.x,opentelemetry-sdk1.44.x,uvicorn0.52.x,pyjwt[crypto]2.14.x,ruff0.16.x,mypy2.3.x,pytest9.1.xOPA1.20.2 (binário estático, Rego v1 padrão)
Estrutura
Ver ../docs/RI-PLANNING.md, seção 8.5, para a árvore completa planejada. O que existe até agora:
RI/
├── pyproject.toml
├── Makefile
├── docker-compose.yml # perfil "core": gateway + sales-domain (OPA/Keycloak pendentes)
├── .env.example
├── deploy/docker/Dockerfile
├── config/
│ ├── policies/ # EP-03: entitlement.rego, transaction.rego (+ testes opa test)
│ └── clients/ # EP-01/EP-04: registrations + profiles/*.yaml
├── src/emcp_bus/
│ ├── common/{config,otel,models}.py # EP-00-T02, EP-08-T01, risk tier compartilhado
│ ├── identity/{models,authn,token_verifier}.py # EP-01-T02/T03
│ ├── entitlement/{models,manager}.py # EP-04
│ ├── registry/models.py # EP-02-T01 (schema apenas)
│ ├── pdp/{client,models}.py # EP-03
│ └── gateway/server.py # EP-05-T01/T02/T04/T06
├── services/example_mcp_servers/sales_domain/server.py # EP-06-T02
└── tests/
├── unit/ # schemas, PDP client, entitlement manager, authn — todos contra dependências reais
└── e2e/ # conftest.py (fixtures compartilhados), walking skeleton, governed gateway