feat(keep-mcp): v0.1 read-only MCP server (sidecar container) - #6619
Open
harisrujanc wants to merge 6 commits into
Open
feat(keep-mcp): v0.1 read-only MCP server (sidecar container)#6619harisrujanc wants to merge 6 commits into
harisrujanc wants to merge 6 commits into
Conversation
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.
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.
harisrujanc
force-pushed
the
keep-mcp-skeleton
branch
from
July 7, 2026 19:11
55b9a38 to
3d658f5
Compare
- 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
marked this pull request as ready for review
August 8, 2026 16:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #6618.
Adds
keep-mcp— a Model Context Protocol server for Keep, shipped as a sidecar container next tokeep-backend/keep-frontend, the same pattern askeep-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 inkeep-backend.keep-backendis 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)
Tools —
search_alerts·list_incidents·get_incident·list_incident_alerts·get_topologyTransports —
stdiofor local desktop clients,streamable-httpfor remote deployments.The service sits behind the
mcpcompose profile, so the defaultdocker compose upis unchanged:Security
The
streamable-httpendpoint 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/offsetare clamped, since the Keep API does not boundlimititself.Deferred to follow-up PRs
POST /providers/{id}/invoke/{method}inkeep-backend+ LGTM passthrough tools (Loki / Mimir / Tempo / Grafana), atriage_alertprompt, OAuth 2.1, and a/readyzendpoint alongside the Helm sub-chartenrich_alert,create_incident,run_workflow) with idempotency, dry-run and audit, gated behind a feature flagOpen question
docker-compose.ymlnormally references published images whiledocker-compose.dev.ymlbuilds locally. Since nokeep-mcpimage is published yet, this PR usesbuild: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.