MCP Audit Gateway

Gateway MCP que adiciona RBAC por ferramenta, isolamento de tenant, exportação de auditoria e redação de PII a qualquer servidor.

Documentação

MCP Audit Gateway

CI License: MIT Python

Gateway MCP que adiciona RBAC por ferramenta e um registro de auditoria exportável a qualquer servidor MCP, além de isolamento por tenant, redação de PII em resultados de ferramentas, limites de taxa por tenant e políticas de permitir/negar em nível de tenant. Ele fica entre um cliente MCP (Claude Desktop, um runtime de agente, seu próprio aplicativo) e um ou mais servidores MCP upstream. O caso concreto para o qual foi construído: colocar RBAC por ferramenta e um registro de auditoria exportável na frente de um servidor MCP do QuickBooks ou HubSpot, para que cada tools/call contra os livros passe por um ponto de estrangulamento aplicável, registrado e redigido.

Relacionados: QuickBooks Online MCP Server · HubSpot CRM MCP Server · O que o MCP de produção realmente exige

Aponte-o para qualquer servidor MCP, descreva seus tenants e papéis em YAML, e a política é um único arquivo que você pode ler em uma revisão. Assinatura de solicitação HMAC e transportes stdio e HTTP streamable estão incluídos. MIT, sem camada paga.

Por que isso existe

Um servidor MCP puro expõe todas as ferramentas a qualquer chamador, sem identidade, sem cota, sem registro e sem redação. Isso é aceitável em um laptop, mas não é viável em um produto multi-tenant. Este gateway adiciona esse plano de controle sem tocar no servidor upstream. O artigo complementar, docs/what-production-mcp-actually-requires.md, percorre cada recurso com uma história concreta de falha.

Ferramentas

O gateway não expõe ferramentas próprias. Ele faz proxy de tools/list e tools/call para os servidores MCP upstream configurados para o tenant chamador, colocando cada ferramenta com proxy em um namespace como <upstream>.<tool> e aplicando filtragem RBAC, limitação de taxa e redação de PII no caminho. Iniciado sem upstreams configurados, initialize e tools/list ainda são bem-sucedidos e a lista de ferramentas retorna vazia.

Sua própria superfície é o plano de controle da CLI:

  • validate: verifica um arquivo de política (papéis, principais, tenants, upstreams, detectores) antes de servir qualquer tráfego.
  • serve --transport stdio: executa o gateway via stdio para um cliente MCP local, como o Claude Desktop.
  • serve --transport http: executa o gateway via HTTP streamable para clientes remotos ou agentes.
  • audit export --format csv: exporta o registro de auditoria como CSV para uma planilha ou ingestão em SIEM.
  • audit export --format json: exporta os mesmos registros como JSON.

Prova: a demonstração com dois tenants

A evidência aqui é uma demonstração que você mesmo executa, não um site em que peço para confiar. demo/run_demo.py coloca o gateway na frente de dois tenants, acme (um subprocesso upstream stdio) e globex (um upstream HTTP streamable), e executa doze cenários que exercitam RBAC, kill-switches de tenant, redação de PII, isolamento entre tenants, assinatura HMAC, rejeição de ferramenta desconhecida e limitação de taxa por tenant contra o servidor MCP de brinquedo incluído. Não há instância hospedada para manter viva nem serviço externo para alcançar; tudo roda em loopback e termina em segundos.

A saída confirmada é o artefato:

  • docs/demo-transcript.md: cada etapa, a decisão do gateway e o resultado que o cliente realmente viu, seguidos por uma tabela resumo dos resultados de auditoria.
  • docs/demo-audit.csv: a trilha de auditoria completa legível por máquina que a mesma execução produziu.

Ambos os arquivos são regenerados literalmente por python demo/run_demo.py, para que a transcrição e sua tabela de auditoria sempre reconciliem com uma execução que você pode reproduzir localmente.

Arquitetura

flowchart LR
    subgraph Clients
        C1[Tenant A client]
        C2[Tenant B client]
    end

    subgraph Gateway [mcp-audit-gateway]
        direction TB
        AUTH[Authenticate principal] --> SIG[Verify HMAC signature]
        SIG --> RBAC[RBAC and allow/deny policy]
        RBAC --> RL[Per-tenant rate limit]
        RL --> ROUTE[Resolve tenant upstream]
        ROUTE --> RED[PII redaction on result]
        RED --> AUD[(Audit log JSONL)]
    end

    subgraph Upstreams
        U1[Tenant A MCP server<br/>stdio]
        U2[Tenant B MCP server<br/>streamable HTTP]
    end

    C1 -->|signed JSON-RPC| AUTH
    C2 -->|signed JSON-RPC| AUTH
    ROUTE --> U1
    ROUTE --> U2
    U1 --> RED
    U2 --> RED
    RED -->|redacted result| C1

Cada solicitação é autenticada para um principal, que a vincula a exatamente um tenant e papel. Um tenant só pode alcançar seus próprios upstreams, credenciais e estado. O pipeline faz curto-circuito no primeiro portão que falha e registra a decisão.

Recursos

RecursoO que faz
RBAC por ferramentaListas de permitir/negar de papel para ferramenta com padrões glob; negar sempre vence.
Isolamento por tenantCada tenant recebe seus próprios processos/endpoints upstream, credenciais, catálogo de ferramentas, balde de limite de taxa e estado. Nomes de ferramentas entre tenants são invisíveis.
Registro de auditoriaJSONL somente de anexação de quem chamou qual ferramenta, com quais argumentos (redigidos), status do resultado, latência e contagens de redação. Exportável para CSV e JSON.
Redação de PIIDetectores configuráveis (email, telefone, SSN, SIN canadense, cartão de crédito) aplicados aos resultados das ferramentas antes de saírem do gateway. Modos mask, hash ou partial.
Limitação de taxaBalde de tokens por tenant (requests_per_minute + burst).
Políticas de permitir/negarKill-switch de ferramenta em nível de tenant que substitui papéis: uma camada de governança acima do RBAC.
Assinatura de solicitaçãoHMAC-SHA256 sobre o corpo da solicitação com uma janela de frescor de timestamp para impedir replay.
Transportesstdio e HTTP streamable nos lados voltados para o cliente e para o upstream.

