Safety-gated MCP server for Metabase API access and dashboard authoring
Project description
mcp-for-metabase
mcp-for-metabase is a safety-gated Python MCP server for Metabase. It lets MCP clients and agents inspect Metabase, run governed queries, and create or maintain dashboards, cards/questions, collections, snippets, permissions, and other Metabase assets through the Metabase REST API.
The server is Docker-first, uses the official MCP Python SDK/FastMCP, and defaults to read-only mode.
Project Status
This project is in production-readiness beta. It has broad generated Metabase API coverage, curated tools for common dashboard and content workflows, Docker-first deployment, live integration coverage, and restrictive default safety gates. Some lower-frequency API areas are available through the generic executor rather than polished high-level tools.
Current highlights:
- MCP transports: stdio and Streamable HTTP.
- Auth: Metabase API key via
X-API-Key, with username/password session fallback. - Generic API coverage: 600 generated operations from the Metabase OpenAPI document.
- Curated tools for discovery, search, metadata inspection, query execution, collections, cards, dashboards, snippets, permissions, users, API keys, public links, copies, card queries, and exports.
- Generic API validation for required path/query/body fields, path/query parameter schemas, and OpenAPI JSON request-body schemas.
- Safety gates:
read-onlyby default,safe-writesfor normal content writes, andall-writesplusconfirm=truefor destructive/admin operations. dry_run=truesupport for write-capable tools.- Audit logging for mutating requests.
- CI gates for formatting, linting, typing, unit tests, MCP stdio protocol tests, Docker smoke tests, package checks, generated-registry freshness, and live Metabase integration tests across supported Docker tags.
Detailed capability tables live in docs/CAPABILITIES.md, with generated API coverage in docs/API_COVERAGE.md. Live test instructions are in docs/INTEGRATION_TESTING.md.
Installation
From PyPI, after the first public release:
python -m pip install mcp-for-metabase
From source:
git clone https://github.com/DominikPollok/mcp-for-metabase.git
cd mcp-for-metabase
python -m pip install -e ".[dev]"
The package name and primary console command are both mcp-for-metabase. The legacy metabase-mcp console command is also installed as a compatibility alias. There are similarly named Metabase MCP packages on PyPI, so check the repository URL and license metadata before installing.
Quickstart With Docker
Create an environment file:
cp .env.example .env
Edit .env:
METABASE_URL=http://metabase:3000
METABASE_IMAGE=metabase/metabase:v0.61.2
METABASE_API_KEY=your_metabase_api_key
METABASE_MCP_TRANSPORT=http
METABASE_MCP_WRITE_MODE=read-only
METABASE_MCP_SQL_GUARD_MODE=strict
METABASE_MCP_SNAPSHOT_DIR=/data/snapshots
Start the stack:
docker compose up --build
The MCP server listens on http://localhost:8000/mcp in Streamable HTTP mode. Metabase is exposed on http://localhost:3000.
Running The MCP Server
stdio:
mcp-for-metabase serve --transport stdio
Streamable HTTP:
mcp-for-metabase serve --transport http --host 0.0.0.0 --port 8000
Core environment variables:
| Variable | Required | Description |
|---|---|---|
METABASE_URL |
Yes | Metabase base URL. |
METABASE_IMAGE |
Optional | Docker Compose Metabase image tag for local integration work. |
METABASE_API_KEY |
Recommended | Preferred authentication method. |
METABASE_USERNAME / METABASE_PASSWORD |
Optional | Session-auth fallback. |
METABASE_MCP_TRANSPORT |
Optional | stdio or http. |
METABASE_MCP_WRITE_MODE |
Optional | read-only, safe-writes, or all-writes. |
METABASE_MCP_SQL_GUARD_MODE |
Optional | strict by default. Use disabled only for trusted internal deployments. |
METABASE_MCP_AUDIT_LOG |
Optional | JSONL path for mutation audit events. |
METABASE_MCP_SNAPSHOT_DIR |
Optional | Directory for durable dashboard/card/collection rollback snapshots. |
METABASE_MCP_TIMEOUT |
Optional | HTTP timeout in seconds. |
Safety Model
The server never bypasses Metabase permissions. API keys inherit their Metabase group permissions, so create a dedicated least-privileged group for agent work.
Write modes:
read-only: default. Read/query operations are allowed; mutations are blocked.safe-writes: allows common create/update/content operations.all-writes: allows destructive/admin operations only when the tool call also passesconfirm=true.
Every mutating request is audited when METABASE_MCP_AUDIT_LOG is set. Read SECURITY.md before connecting the server to production Metabase.
Native SQL guard:
strictis the default and applies to both curated tools andmetabase_api_request.- Native SQL is limited to single-statement read-only queries starting with
SELECT,WITH,EXPLAIN,SHOW,DESCRIBE, orDESC. - SQL comments, statement separators, and mutation/admin keywords such as
INSERT,UPDATE,DELETE,DROP,ALTER,TRUNCATE,MERGE,GRANT, andCALLare blocked before any request is sent to Metabase. - Native SQL snippets may be fragments, but the same separator/comment/mutation keyword blocklist applies.
- This guard is defense-in-depth; still use least-privileged Metabase API keys and database roles.
Snapshot tools persist rollback payloads under METABASE_MCP_SNAPSHOT_DIR:
metabase_snapshot_entitysaves a dashboard, card, collection, or permissions graph snapshot and returns asnapshot_id.metabase_list_saved_snapshotslists saved snapshots.metabase_restore_saved_snapshotrestores bysnapshot_idwith the same write-mode and confirmation gates as direct updates.
Treat snapshot files as sensitive because they can contain dashboard definitions, SQL, collection metadata, and permission graph data.
Capability Overview
The server exposes the complete generated operation catalog through metabase_api_request, with curated high-level tools for the workflows agents need most often.
| Area | MCP support |
|---|---|
| API discovery | Native MCP tools/list, resources/list, prompts/list, metabase://api/coverage, metabase://api/operations, and operation search/get tools. |
| Dashboards | Curated create/get/update/archive/delete/copy, parameters, public links, item/layout management, snapshots, and saved snapshot restore. |
| Cards/questions | Curated create/get/update/archive/delete/copy, query, export, public links, series lookup, and idempotent create-or-update. |
| Collections | Curated tree, create, create-or-update, update, archive, and snapshot/restore. |
| Metadata/querying | Curated database/table metadata reads and governed dataset/card query execution. |
| Snippets | Curated list/get/create/update/create-or-update native SQL snippets. |
| Admin/security | Curated permissions graph, permission groups, users, settings, API keys, and database sync/rescan helpers with admin gates. |
| Notifications | Curated pulse list/get/create/update/delete subscription helpers. |
| Content management | Curated bookmarks, revisions, timelines, timeline events, segments, documents, and cache operations. |
| Remaining Metabase API | Available through metabase_api_request with registry discovery, schema validation, safety classification, dry-run support, and audit logging for mutations. |
Connecting Agents
Read docs/CONNECTING_AGENTS.md or use the optional Codex skill at .codex/skills/connect-metabase-agents/SKILL.md.
Example stdio client config:
{
"mcpServers": {
"metabase": {
"command": "mcp-for-metabase",
"args": ["serve", "--transport", "stdio"],
"env": {
"METABASE_URL": "https://metabase.example.com",
"METABASE_API_KEY": "mb_your_key",
"METABASE_MCP_WRITE_MODE": "read-only"
}
}
}
}
Agents should start with native MCP discovery:
- Call
tools/list. - Call
resources/list. - Call
resourceTemplates/list. - Call
prompts/list. - Read
metabase://agent/connection-guide. - Read
metabase://api/coverageor callmetabase_discover_operations.
Local Development
Recommended:
uv sync --all-extras
uv run ruff format --check .
uv run ruff check .
uv run mypy src
uv run pytest
Run the disposable live integration path:
docker compose up -d postgres metabase
uv run python scripts/bootstrap_metabase_test_instance.py --output-env .metabase-test.env
set -a && . ./.metabase-test.env && set +a
uv run pytest tests/integration -q --no-cov
docker compose down -v
Fallback without uv:
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e ".[dev]"
ruff format --check .
ruff check .
mypy src
pytest
Build and inspect distributions:
python -m build
twine check dist/*
API Registry
Refresh the registry from the official public docs:
python scripts/fetch_openapi.py --output docs/openapi.json
python scripts/build_api_registry.py --openapi docs/openapi.json
Refresh from a live instance:
python scripts/fetch_openapi.py \
--base-url "$METABASE_URL" \
--api-key "$METABASE_API_KEY" \
--output docs/openapi.json
python scripts/build_api_registry.py --openapi docs/openapi.json
Compare two generated registry snapshots before upgrading Metabase docs:
python scripts/diff_api_registry.py \
--old src/mcp_for_metabase/api_registry.json \
--new /tmp/new_api_registry.json \
--format markdown \
--fail-on-removal
Generated outputs:
src/mcp_for_metabase/api_registry.jsonsrc/mcp_for_metabase/openapi.jsondocs/API_COVERAGE.md
docs/openapi.json is intentionally ignored because it is a temporary fetch target. The runtime package includes the normalized OpenAPI snapshot under src/mcp_for_metabase/openapi.json.
Documentation
- Requirements
- Definition of Done
- Architecture
- Security
- Tool catalog
- Capabilities
- API coverage
- Implementation status
- Agent development guide
- Connecting agents
- Compatibility
- Dependency licenses
- Release checklist
Contributing
Contributions are welcome. Read CONTRIBUTING.md, keep changes small, and preserve the safety gates around Metabase mutations.
The .codex/skills directory is intentionally included as optional agent workflow guidance for contributors who use Codex or compatible agent tooling.
License
mcp-for-metabase is licensed under GPL-3.0-or-later. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_for_metabase-0.1.0.tar.gz.
File metadata
- Download URL: mcp_for_metabase-0.1.0.tar.gz
- Upload date:
- Size: 308.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ad7d86326990096a7ecf35290d371f6511440790c345330b1f14ea9687b3846
|
|
| MD5 |
5f755c96f623add782a33d00e3f199a3
|
|
| BLAKE2b-256 |
b7fe962b7e4eab82f96e1b56658082a8ee087531d77719ef5c50e4929135a083
|
Provenance
The following attestation bundles were made for mcp_for_metabase-0.1.0.tar.gz:
Publisher:
release.yml on DominikPollok/mcp-for-metabase
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_for_metabase-0.1.0.tar.gz -
Subject digest:
0ad7d86326990096a7ecf35290d371f6511440790c345330b1f14ea9687b3846 - Sigstore transparency entry: 1610706999
- Sigstore integration time:
-
Permalink:
DominikPollok/mcp-for-metabase@fbff9ba16fbe8d8dff388da775d688794cfc5ed9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/DominikPollok
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@fbff9ba16fbe8d8dff388da775d688794cfc5ed9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_for_metabase-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_for_metabase-0.1.0-py3-none-any.whl
- Upload date:
- Size: 206.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
702cd5aa70b965fcdd8e110b5d9bd4787dc105108ab09d698901b041be19a5be
|
|
| MD5 |
f1ad5158d8ae32ea365677fe56cae9b9
|
|
| BLAKE2b-256 |
cd2ed95c1c65c56bfecf3f6cfd9661973797d740baedc6f916893aad0768d73a
|
Provenance
The following attestation bundles were made for mcp_for_metabase-0.1.0-py3-none-any.whl:
Publisher:
release.yml on DominikPollok/mcp-for-metabase
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_for_metabase-0.1.0-py3-none-any.whl -
Subject digest:
702cd5aa70b965fcdd8e110b5d9bd4787dc105108ab09d698901b041be19a5be - Sigstore transparency entry: 1610707081
- Sigstore integration time:
-
Permalink:
DominikPollok/mcp-for-metabase@fbff9ba16fbe8d8dff388da775d688794cfc5ed9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/DominikPollok
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@fbff9ba16fbe8d8dff388da775d688794cfc5ed9 -
Trigger Event:
push
-
Statement type: