ombi-mcp
A Model Context Protocol (MCP) server that exposes Ombi — the self-hosted media request manager — to MCP clients such as AI assistants.
ombi-mcp is a distributable, statically linked Go binary that speaks MCP over stdio. It works against any self-hosted Ombi instance: point it at your instance with OMBI_URL and authenticate with either a JWT login or an API key. Nothing is instance-specific or hardcoded.
Status: under active development. The tool catalogue, schemas and auth layer are implemented; see Project status for details.
Features
- 31 tools covering search, discovery, requests, issues, votes, users, library, server status and administration — every one mapped from the documented Ombi API.
- Bundle-based deployment policy: expose only ordinary media workflows (
core), or opt in tomoderationandadministrationtool groups per deployment. - Effect-encoding tool names:
read_*tools are read-only,write_*tools mutate state. MCP tool annotations (readOnlyHint,destructiveHint,idempotentHint,openWorldHint) are declared per tool. - Strict, embedded schemas: every tool advertises a complete JSON Schema 2020-12 input schema and a structured output envelope, generated from the design docs in
docs/schemaand embedded at build time. - Two upstream auth modes with automatic JWT lifecycle management (login, caching, single-flight renewal, retry-on-401).
- Predictable results: every tool returns the same bounded envelope with
ok,data/error,warnings,truncatedand acorrelation_id— never raw upstream dumps.
Requirements
- Go 1.27+ (to build)
- A reachable Ombi instance and credentials (API key, or username/password for JWT mode)
Building
CGO_ENABLED=0 go build -o ombi-mcp ./cmd/ombi-mcp
The server ships as a statically linked binary with no CGO dependencies.
Gitea Actions builds macOS, Windows, and Linux binaries and publishes a
multi-platform Docker image to git.i3omb.com/gronod/ombi-mcp. See
CI/CD setup and container usage for runner labels, registry secrets,
artifact downloads, and publishing triggers.
Configuration
All configuration is via environment variables:
| Variable | Required | Description |
|---|---|---|
OMBI_URL |
yes | Base URL of the Ombi instance. Must be a scheme + host with no credentials, query string or fragment. A reverse-proxy path prefix is preserved. |
OMBI_AUTH_MODE |
yes | Upstream credential mechanism: jwt (primary) or api_key. |
OMBI_USERNAME |
jwt mode | Ombi login username. |
OMBI_PASSWORD |
jwt mode | Ombi login password. |
OMBI_API_KEY |
api_key mode | Ombi API key, sent as the ApiKey header. |
OMBI_USER_NAME |
no | Optional Ombi username sent as the UserName header in api_key mode, to bind requests to a specific Ombi user. |
OMBI_BUNDLES |
no | Comma-separated tool bundles to enable: core, moderation, administration. Defaults to core. |
MCP_TRANSPORT |
no | |
MCP_PORT |
no |
Credentials are read from the environment only — keep them in a local .env or your MCP client's per-server env block, and never commit them.
Auth modes
jwt(primary): logs in once viaPOST /api/v1/TokenwithOMBI_USERNAME/OMBI_PASSWORD, caches the bearer token, renews it proactively before expiry (expiry is taken from the response, the JWTexpclaim, or a conservative fallback), and transparently retries once after a401.api_key(secondary): sends theApiKeyheader on every request; optionally impersonates/binds a user withUserName.
Running with an MCP client
ombi-mcp communicates over stdio, so it is launched as a subprocess by the MCP client. Example client configuration:
{
"mcpServers": {
"ombi": {
"command": "/usr/local/bin/ombi-mcp",
"env": {
"OMBI_URL": "https://ombi.example.com",
"OMBI_AUTH_MODE": "api_key",
"OMBI_API_KEY": "your-api-key"
}
}
}
}
To expose moderation and administration tools as well:
"env": {
"OMBI_URL": "https://ombi.example.com",
"OMBI_AUTH_MODE": "jwt",
"OMBI_USERNAME": "your-user",
"OMBI_PASSWORD": "your-password",
"OMBI_BUNDLES": "core,moderation,administration"
}
HTTP/SSE transport
Set MCP_TRANSPORT=sse (and optionally MCP_PORT, default 8080) to serve MCP over HTTP with server-sent events instead of stdio. The server exposes GET /sse (session stream) and accepts client JSON-RPC messages via POST to the session endpoint advertised in the endpoint event (/sse?sessionid=..., also reachable at /messages). CORS is permissive so browser-based clients can connect.
MCP_TRANSPORT=sse MCP_PORT=8080 ./ombi-mcp
# client: GET http://localhost:8080/sse → event: endpoint
# POST http://localhost:8080/sse?sessionid=<id> (JSON-RPC body)
Tool catalogue
Tools are grouped into bundles — deployment policy groups, not permission boundaries by themselves. Only tools in enabled bundles are advertised via tools/list, and bundle policy is re-checked at tools/call time.
Core (18 tools) — enabled by default
| Tool | Description |
|---|---|
read_search |
Search media by text, with explicit movie refinements or a multi-search filter. |
read_discover |
Curated lists, similar movies, collections, credits, artist albums, advanced movie filters. |
read_media |
Media details by provider or request; ratings; streaming availability. |
read_reference |
Genres, languages, keywords, watch-provider catalogue, countries, issue categories. |
read_requests |
List/get/search requests, TV children, recent requests, privileged retry queue. |
read_request_stats |
Request counts, totals, per-media quota, user-has-requests. |
read_issues |
Issues, grouped summaries, comments and counts. |
read_votes |
Global vote list or votes on a request. |
read_users |
Self, authorized user lookup, claims, online users, preference read. |
read_library |
Recent additions, calendar, artwork. |
read_server |
Server status, version, features, stats, cron validation. |
read_integration |
Saved ARR options and authorized media-server metadata. |
write_request_create |
Create one media request or an explicit collection request. |
write_request_subscribe |
Subscribe/unsubscribe to a request. |
write_issue_create |
Report an issue. |
write_issue_comment |
Add a comment to an issue. |
write_vote |
Up/down vote on a request. |
write_user_preferences |
Language, streaming country, newsletter opt-out. |
Moderation (5 tools) — opt-in
| Tool | Description |
|---|---|
write_request_moderate |
Approve, deny, mark available. |
write_request_delete |
Delete a single movie/album/TV-parent/TV-child request. |
write_request_options |
Advanced routing overrides and TV root folder/quality. |
write_request_reprocess |
Reprocess an existing request. |
write_issue_manage |
Change issue state, delete issues/comments, manage categories. |
Administration (8 tools) — opt-in
| Tool | Description |
|---|---|
read_settings |
Safe (non-secret) configuration projection and revision. |
write_settings_patch |
Typed, non-secret settings patch or feature flag. |
write_user_manage |
Delete a user or send a welcome email. |
write_integration_test |
Test a saved integration profile (can send notifications). |
write_job_run |
Trigger permitted jobs / watchlist revalidation. |
write_notification_send |
Send email to explicit recipients. |
write_retry_remove |
Remove one retry-queue entry. |
read_logs |
Bounded, sanitized diagnostic log reads. |
Result envelope
Every tool returns the same structured envelope as its structuredContent (plus a serialized text copy for clients that do not consume structured content):
{
"ok": true,
"operation": "read_search",
"data": { "…family-specific result…" },
"warnings": [],
"truncated": false,
"correlation_id": "…"
}
- On success (
ok: true)datais present anderroris absent; on failure the reverse. This is enforced by the tool's JSON Schema output contract. datais always one of a small set of typed families (e.g.media_page,request_page,mutation,metrics) — never an arbitrary upstream payload.truncatedsignals that a bounded result was clipped;warningscarries non-fatal notes;correlation_idties a result back to a specific call for diagnostics.- Errors carry a stable
code(e.g.INVALID_ARGUMENT,INTERNAL_ERROR), a human-readable message, aretryableflag and, where applicable, the upstreamhttp_statusandretry_after_seconds.
Enum-like upstream values (request types, issue statuses, notification agents/types) are translated to stable agent-facing labels (movie/tv/album, pending/in_progress/resolved/closed, …) in both directions by the internal/translate layer.
Architecture
cmd/ombi-mcp/ entrypoint: config → auth → client → MCP server over stdio
internal/config/ environment/config loading and validation
internal/ombi/ Ombi API client, auth manager, wire types
internal/mcpserver/ MCP protocol wiring (tools/list, tools/call dispatch)
internal/tools/ tool registry, argument handling, result envelope,
embedded JSON schemas (generated)
internal/translate/ bidirectional enum label ↔ wire-constant translation
docs/schema/ design and audit docs; source of the tool contracts
tools/schemagen/ generator that extracts embedded schemas from docs
Design principles:
- Single client module — all Ombi API access goes through
internal/ombi; tools never make their own HTTP calls. - Static, audited catalogue — the 31-tool registry is fixed; input schemas are generated from the docs via
go generateand embedded, and output schemas are composed per tool from a shared$defslibrary. - Bounded results — list-shaped data is page-bounded and flagged with
truncatedrather than streamed unbounded. - No instance-specific defaults — every URL and credential comes from the environment.
Development
Requires Go 1.27+.
go mod tidy # install dependencies
CGO_ENABLED=0 go build ./... # build all packages
CGO_ENABLED=0 go build -o ombi-mcp ./cmd/ombi-mcp
go run ./cmd/ombi-mcp # run dev server (stdio)
go test ./... # run tests
go vet ./... && gofmt -l . # lint / formatting check
go generate ./internal/tools # regenerate embedded schemas
For integration testing against a real instance, put OMBI_URL, OMBI_AUTH_MODE and credentials in a local .env — never commit secrets, .env files or generated artifacts.
Project status
- Done: schema design and endpoint-coverage audit (all 377 RAML operations accounted for in
docs/schema/), the 31-tool catalogue with input/output JSON Schemas, JWT and API-key auth with token lifecycle management, the MCP stdio server with bundle filtering and tool annotations, and the enum translation layer. - In progress: completing and verifying tool handlers against a live Ombi instance; see
docs/schema/06-verification.mdfor tracked runtime assumptions and acceptance criteria.
Links
- Ombi: https://ombi.io/
- Model Context Protocol: https://modelcontextprotocol.io/
- Design docs:
docs/schema/README.md