Files
ombi-mcp/docs/megaplans/m1/05-output-schema-modularisation.md
gronod 722108ebd0 Initial commit: Ombi MCP server design docs and Go skeleton
Schema docs (docs/schema) cover tool mapping, input/output contracts and
endpoint coverage for all 31 MCP tools; megaplan M1 phases 01-03 applied
(namespace rename to read_*/write_*, input schema rectification).
Go module provides config loading, Ombi client, and tool registry
skeleton for implementation.
2026-09-18 15:55:44 +01:00

7.3 KiB
Raw Permalink Blame History

Phase 05 — Output Schema Modularisation

Objective

Dismantle the monolithic 1,200-line union in 04-results.md. Publish per-tool outputSchema on each Tool object (MCP 2025-11-25), each referencing a centralised $defs library.

Prerequisites

  • Phase 01 complete (operation enum values already carry the new tool names; this phase replaces the enum with per-tool const).
  • Phase 04 complete (string-label enums used by the replacement issue/retry defs).
  • Locked decision D4: each of the 31 tools declares a distinct outputSchema composed from a centralised $defs library of the 15 result families; output schemas are never embedded in description strings.
  • Source document to rewrite: docs/schema/04-results.md.

Specification

Structure of the rewritten 04-results.md

  1. Keep prose sections Registration and results, Domain projections, Errors and partial effects, Resources (update wording: per-tool outputSchema, not "the common outputSchema"; operation enum → new names).
  2. § Shared $defs library — one JSON block containing every definition (target, identifier, reference, credit, provider, episode, season, media, request, issue, comment, group, vote, user, calendar, artwork, retry, paging, media_page, request_page, issue_page, comment_page, group_page, vote_page, user_page, calendar_page, artwork_page, retry_page, reference_page, metric, metrics, change, settings, mutation, log_file, logs, error). All carried verbatim except the two replacements below.
  3. § Envelope template — printed in full below.
  4. § Tool→family matrix + composition rule — printed in full below.
  5. Remove the giant allOf if/then cascade and the global operation enum (replaced by per-tool const).

Envelope template (per-tool outputSchema, printed in full)

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ok": { "type": "boolean" },
    "operation": { "const": "<tool_name>" },
    "data": { "oneOf": [ "<$ref to each allowed family>" ] },
    "error": { "$ref": "#/$defs/error" },
    "warnings": {
      "type": "array",
      "items": { "type": "string" },
      "maxItems": 100
    },
    "truncated": { "type": "boolean" },
    "correlation_id": { "type": "string" }
  },
  "required": ["ok", "operation", "warnings", "truncated", "correlation_id"],
  "additionalProperties": false,
  "allOf": [
    {
      "if": { "properties": { "ok": { "const": true } } },
      "then": { "required": ["data"], "not": { "required": ["error"] } },
      "else": { "required": ["error"] }
    }
  ],
  "$defs": { "<transitive closure of the shared library for this tool>" }
}

Composition rule (deterministic)

For each tool: set operation.const to the tool name; set data.oneOf to its allowed families per the matrix; compute $defs = {error} ∪ the allowed families ∪ every def reachable by following $refs inside them (e.g. media_page → media → identifier, target, credit, provider, reference, season, episode; request_page → request → target, identifier, season, episode, paging). Registration text must state: "tools/list advertises outputSchema on each Tool object per MCP 2025-11-25; output contracts never appear inside description."

Tool→family matrix (identical allowances as before, new names)

Tool Allowed data families
read_search media_page
read_discover media_page
read_media media_page
read_reference reference_page
read_requests request_page, retry_page
read_request_stats metrics
read_issues issue_page, comment_page, group_page, metrics
read_votes vote_page
read_users user_page, reference_page
read_library media_page, calendar_page, artwork_page
read_server metrics, reference_page
read_integration reference_page, user_page
read_settings settings
read_logs logs
write_request_create … all 17 write_* mutation

Replacement defs (printed in full — enum abstraction per Phase 04)

issue (labels + code twins):

"issue": {
  "type": "object",
  "properties": {
    "id": { "type": "integer", "minimum": 1 },
    "title": { "type": "string" },
    "subject": { "type": "string" },
    "description": { "type": "string" },
    "category_id": { "type": "integer", "minimum": 1 },
    "status": {
      "type": "string",
      "enum": ["pending", "in_progress", "resolved", "closed"]
    },
    "status_code": { "type": "integer", "enum": [0, 1, 2, 3] },
    "request_type": {
      "type": "string",
      "enum": ["movie", "tv", "album"]
    },
    "request_type_code": { "type": "integer", "enum": [0, 1, 2] },
    "request_id": { "type": "integer", "minimum": 1 },
    "provider_id": { "type": "string" },
    "created_date": { "type": "string" },
    "resolved_date": { "type": "string" },
    "reported_by_user_id": { "type": "string" }
  },
  "required": ["id"],
  "additionalProperties": false
}

retry (label + code twin):

"retry": {
  "type": "object",
  "properties": {
    "queue_id": { "type": "integer", "minimum": 1 },
    "request_id": { "type": "integer", "minimum": 1 },
    "request_type": {
      "type": "string",
      "enum": ["movie", "tv", "album"]
    },
    "request_type_code": { "type": "integer", "enum": [0, 1, 2] },
    "title": { "type": "string" },
    "reason": { "type": "string" }
  },
  "required": ["queue_id"],
  "additionalProperties": false
}

vote stays numeric (vote_code enum:[0,1]) — VoteType labels remain Verify. settings def gains optional leaf naming note (no schema change needed — change.value already allows string|number; agent/notification_type leaves emit label strings when mapped, raw ints + warning when unmapped).

All other defs carry over byte-identical from the current 04-results.md (media, request, comment, group, user, calendar, artwork, paging, all *_page shells, metric, metrics, change, settings, mutation, log_file, logs, error).

Target artefacts

  • docs/schema/04-results.md — restructured per the five steps above: prose updated, shared $defs library block (with issue/retry replaced), envelope template, tool→family matrix, monolithic union removed. Per-tool outputSchema composition documented; operation becomes const.

Verification gates

  • operation is a const per tool; no global oneOf-of-15-families union remains at envelope level.
  • Every tool's data.oneOf matches the matrix exactly.
  • $defs in each tool schema is exactly the transitive closure (no unused defs — context budget).
  • issue/retry emit status/request_type label enums plus *_code twins.
  • Docs state outputSchema is a Tool field; nothing about embedding contracts in description.

Evidence labels

  • Documented — outputSchema on the Tool object per MCP 2025-11-25 (D4); result-family allowances carried over from the existing spec.
  • Design — per-tool outputSchema composition, transitive-closure $defs rule, operation as const, issue/retry label+code twins per Phase 04.
  • Verify — vote stays numeric pending VoteType label verification; unmapped upstream ints emit *_code + warning per the Phase 04 fallback contract.