Files
gronod 6926a91c80
Build and publish / Test and build (darwin) (pull_request) Successful in 1m52s
Build and publish / Test and build (linux) (pull_request) Successful in 2m30s
Build and publish / Test and build (windows) (pull_request) Successful in 3m7s
Build and publish / Test and build (windows) (push) Successful in 3m7s
Build and publish / Test and build (darwin) (push) Successful in 1m45s
Build and publish / Test and build (linux) (push) Successful in 2m12s
Build and publish / Build and publish Docker image (pull_request) Successful in 1m49s
Build and publish / Build and publish Docker image (push) Successful in 2m4s
Fix M7 admin/server wire contracts
2026-09-19 18:36:03 +01:00

12 KiB

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 to moderation and administration tool 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/schema and 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, truncated and a correlation_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 via POST /api/v1/Token with OMBI_USERNAME/OMBI_PASSWORD, caches the bearer token, renews it proactively before expiry (expiry is taken from the response, the JWT exp claim, or a conservative fallback), and transparently retries once after a 401.
  • api_key (secondary): sends the ApiKey header on every request; optionally impersonates/binds a user with UserName.

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) data is present and error is absent; on failure the reverse. This is enforced by the tool's JSON Schema output contract.
  • data is always one of a small set of typed families (e.g. media_page, request_page, mutation, metrics) — never an arbitrary upstream payload.
  • truncated signals that a bounded result was clipped; warnings carries non-fatal notes; correlation_id ties a result back to a specific call for diagnostics.
  • Errors carry a stable code (e.g. INVALID_ARGUMENT, INTERNAL_ERROR), a human-readable message, a retryable flag and, where applicable, the upstream http_status and retry_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 generate and embedded, and output schemas are composed per tool from a shared $defs library.
  • Bounded results — list-shaped data is page-bounded and flagged with truncated rather 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.md for tracked runtime assumptions and acceptance criteria.