@serdnaley/metabase-mcpSAFE
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
MCP server for Metabase — comprehensive coverage of the Metabase REST API for AI assistants.
Metabase ships a built-in MCP for querying data. This project goes further: 128 tools covering dashboards, questions, collections, users, permissions, alerts, settings, and more — so AI assistants can fully manage Metabase, not just read from it.
Features
- 128 MCP tools across 26 domains: search, databases, tables, collections, cards, dashboards, actions, dataset, users, groups, permissions, segments, revisions, settings, alerts, subscriptions, glossary, documents, timelines, bookmarks, moderation, snippets, x-rays, cache, persistence, uploads
- Full CRUD: Create, read, update, delete across all domains
- Admin automation: User/group management, permissions, settings, database connections
- Read-only mode: Restrict to read-only tools via a single env var
- Type-safe: HTTP client generated from Metabase's OpenAPI spec
- Two auth modes: API key (recommended) or email/password session
- Zero config: Runs via
npx— no installation needed
Installation
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"metabase": {
"command": "npx",
"args": ["-y", "@serdnaley/metabase-mcp"],
"env": {
"METABASE_URL": "https://your-metabase.example.com",
"METABASE_API_KEY": "mb_xxx"
}
}
}
}Restart Claude Desktop after saving.
Claude Code (CLI)
claude mcp add metabase \ --env METABASE_URL=https://your-metabase.example.com \ --env METABASE_API_KEY=mb_xxx \ -- npx -y @serdnaley/metabase-mcp
Or add to .claude/mcp.json:
{
"mcpServers": {
"metabase": {
"ty64a9a00cc48fOBSERVED · 2026-10-12Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add metabase-mcp --env METABASE_API_KEY=${METABASE_API_KEY} --env METABASE_PASSWORD=${METABASE_PASSWORD} -- npx -y @serdnaley/[email protected]{
"mcpServers": {
"metabase-mcp": {
"command": "npx",
"args": [
"-y",
"@serdnaley/[email protected]"
],
"env": {
"METABASE_API_KEY": "${METABASE_API_KEY}",
"METABASE_PASSWORD": "${METABASE_PASSWORD}"
}
}
}
}Exposed tools (128)
53 read · 53 write · 22 destructive. Blast radius: 22 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
add_group_member | write | Add a user to a Metabase permission group |
copy_card | read | Copy a card to a collection |
copy_dashboard | read | Copy a dashboard to a collection |
create_action | write | Create a new action (query or implicit only — HTTP actions are not supported) |
create_action_public_link | write | Generate a public link for an action form |
create_alert | write | Create an alert on a saved question. Alerts notify recipients via email or Slack when query results meet a condition. |
create_bookmark | write | Bookmark a card, dashboard, or collection |
create_card | write | Create a new question (native SQL or structured query) |
create_card_public_link | write | Generate a public sharing link for a card. Returns the card with a public_uuid field. The public URL is {metabase_url}/public/question/{uuid}. Public sharing must be enabled in Metabase admin settings. |
create_collection | write | Create a new collection |
create_dashboard | write | Create a new dashboard |
create_dashboard_public_link | write | Generate a public sharing link for a dashboard. Returns the dashboard with a public_uuid field. The public URL is {metabase_url}/public/dashboard/{uuid}. Public sharing must be enabled in Metabase admin settings. |
create_dashboard_subscription | write | Create an email or Slack subscription for a dashboard. Subscriptions deliver a snapshot of the dashboard on a schedule. |
create_database | write | Add a new database connection to Metabase |
create_document | write | Create a narrative analytics document |
create_glossary_term | write | Create a business glossary term |
create_group | write | Create a new Metabase permission group |
create_moderation_review | destructive | Mark a card or dashboard as verified or remove verification (Pro/Enterprise) |
create_segment | write | Create a new segment |
create_snippet | write | Create a reusable SQL snippet |
create_timeline | write | Create a timeline for annotating charts |
create_timeline_event | write | Create an event on a timeline |
create_user | write | Create a new Metabase user |
deactivate_user | destructive | Deactivate a Metabase user (soft-delete). The user record is retained but access is disabled. |
delete_action | destructive | Delete an action |
delete_action_public_link | destructive | Remove the public link from an action |
delete_alert | destructive | Delete an alert |
delete_bookmark | destructive | Remove a bookmark from a card, dashboard, or collection |
delete_card | destructive | Delete a card (question) |
delete_card_public_link | destructive | Remove the public sharing link from a card |
delete_dashboard | destructive | Delete a dashboard |
delete_dashboard_public_link | destructive | Remove the public sharing link from a dashboard |
delete_dashboard_subscription | destructive | Delete a dashboard subscription |
delete_database | destructive | Delete a database connection from Metabase |
delete_document | destructive | Delete a document |
delete_glossary_term | destructive | Delete a glossary term |
delete_group | destructive | Delete a Metabase permission group |
delete_segment | destructive | Delete (archive) a segment |
delete_snippet | destructive | Archive (soft-delete) a SQL snippet |
delete_timeline | destructive | Delete a timeline |
delete_timeline_event | destructive | Delete a timeline event |
discard_field_values | destructive | Clear cached field values for a field |
execute_action | write | Run an action with optional parameters |
execute_card_query | write | Run a saved question and return results. For parameterized cards, pass template tag values as key-value pairs (e.g. { fromDate: |
execute_query | write | Run an ad-hoc query (native SQL or structured) and return results |
generate_xray | read | Generate an automatic X-ray exploratory dashboard for a table |
get_action | read | Get action details |
get_activity | read | Get recent activity feed (user actions, views, etc.) |
get_alert | read | Get details of a specific alert |
get_card | read | Get card details (query definition, visualization settings) |
get_collection | read | Get collection details |
get_collection_permissions | read | Get the collection permissions graph (which groups can access which collections) |
get_collection_tree | read | Get the full collection hierarchy as a tree |
get_current_user | read | Get the currently authenticated Metabase user |
get_dashboard | read | Get dashboard with all cards and layout |
get_database | read | Get database details by ID |
get_database_metadata | read | Get full database metadata: tables, fields, types, relationships |
get_database_schema | read | Get tables within a specific database schema |
get_document | read | Get a document by ID |
get_field | read | Get field details including type, special type, fingerprint |
get_field_values | read | Get sample values for a field |
get_glossary_term | read | Get a glossary term by ID |
get_permissions_graph | write | Get the full data permissions graph (view-data and create-queries permissions per group per database) |
get_segment | read | Get segment by ID |
get_setting | read | Get a specific Metabase setting value |
get_snippet | read | Get a SQL snippet by ID |
get_table | read | Get table details and field info |
get_table_query_metadata | read | Get full query metadata for a table (fields, FKs, metrics) |
get_task | read | Get details of a specific background task |
get_timeline | read | Get a timeline by ID |
get_user | read | Get a Metabase user by ID |
invalidate_cache | read | Invalidate cached query results |
list_actions | read | List all actions |
list_alerts | read | List all alerts configured in Metabase |
list_bookmarks | read | List all bookmarks for the current user |
list_cards | read | List all saved questions |
list_collection_items | read | List items in a collection (cards, dashboards, sub-collections) |
list_collections | read | List all collections |
list_dashboard_subscriptions | read | List email/Slack subscriptions for a dashboard |
list_dashboards | read | List all dashboards |
list_database_schemas | read | List schemas in a database |
list_databases | read | List all databases the user has access to |
list_documents | read | List all narrative analytics documents |
list_glossary_terms | read | List all business glossary terms |
list_groups | read | List all Metabase permission groups |
list_revisions | read | List revision history for a card or dashboard |
list_segments | read | List all segments |
list_settings | read | List all Metabase instance settings |
list_snippets | read | List all SQL snippets |
list_tasks | read | List all scheduled background tasks and their status |
list_timelines | read | List all timelines |
list_users | read | List all Metabase users. Supports optional search query to filter by name or email. |
notify_database | write | Send a post-ETL pipeline notification to trigger a schema sync on a database |
persist_model | write | Enable persistence (materialization) for a model card |
reactivate_user | read | Reactivate a previously deactivated Metabase user |
refresh_persisted_model | write | Manually trigger a refresh of the materialized data for a persisted model |
remove_group_member | destructive | Remove a user from a Metabase permission group by membership ID |
reorder_fields | write | Set a custom field ordering for a table by providing an ordered list of field IDs |
rescan_field_values | write | Trigger a re-scan of field values used to populate filter dropdowns |
revert_revision | read | Revert a card or dashboard to a prior revision |
search | read | Search across all Metabase entities (cards, dashboards, collections, tables, etc.) |
sync_database_schema | write | Trigger a schema resync on a database (use after DDL changes to pick up new or modified tables) |
translate_entity_ids | read | Translate serialization entity IDs to API integer IDs |
unpersist_model | write | Disable persistence (materialization) for a model card |
update_action | write | Update an action (cannot change type to http) |
update_alert | write | Update an existing alert. Only the fields you provide will be changed. |
update_cache_config | write | Update cache strategy for a model (database, dashboard, or card) |
update_card | write | Update question query, display, name, or other properties |
update_collection | write | Update collection properties |
update_collection_permissions | write | Update the collection permissions graph. Must include the |
update_dashboard | write | Update dashboard properties (name, description, filters) |
update_dashboard_cards | destructive | Add, remove, or reposition cards on a dashboard |
update_dashboard_subscription | write | Update a dashboard subscription (schedule, channels, parameters) |
update_database | write | Update an existing database connection configuration |
update_document | write | Update a document |
update_field | write | Update field display name, description, semantic type, visibility, or FK target |
update_glossary_term | write | Update a glossary term |
update_group | write | Update the name of a Metabase permission group |
update_permissions_graph | write | Update the data permissions graph. Must include the |
update_segment | write | Update an existing segment |
update_setting | write | Update a Metabase setting value |
update_snippet | write | Update a SQL snippet |
update_table | write | Update table display name, description, visibility type, or entity type |
update_timeline | write | Update a timeline |
update_timeline_event | write | Update a timeline event |
update_user | write | Update an existing Metabase user. Only provided fields will be updated. |
upload_csv | write | Upload a CSV file as a new table in Metabase |
validate_database | read | Test database connection parameters before saving to verify credentials and connectivity |
Trust audit
SAFEgrade B · trust 87/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (1 observation(s))
- Network
- declared (3 observation(s))
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (9)
create_moderation_review, deactivate_user, delete_action, delete_action_public_link, delete_alert, delete_bookmark, delete_card, delete_card_public_link, delete_dashboard, delete_dashboard_public_link
import { search } from "../../src/services/search.js";import { getTableQueryMetadata } from "../../src/services/tables.js";import { createCard, executeCardQuery, deleteCard } from "../../src/services/cards.js";import { executeQuery } from "../../src/services/dataset.js";import { createCollection, getCollection, listCollectionItems, updateCollection } from "../../src/services/collections.js";@modelcontextprotocol/sdk, openapi-fetch, zod, @types/bun, @types/node, openapi-typescript, typescript
generated/metabase-api.d.ts
Gates applied: no_behavioural_pass, no_license.
64a9a00cc48ffull audit observations/trust-audit/mcp-server/serdnaley__metabase-mcp.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-12 | 64a9a00cc48f | SAFE | B | 87 | first audit |
Questions
What tools does @serdnaley/metabase-mcp expose?
128 in total: 53 read-only, 53 that write, and 22 that can delete or overwrite (create_moderation_review, deactivate_user, delete_action, delete_action_public_link, delete_alert). Every one is listed on this page with its risk.
Is @serdnaley/metabase-mcp safe to connect to an agent?
The audit found nothing in the source that contradicts what it says it does, and graded it B (87/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean server reads B. Separately from the audit: 22 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does @serdnaley/metabase-mcp need?
It reads METABASE_API_KEY and METABASE_PASSWORD from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does @serdnaley/metabase-mcp run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as @serdnaley/metabase-mcp at 0.2.0.
How current is this page?
The grade is for one exact copy of the source (64a9a00cc48f), read on 2026-10-12. The repository is watched and re-audited when it changes.