Metabase
oficialServidor MCP oficial do Metabase para pesquisar dados, criar consultas na camada semântica e visualizar resultados por meio de clientes MCP.
O que você pode fazer com Metabase MCP?
- Pesquisar e recuperar conteúdo — Peça ao seu assistente para encontrar perguntas, painéis ou modelos no Metabase usando a ferramenta
searche, em seguida, busque os detalhes comget_content. - Executar consultas e visualizar resultados — Faça seu assistente executar consultas estruturadas via
execute_queryou SQL bruto comexecute_sqle, depois, renderize os resultados como gráficos interativos usandovisualize_query. - Criar e gerenciar painéis — Instrua seu assistente a criar ou atualizar painéis e seus layouts com
dashboard_write, ou duplicar conteúdo existente em coleções viaduplicate_content. - Configurar alertas e assinaturas — Peça ao seu assistente para criar alertas agendados para perguntas salvas com
alert_writeou configurar assinaturas de e-mail de painéis usandosubscription_write. - Explorar a hierarquia de dados — Direcione seu assistente para navegar por bancos de dados, esquemas, tabelas e campos através de
browse_data, ou navegue por coleções estruturalmente combrowse_collection.
Documentação
Servidor MCP do Metabase
O Metabase inclui um servidor integrado de Model Context Protocol (MCP) que permite que clientes de IA se conectem diretamente a uma instância do Metabase. Ele usa o transporte HTTP Streamable e se baseia na Agent API do Metabase para expor ferramentas de busca, navegação, consulta, visualização e criação/atualização de conteúdo — tudo limitado às permissões do usuário conectado.
Endpoint
O servidor MCP está disponível em:
https://{your-metabase.example.com}/api/metabase-mcp
O caminho legado /api/mcp ainda funciona como um alias para clientes existentes, mas /api/metabase-mcp é a
URL canônica a ser divulgada.
Conectando um cliente
Aponte qualquer cliente compatível com MCP para o endpoint /api/metabase-mcp. Por exemplo, com o Claude Code:
claude mcp add metabase https://{your-metabase.example.com}/api/metabase-mcp --transport streamable-http
Para o Claude Desktop, crie um conector personalizado usando a mesma URL.
Para o Cursor, abra Configurações > MCP e adicione um novo servidor com o tipo definido como streamable-http e a URL:
https://{your-metabase.example.com}/api/metabase-mcp
Autenticação
Os clientes MCP autenticam via OAuth 2.0. O Metabase executa seu próprio servidor OAuth incorporado — nenhum provedor externo é necessário.
O fluxo para uma primeira conexão:
- O cliente descobre os endpoints OAuth do Metabase.
- O cliente se registra no Metabase.
- O usuário é redirecionado para o Metabase para fazer login e aprovar a conexão.
- O cliente recebe um token de acesso limitado às permissões do usuário no Metabase.
Sessões baseadas em navegador (autenticação por cookie), chaves de API e tokens mb:full não possuem escopo MCP, portanto podem se conectar, mas
não podem chamar nenhuma ferramenta com escopo.
Escopos
Os tokens de acesso têm escopos que limitam quais ferramentas um cliente pode usar:
| Escopo | Ferramentas que concede |
|---|---|
agent:content:read | browse_collection, browse_data, get_content, get_parameter_values, glossary, learn, search e o recurso de dados catalog://metabase/fields (consulte Recursos) |
agent:content:write | bookmark_content, collection_write, dashboard_write, document_write, duplicate_content, measure_write, metric_write, question_write, segment_write |
agent:delivery:write | alert_write, subscription_write |
agent:query:run | execute_query, refresh_ui_credential, render_drill_through, run_saved_question, visualize_query |
agent:sql:run | execute_sql |
Uma ferramenta corresponde apenas ao escopo exato na tabela. Um curinga como * ou agent:*, e o
sentinel ::unrestricted, não são escopos MCP, portanto não concedem nenhuma ferramenta.
Esses escopos controlam apenas a superfície MCP. Nenhum endpoint REST pode declarar um deles como seu :scope, portanto um novo token emitido para um
cliente MCP não concede nada na API REST.
O scopes_supported dos metadados do recurso protegido e o scope do desafio 401 listam todos os escopos da
tabela, portanto uma nova conexão solicita todos eles. Alguns clientes não fazem step-up após um 403: uma reconexão manual
nas configurações do conector do Claude registra um novo cliente e solicita exatamente o que essas listas indicam. Quando listavam apenas o
escopo básico, essa reconexão nunca oferecia escrita, SQL bruto ou entrega, e o usuário não tinha como concedê-los
(ENG-11089). Os metadados do servidor de autorização também divulgam todos eles.
O escopo básico (agent:content:read agent:query:run) está bloqueado na tela de consentimento: quando um cliente solicita um desses,
o usuário não pode desmarcá-lo. agent:query:run está no escopo básico para que os gráficos nunca precisem de step-up. O Claude
Desktop tenta novamente uma ferramenta após um step-up em uma sessão que não declara suporte a MCP Apps, portanto um
visualize_query com step-up é recusado e seu gráfico nunca é incorporado.
Uma chamada de ferramenta ou leitura de recurso de dados para a qual o token não possui escopo é recusada com HTTP 403 e um
desafio WWW-Authenticate: Bearer error="insufficient_scope" cujo scope lista os escopos v2 que o token já
possui mais o necessário, para que um cliente possa fazer step-up. Cada ferramenta também declara seu escopo em securitySchemes, que é o
rascunho SEP-1488, suportado pelo ChatGPT. Ele não
faz parte do MCP 2025-03-26 (a versão que este servidor reporta) nem da especificação final de ferramentas de 2026-07-28, portanto outros clientes
descobrem o escopo ausente pelo 403. Dentro de um lote JSON-RPC, a recusa é um erro -32600 in-band
em vez disso. Leituras de shell de UI nunca são desafiadas: consulte Recursos.
Os metadados de recurso protegido OAuth estão disponíveis em:
/.well-known/oauth-protected-resource/api/metabase-mcp
Na tela de consentimento, todo escopo solicitado pelo cliente começa marcado, e os escopos básicos também estão bloqueados. Apenas
os escopos que permanecem marcados são concedidos, e somente para o token que esta autorização emite. Desmarcar nunca afeta um token
que o aplicativo já possui. Um escopo deixado desmarcado não é lembrado pelo Metabase. Um 403 posterior pode acionar outro step-up em
clientes que o suportam. Outros clientes podem exigir reautorização manual. O error_description de cada desafio termina
com uma nota de que o usuário deve conceder a permissão na tela de consentimento.
Vários clientes substituem o error_description do 403 por seu próprio texto, portanto o instructions do resultado initialize
também explica falhas de escopo ao modelo: um erro de autenticação geralmente significa uma permissão ausente em vez de um
login expirado, o modelo deve nomear a ferramenta ou recurso que falhou e a permissão que ele exige, e o usuário a concede
reconectando e deixando a permissão marcada na tela de consentimento. As instruções são uma única string estática, a mesma
para todos os chamadores: não há lista de permissões por conexão.
Acesso a ferramentas por grupo
Em instâncias Enterprise com o recurso ai_controls, um administrador pode restringir a superfície por grupo de permissões em Admin > IA > Controles de uso > Acesso a ferramentas MCP (exibido sempre que o servidor MCP está ativo, com ou sem um provedor de LLM). Cada grupo tem uma linha em mcp_group_permission indicando se seus membros podem se conectar e, por nome de ferramenta, o "yes" ou "no" explícito do administrador; uma ferramenta sem entrada assume o padrão declarado por seu autor, portanto todo deftool carrega um :default-access obrigatório de :allowed ou :denied, e uma ferramenta lançada posteriormente recebe exatamente esse padrão em todos os grupos até que um administrador o substitua. As entradas são indexadas por nome de ferramenta, portanto renomear uma ferramenta exige :renamed-from com seus nomes anteriores (uma entrada armazenada sob um nome anterior ainda se aplica e a API de administração a apresenta sob o nome atual), ou o autor aceita que a escolha de cada administrador para ela seja descartada; metabase.mcp.v2.tool-names-test fixa os nomes ativos para que nenhum dos dois aconteça por acidente. A política efetiva de um usuário é o tool_access de cada grupo seu cuja linha habilita MCP: o MCP está ativo quando qualquer grupo desse tipo existe, e uma ferramenta é permitida quando qualquer um desses grupos a resolve como sim. As linhas sozinhas decidem isso, e também registram o modo de permissão: modo simples (Administradores, Todos os usuários e Todos os usuários de tenant) ou modo de nível de grupo (todos os outros grupos), que é o estado em que Todos os usuários não tem linha. Um interruptor exclui as linhas dos grupos que o novo modo oculta e semeia os grupos que ele habilita na entrada que não têm linha (Analistas de dados ao entrar no modo de nível de grupo, Todos os usuários e Todos os usuários de tenant ao sair dele), e PUT recusa um grupo que o modo atual oculta, portanto nenhuma solicitação lê um modo em cache. A política é aplicada além dos escopos OAuth em tools/list e tools/call (v2/registry.clj), e um usuário cujos grupos não concedem acesso é recusado em initialize e em resources/read (para sessões abertas antes de o MCP ser desativado) com um erro nomeando a correção. Ferramentas somente de aplicativo (_meta {:ui {:visibility ["app"]}}, ou seja, refresh_ui_credential) não estão na página de administração: elas são permitidas enquanto a política permitir qualquer ferramenta de MCP Apps. Superusuários e chamadores internos nunca são restringidos; OSS permite tudo. No Enterprise, as linhas armazenadas são aplicadas mesmo sem o recurso ai_controls (um token expirado ou não verificável mantém as restrições que um administrador configurou); o recurso apenas controla a página e a API de administração. O resolvedor é permissions.clj (defenterprise, implementação EE em metabase-enterprise.mcp.permissions) e a API de administração é /api/ee/ai-controls/mcp-permissions.
Ferramentas disponíveis
Geradas a partir do registro v2 (deftool). O escopo nomeado aqui é o que o registro verifica antes de a ferramenta
ser executada; alguns manipuladores verificam um escopo adicional quando sabem o que a chamada faz — agent:sql:run quando uma fonte
resolve para SQL nativo (question_write) e agent:query:run para a execução que um alerta ou assinatura adia
(alert_write, subscription_write). Essas recusas carregam o mesmo desafio 403 insufficient_scope. tools/list
mostra todas as ferramentas, independentemente do que o token possui, e um token sem o escopo não pode chamá-la.
| Ferramenta | Escopo | Descrição |
|---|---|---|
alert_write | agent:delivery:write | Criar ou atualizar um alerta: uma notificação enviada em um agendamento quando os resultados de uma pergunta salva atendem a uma condição. |
bookmark_content | agent:content:write | Adicionar ou remover um marcador em conteúdo para o usuário que está chamando — a mesma lista de favoritos/estrelados que a barra lateral do Metabase mostra. |
browse_collection | agent:content:read | Navegar por coleções estruturalmente — um id uniforme sobre cada partição: um id numérico, um entity_id de 21 caracteres, "root" (re-enraizado por namespace) ou "trash" (conteúdo arquivado, somente no modo de itens). |
browse_data | agent:content:read | Navegar pela hierarquia de dados: bancos de dados → esquemas → tabelas → campos. |
collection_write | agent:content:write | Criar, renomear, mover, arquivar ou restaurar uma coleção — as pastas que guardam perguntas, dashboards, modelos e documentos. |
dashboard_write | agent:content:write | Criar ou atualizar um dashboard e editar seu layout com operações ordenadas. |
document_write | agent:content:write | Criar ou atualizar um documento. |
duplicate_content | agent:content:write | Copiar uma pergunta, dashboard ou documento para uma coleção — mais barato e mais seguro do que ler o original e recriá-lo, e preserva tudo o que as projeções de leitura deixam de fora. |
execute_query | agent:query:run | A forma padrão de responder a uma pergunta a partir de dados: validar e executar uma consulta estruturada (MBQL), retornando linhas mais um query_handle. |
execute_sql | agent:sql:run | Saída de emergência: executar uma string SQL bruta contra um banco de dados, retornando linhas mais um query_handle. |
get_content | agent:content:read | Buscar conteúdo por {type, id} — a leitura tipada para qualquer coisa encontrada via busca ou browse_collection. |
get_parameter_values | agent:content:read | Buscar os valores válidos para um filtro em um dashboard ou pergunta salva, para que você filtre com valores reais em vez de adivinhar. |
glossary | agent:content:read | Consultar um termo de negócio conforme definido nesta instância do Metabase; os nomes dos termos definidos acompanham a própria descrição da ferramenta. |
learn | agent:content:read | Ler a documentação de tarefas (skills) deste servidor para os dialetos de escrita que os esquemas não conseguem descrever completamente. |
measure_write | agent:content:write | Criar ou atualizar uma medida: uma agregação MBQL nomeada e reutilizável anexada a uma tabela, referenciada dentro da agregação de outra consulta como ["measure", id]. |
metric_write | agent:content:write | Criar ou atualizar uma métrica: uma agregação salva e reutilizável que vive em uma coleção e pode ser consultada por conta própria ou referenciada a partir de outras consultas. |
question_write | agent:content:write | Criar, atualizar ou arquivar uma pergunta salva ou modelo. |
refresh_ui_credential | agent:query:run | Atualizar a credencial com escopo usada por um MCP App do Metabase. |
render_drill_through | agent:query:run | Renderizar a visualização de drill-through para a qual o usuário acabou de navegar. |
run_saved_question | agent:query:run | Executar uma pergunta salva (card) por id numérico ou entity_id, retornando linhas inline. |
search | agent:content:read | Encontrar conteúdo em toda a instância do Metabase por relevância. |
segment_write | agent:content:write | Criar ou atualizar um segmento: um filtro MBQL nomeado e reutilizável anexado a uma tabela, referenciado a partir dos filtros de outras consultas. |
subscription_write | agent:delivery:write | Criar ou atualizar uma assinatura de dashboard — entrega agendada de um dashboard inteiro, por exemplo. |
visualize_query | agent:query:run | Visualizar uma consulta como um gráfico interativo ou tabela, renderizado inline na conversa. |
execute_query retorna row_limit linhas por chamada (padrão 100, máximo 2000) — um tamanho de página, não um limite no resultado.
Uma página truncada reporta truncated: true e, quando a consulta tem uma ordem total, um next_cursor para passar de volta como
cursor para a próxima página, até que uma página chegue com truncated: false. Uma consulta que quer apenas suas primeiras N linhas
carrega limit: N em seu estágio (com um order-by); o servidor gasta esse limite ao longo das páginas, então a última
página volta completa sem cursor e a paginação termina por si só.
Recursos
O servidor expõe recursos do MCP para que clientes possam buscar conteúdo complementar por URI sem inflar as descrições das ferramentas.
| URI do recurso | Escopo | Descrição |
|---|---|---|
ui://metabase/visualize-query.html | agent:query:run (somente credencial de UI) | O shell iframe dos MCP Apps para o qual visualize_query aponta um cliente capaz. |
ui://metabase/render-drill-through.html | agent:query:run (somente credencial de UI) | O shell para o qual render_drill_through aponta. |
catalog://metabase/fields | agent:content:read | Os caminhos de pontos que cada tipo de conteúdo aceita nos argumentos de fields. |
Todo recurso é listado independentemente dos escopos do token. Um recurso de dados, como o catálogo de campos, é lido apenas por um
token que possua seu escopo; caso contrário, a leitura recebe o desafio 403 insufficient_scope descrito em
Escopos. Um shell de UI é lido por qualquer token, porque um host de MCP Apps lê o shell de uma ferramenta
junto com a chamada da ferramenta, e se essa leitura fosse recusada, o host não subiria de nível após o 403 da chamada da ferramenta. Os
shells não carregam dados. Um shell lido por um token sem o escopo do shell nunca gera uma credencial de UI. Os dados do gráfico são
protegidos pela chamada da ferramenta e por refresh_ui_credential (ambos agent:query:run), que o iframe precisa antes de poder
consultar qualquer coisa. Uma URI desconhecida é um erro -32602 "Recurso não encontrado".
Os pacotes de skills são entregues por meio da ferramenta learn em vez de como recursos.
A navegação de entidades é feita com as ferramentas get_content e browse_* em vez de um esquema de URI; os recursos ui://
acima existem apenas para que um cliente que possa renderizar um iframe tenha algo para montar.
Métodos JSON-RPC suportados
| Método | Descrição |
|---|---|
initialize | Inicializar a conexão MCP. Retorna capacidades do servidor e um ID de sessão. |
notifications/initialized | Notificação do cliente de que a inicialização está completa. |
tools/list | Listar ferramentas disponíveis, independentemente dos escopos do token. |
tools/call | Chamar uma ferramenta com argumentos. |
resources/list | Listar recursos disponíveis, independentemente dos escopos do token. |
resources/read | Ler um recurso por URI; um recurso de dados precisa do seu escopo. Requer uma sessão. |
ping | Ping de keepalive. |
As solicitações podem ser enviadas individualmente ou como um lote JSON-RPC. O servidor responde com JSON ou SSE dependendo do
cabeçalho Accept.
Arquitetura
A implementação vive nestes arquivos:
-
transport.clj- O transporte HTTP. Analisa solicitações JSON-RPC, valida autenticação e cabeçalhos de sessão, aplica verificações de origem (proteção contra rebinding de DNS) e despacha para o método apropriado. Suporta tanto formatos de resposta JSON quanto SSE. -
v2/api.clj- O manipulador da superfície de ferramentas. Conecta o transporte aos registros de ferramentas e recursos v2 e define o despacho de métodos (tools/list,tools/call,resources/list,resources/read,ping). -
v2/registry.clj- O registro de ferramentas v2. As ferramentas se auto-registram viadeftool; o registro verifica escopos, valida argumentos, despacha chamadas e registra o uso. -
scope.clj- Lógica de correspondência de escopo. Somente correspondências exatas: curingas, escopos nulos e o sentinela::unrestrictednão correspondem a nada.
Fluxo de solicitação
MCP client
-> POST /api/metabase-mcp (JSON-RPC)
-> Origin + session validation
-> Auth: OAuth bearer token or browser session
-> Scope check against requested tool
-> Synthetic request to Agent API endpoint
-> Response materialized as MCP content
-> JSON or SSE back to client