A Model Context Protocol server that exposes Metaplane's REST API as 18 LLM-callable tools, organized around monitors, connections, and tags.
- Pure Python (3.12+),
uv-managed. - stdio and streamable HTTP transports in one binary.
- Structured JSON logs on stderr (stdout is reserved for MCP frames).
- Correlation IDs propagated to Metaplane via
X-Request-ID. - Retries with exponential backoff + jitter, honoring
Retry-After. - Pydantic v2 schemas for every tool input and a shared
ToolResponseenvelope{summary, data, resource_links}.
- 11 monitor tools — create, read, update, run, list by connection/entity, ingest and backfill datapoints, bulk-fetch across tables, graceful "not yet run" handling on status.
- 3 connection tools — list connections, inspect sync status, trigger sync.
- 4 tag tools — batch-apply / batch-remove table tags, list monitors by tag, fetch tag definitions.
- Resource handler — dereferences
metaplane://monitor/{id}URIs returned in tool responses. - Stubbed auth provider — a
Protocolplaceholder for OAuth 2.1 + PKCE (roadmap). - No runtime dependencies on Metaplane's web UI — we do not embed
(potentially wrong) web URLs. Only first-party REST endpoints and our own
metaplane://resource scheme are used.
uvx metaplane-mcp-servergit clone https://github.com/paschmaria/metaplane-mcp-server
cd metaplane-mcp-server
uv sync
uv run python -m metaplane_mcpAll settings come from environment variables (prefixed METAPLANE_) or CLI flags.
| Env var | CLI flag | Default | Purpose |
|---|---|---|---|
METAPLANE_API_KEY |
— | required for stdio | Static API key used by the server. |
METAPLANE_BASE_URL |
--base-url |
https://dev.api.metaplane.dev |
Metaplane REST base URL. |
METAPLANE_TRANSPORT |
--transport |
stdio |
stdio or http. |
METAPLANE_HTTP_HOST |
--host |
127.0.0.1 |
HTTP bind host. |
METAPLANE_HTTP_PORT |
--port |
8080 |
HTTP bind port. |
METAPLANE_REQUEST_TIMEOUT_SECONDS |
— | 30 |
Per-request timeout (seconds). |
METAPLANE_MAX_RETRIES |
— | 3 |
Max attempts on 429/5xx. |
METAPLANE_AUTH_HEADER |
— | Authorization |
Header name used to send the API key. |
METAPLANE_AUTH_SCHEME |
— | Bearer |
Scheme prefix when using Authorization. |
METAPLANE_ENABLE_TELEMETRY |
— | false |
Reserved (Sentry/OTel hook, currently no-op). |
Metaplane's public REST reference hides the exact authentication header behind
a login wall. This server defaults to Authorization: Bearer <key> because
that is the most common convention for modern REST APIs. If your Metaplane
deployment requires X-API-Key (or similar) instead, set:
export METAPLANE_AUTH_HEADER=X-API-Key
# leave METAPLANE_AUTH_SCHEME alone (only used for Authorization)For the HTTP transport, per-request Authorization headers are forwarded
to Metaplane verbatim, so callers can bring their own token.
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"metaplane": {
"command": "uvx",
"args": ["metaplane-mcp-server"],
"env": { "METAPLANE_API_KEY": "<your-key>" }
}
}
}claude mcp add metaplane uvx metaplane-mcp-server --env METAPLANE_API_KEY=<your-key>uvx metaplane-mcp-server --transport http --host 0.0.0.0 --port 8080
# -> serves MCP at http://0.0.0.0:8080/mcpPoint any streamable-HTTP MCP client at that URL. Forward Authorization per
request — the server uses the caller's token (not METAPLANE_API_KEY).
| # | Tool | Endpoint | Description |
|---|---|---|---|
| 1 | create_monitor |
POST /v1/monitors |
Create a monitor (forwards extra fields verbatim). |
| 2 | get_monitor |
GET /v1/monitors/{id} |
Fetch a monitor by ID. |
| 3 | update_monitor |
POST /v1/monitors/{id} |
Update a monitor (Metaplane uses POST). |
| 4 | get_evaluation_history |
GET /v1/monitors/{id}/evaluation-history (unverified) |
Historic evaluation runs. Path sourced from Metaplane blog. |
| 5 | run_monitor |
POST /v1/monitors/run |
Trigger an ad-hoc evaluation. |
| 6 | list_monitors_for_connection |
GET /v1/monitors/connection/{id} |
Monitors attached to a connection. |
| 7 | ingest_datapoint |
POST /v1/monitors/ingest-datapoint/{id} |
Ingest a single observation. |
| 8 | import_historic_data |
POST /v1/monitors/import-historic/{id} |
Backfill historical observations. |
| 9 | get_monitors_for_entity |
GET /v1/monitors/path/{conn}/{absolutePath} |
Monitors on a DB/schema/table/column. |
| 10 | get_monitor_status |
GET /v2/monitors/status/{id} (404 → status=not_run) |
Current monitor status with graceful "not run yet" handling. |
| 11 | bulk_get_monitors_on_tables |
POST /v2/monitors/bulk-fetch/tables/{conn} |
Monitors for many tables in one call. |
| 12 | list_connections |
GET /v1/connections |
All connections visible to the API key. |
| 13 | get_connection_sync_status |
GET /v1/connections/{id}/sync/status |
Current connection sync state. |
| 14 | trigger_connection_sync |
POST /v1/connections/{id}/sync |
Kick off a sync run. |
| 15 | tag_tables |
POST /v1/tags/batch/tag-tables |
Apply tags to a batch of tables. |
| 16 | remove_table_tags |
POST /v1/tags/batch/remove-table-tags |
Remove tags from a batch of tables. |
| 17 | list_monitors_for_tag |
GET /v1/tags/tagged-monitors/{tag} |
Monitors carrying a given tag. |
| 18 | list_tag_definitions |
POST /v1/tags/batch/tag-definitions |
Tag metadata (colors, descriptions). |
Every tool returns:
{
"summary": "One-line human summary for the agent.",
"data": {...}, # shaped Metaplane payload
"resource_links": ["metaplane://monitor/mon_xxx", ...]
}metaplane://monitor/{id} resolves to the full Metaplane monitor record as
JSON via GET /v1/monitors/{id}.
# Install (including dev deps)
uv sync --all-groups
# Lint & format (run before committing)
uv run ruff check
uv run ruff format --check
# Tests (asyncio + respx, no live API)
uv run pytest -q
# Run the server
METAPLANE_API_KEY=dev-key uv run python -m metaplane_mcpMETAPLANE_API_KEY=dev-key \
npx @modelcontextprotocol/inspector --cli \
-e METAPLANE_API_KEY=dev-key \
uv run python -m metaplane_mcp \
--method tools/listPRs welcome. Please:
- Keep the Pydantic input schemas tight — if you add a field, give it a
descriptionand a sensible default. - Cover new tools with at least a happy-path
respxtest intests/tools/. uv run ruff check && uv run ruff format --check && uv run pytest -qmust pass.
- Confirm the exact auth-header name /
evaluation_historypath against Metaplane's post-login docs and drop the "unverified" caveats. - Implement OAuth 2.1 + PKCE via the stubbed
AuthProviderProtocol. - Wire up
init_telemetry()for Sentry / OpenTelemetry span export. - Publish to PyPI under
metaplane-mcp-server. - Register in the community MCP server index.
- Add web-UI deep-links to tool responses once the URL pattern is confirmed.
MIT — see LICENSE.