Início rápido

uv venv --python 3.12
uv pip install -e ".[dev]"

# Validate the bundled two-tenant demo config
python -m mcp_gateway validate --config config/demo.yaml

# Run the full scripted demo (starts a stdio upstream and an HTTP upstream,
# proves tenant isolation, and writes docs/demo-transcript.md)
python demo/run_demo.py

Instalado como pacote, os mesmos comandos são executados pelo script de console mcp-audit-gateway.

Executando sem configuração

O gateway inicia sem nenhum arquivo de configuração, que é o que um cliente MCP ou um rastreador de registro vê em uma primeira sondagem tools/list:

mcp-audit-gateway serve --transport stdio

Isso atende a um principal local contra zero upstreams: initialize e tools/list são bem-sucedidos, a lista de ferramentas está vazia, nada é gravado em disco. Aponte-o para um arquivo de política para torná-lo útil, seja com --config ou definindo MCP_AUDIT_GATEWAY_CONFIG.

Executando o gateway

# Streamable HTTP, for remote/agent clients (reads host/port from the config)
python -m mcp_gateway serve --config config/demo.yaml --transport http

# stdio, for a local client such as Claude Desktop (pins the session to a principal)
python -m mcp_gateway serve --config config/demo.yaml --transport stdio --principal acme-admin

--principal é necessário apenas quando a configuração define mais de um; com um único principal, a sessão stdio o utiliza.

O tenant globex da demonstração faz proxy de um upstream HTTP esperado em http://127.0.0.1:9100/mcp. Para servir o gateway contra demo.yaml diretamente, inicie esse upstream primeiro:

python -m mcp_gateway.toy_upstream --transport http --host 127.0.0.1 --port 9100 --dataset globex

demo/run_demo.py lida com essa conexão automaticamente em uma porta efêmera, então é a maneira mais rápida de ver tudo funcionar.

Comandos upstream stdio que começam com python ou python3 são iniciados sob o próprio interpretador do gateway, então um upstream python -m ... funciona independentemente de python estar no PATH do chamador. Qualquer outro comando é executado literalmente.

Exportando o registro de auditoria

python -m mcp_gateway audit export --input config/audit-log.jsonl --format csv --output audit.csv
python -m mcp_gateway audit export --input config/audit-log.jsonl --format json

Referência de configuração

gateway:
  name: mcp-audit-gateway-demo
  http: { host: 127.0.0.1, port: 8080 }

security:
  require_signature: true          # enforce HMAC signing on incoming requests
  signature_max_age_seconds: 300   # replay window

redaction:
  enabled: true                    # redact tool RESULTS before returning them
  mode: mask                       # mask | hash | partial
  detectors: [email, phone, ssn, sin, credit_card]
  redact_arguments: true           # also redact arguments written to the audit log

audit:
  enabled: true
  path: audit-log.jsonl            # relative to the config file's directory
  argument_logging: redacted       # redacted | full | keys_only | none

roles:                             # role -> tool allow/deny (glob patterns, deny wins)
  admin:   { allow_tools: ["*"] }
  analyst: { allow_tools: ["billing.get_*", "billing.list_*"], deny_tools: ["billing.delete_*"] }

principals:                        # a credential = one identity = tenant + role + signing secret
  - { id: acme-admin, tenant: acme, role: admin, secret: "demo-only-secret" }

tenants:
  acme:
    deny_tools: ["billing.delete_invoice"]   # optional tenant-level kill switch
    upstreams:
      - { name: billing, transport: stdio, command: ["python", "-m", "mcp_gateway.toy_upstream", "--dataset", "acme"] }
    rate_limit: { requests_per_minute: 60, burst: 10 }

As ferramentas são colocadas em namespace como <upstream>.<tool> (por exemplo, billing.get_invoice), para que os padrões de RBAC e política sejam estáveis entre tenants e colisões entre upstreams sejam impossíveis.

Executando os testes

uv run pytest

A suíte é totalmente offline. Os servidores MCP "externos" com os quais ela fala são o upstream de brinquedo incluído, exercitados de verdade tanto via stdio (subprocesso) quanto via HTTP streamable (loopback): sem rede, sem mocks de mocks, e termina em segundos.

Notas de segurança e escopo

  • Segredos YAML estáticos são apenas para demonstrações locais. Em produção, carregue segredos de principal de um gerenciador de segredos e prefira credenciais de curta duração por solicitação; veja o artigo.
  • A assinatura HMAC protege o salto cliente-gateway. Ela não substitui TLS ou controles de rede.
  • A redação é uma defesa em profundidade baseada em regex, melhor esforço, não uma garantia DLP certificada. Trate-a como uma camada.
  • O registro de auditoria é um registro pontual do que o gateway observou. Não é uma atestação de conformidade.
  • Faça proxy e inspecione apenas servidores MCP que você possui ou está autorizado a operar.

Contrate-me

Torno backends da era da IA e críticos para dinheiro seguros para produção: autenticação, multi-tenancy, governança e a correção monótona que evita incidentes. Disponível para trabalhos com MCP, cobrança e endurecimento. Portfólio e contato: https://amin-ale.github.io/portfolio-site · amin.ale.business@gmail.com.

Licença

MIT. Veja LICENSE.