Skip to content

feat(keep-mcp): v0.1 read-only MCP server (sidecar container) - #6619

Open
harisrujanc wants to merge 6 commits into
keephq:mainfrom
harisrujanc:keep-mcp-skeleton
Open

feat(keep-mcp): v0.1 read-only MCP server (sidecar container)#6619
harisrujanc wants to merge 6 commits into
keephq:mainfrom
harisrujanc:keep-mcp-skeleton

Conversation

@harisrujanc

@harisrujanc harisrujanc commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Closes #6618.

Adds keep-mcp — a Model Context Protocol server for Keep, shipped as a sidecar container next to keep-backend / keep-frontend, the same pattern as keep-websocket-server. It is a thin adapter over the Keep REST API with no direct DB or secret-manager access, so RBAC and tenancy stay in keep-backend. keep-backend is not modified.

This lets an LLM client answer questions like "what's firing right now, and which incident does it belong to?" by chaining tool calls, instead of a human clicking through the UI.

v0.1 surface (read-only)

Toolssearch_alerts · list_incidents · get_incident · list_incident_alerts · get_topology

Transportsstdio for local desktop clients, streamable-http for remote deployments.

The service sits behind the mcp compose profile, so the default docker compose up is unchanged:

KEEP_MCP_KEEP_API_KEY=<your-key> docker compose --profile mcp up keep-mcp

Security

The streamable-http endpoint is unauthenticated in v0.1 and holds a Keep API key, so anything that can reach the port gets read access to alerts, incidents and topology. It is meant for the compose network or a trusted local host. Endpoint auth lands in v0.2 with OAuth 2.1. Flagging it explicitly rather than leaving it to be discovered.

Model-supplied limit/offset are clamped, since the Keep API does not bound limit itself.

Deferred to follow-up PRs

  • v0.2: POST /providers/{id}/invoke/{method} in keep-backend + LGTM passthrough tools (Loki / Mimir / Tempo / Grafana), a triage_alert prompt, OAuth 2.1, and a /readyz endpoint alongside the Helm sub-chart
  • v0.3: mutating tools (enrich_alert, create_incident, run_workflow) with idempotency, dry-run and audit, gated behind a feature flag

Open question

docker-compose.yml normally references published images while docker-compose.dev.yml builds locally. Since no keep-mcp image is published yet, this PR uses build: so the compose command above works out of the box — happy to switch it to an image reference if you'd rather add it to the release pipeline first.

Demo video to follow, per @shahargl's request on #6618.

harisrujanc and others added 3 commits July 5, 2026 14:58
Introduces keep-mcp/ — a standalone Python package that exposes Keep's
alerts, incidents, and topology to LLM agents via the Model Context
Protocol. Ships as an independent container alongside keep-backend and
keep-frontend, matching the existing keep-websocket-server sidecar
pattern.

Tools (v0.1, read-only):
- search_alerts(cel, limit, offset)
- list_incidents(status, severity, limit, offset, cel)
- get_incident_with_alerts(incident_id, alerts_limit)
- get_topology(service)

Resources:
- keep://alerts
- keep://incidents
- keep://topology

Transports: stdio (local desktop clients) and streamable-http (remote).
Auth: X-API-KEY forwarded from KEEP_MCP_KEEP_API_KEY; no direct DB or
secret-manager access — RBAC and tenancy stay in keep-backend.

Ops: /healthz + /readyz, Docker HEALTHCHECK, Alpine python:3.13.5 base
matching Dockerfile.api, non-root user (UID 1000).

Wired into docker-compose behind the 'mcp' profile so it stays out of
the default 'docker compose up'.
- delete KeepAPIError + _extract_detail; rely on httpx.raise_for_status
- delete get_alerts_by_fingerprints (no v0.1 caller)
- delete client.ping(); inline into /readyz
- delete INCIDENT_STATUSES/SEVERITIES/_validate_subset (backend already 422s)
- delete keep://alerts/incidents/topology resources (tools cover it)
- split get_incident_with_alerts into get_incident + list_incident_alerts
- inline build_server() into main() — one caller, no fake factory
- drop starlette (transitive via mcp) and ruff (unwired) deps
- delete empty tests/__init__.py
- update tests to expect httpx.HTTPStatusError

All 5 tests pass; MCP handshake + tools/list verified end-to-end.
@CLAassistant

CLAassistant commented Jul 6, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Ultra pass: this is a proxy to 5 REST endpoints. It doesn't need a
client class, a config module, a factory, or three ceilings on limit.

- delete client.py, config.py, .gitignore
- fold everything into __main__.py: 5 tools call httpx directly
- drop pydantic and pydantic-settings deps (os.environ.get is fine)
- delete /readyz (add back with the Helm chart)
- delete client-side limit clamps and status default (backend handles)
- shrink README to 20 lines

3/3 tests pass; streamable-http boots; MCP handshake works.
- add a dedicated unit-test workflow; keep-mcp/** matched no existing
  paths filter, so the tests never ran
- clamp model-supplied limit/offset in one place; the Keep API does not
  bound limit itself
- add docstrings to get_incident, list_incident_alerts and get_topology,
  which MCP sends to the model as the tool description
- drop dead KEEP_MCP_LOG_LEVEL and duplicated transport env vars
- drop the nested [tool.ruff] block that conflicted with repo-wide black
- drop the unpublished image reference so compose builds locally, matching
  the docker-compose.dev.yml convention
- document that the streamable-http endpoint is unauthenticated in v0.1
- parameterize tests across all five tools, add API-key and clamp cases
The action auto-detects its ruff version from the checkout and picked up
0.16.2 for keep-mcp, which then conflicted with the repo's 0.11.4 pin.
@harisrujanc
harisrujanc marked this pull request as ready for review August 8, 2026 16:49
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. Feature A new feature labels Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature A new feature size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[➕ Feature]: Official MCP (Model Context Protocol) server for Keep

2 participants