mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-11 02:13:48 +00:00
refactor(mcp): consolidate documentation into mcp.schema.ts
Single file to update when the data model changes: - EVENT_TIMER_FIELDS and EVENT_WRITABLE_FIELDS (tool JSON schemas) moved from mcp.tools.ts - ONTIME_SCHEMA_MARKDOWN and ONTIME_DOCS_MARKDOWN moved from mcp.resources.ts - mcp.tools.ts and mcp.resources.ts now import from mcp.schema.ts - Removed inline data model notes from the agenda prompt; replaced with a reference to the ontime://schema resource - Fixed inaccurate enum values in schema (Milestone type added, TimerType/EndAction corrected to match ontime-types) https://claude.ai/code/session_01U24MeuUacYXeQhbX3tatEe
This commit is contained in:
@@ -46,12 +46,7 @@ export function handleGetPrompt(name: string, args: Record<string, string>): Get
|
||||
content: {
|
||||
type: 'text',
|
||||
text: `Convert the following agenda into an Ontime rundown.
|
||||
|
||||
Data model:
|
||||
- Times are milliseconds from midnight. 09:00 = 32400000, 10:30 = 37800000, etc.
|
||||
- duration = timeEnd - timeStart
|
||||
- endAction: "load-next" for back-to-back sessions, "none" otherwise
|
||||
- Ask the user what cue naming and colour conventions they prefer
|
||||
Read the ontime://schema resource if you need a data model reference.
|
||||
|
||||
Steps:
|
||||
1. Call ontime_get_rundown to see current state and identify an \`after\` anchor if appending.
|
||||
|
||||
@@ -4,118 +4,7 @@ import { normalisedToRundownArray } from '../api-data/rundown/rundown.utils.js';
|
||||
import { getDataProvider } from '../classes/data-provider/DataProvider.js';
|
||||
import type { ListResourcesResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
// Static Ontime data model reference — agents read this once per session to understand
|
||||
// the rundown structure, time format, and entry types before issuing tool calls.
|
||||
const ONTIME_SCHEMA_MARKDOWN = `# Ontime data model
|
||||
|
||||
A concise reference for how Ontime structures rundowns, events, and related data.
|
||||
|
||||
## Rundown
|
||||
|
||||
A rundown is an ordered list of entries rendered as a show schedule. A project can contain multiple rundowns; one is "loaded" at a time.
|
||||
|
||||
\`\`\`
|
||||
Rundown {
|
||||
id: string
|
||||
title: string
|
||||
order: EntryId[] // top-level entry order
|
||||
flatOrder: EntryId[] // includes entries nested in groups
|
||||
entries: { [id: EntryId]: OntimeEntry }
|
||||
revision: number
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Entries
|
||||
|
||||
There are three entry types discriminated by \`type\`:
|
||||
|
||||
### \`event\` — OntimeEvent (a timed show item)
|
||||
\`\`\`
|
||||
{
|
||||
type: 'event'
|
||||
id: EntryId
|
||||
cue: string // human-facing cue label
|
||||
title: string
|
||||
note: string
|
||||
colour: string // hex, e.g. "#4A90D9"
|
||||
timeStart: number // ms from midnight (09:00 = 32400000)
|
||||
timeEnd: number // ms from midnight
|
||||
duration: number // ms (= timeEnd - timeStart)
|
||||
delay: number // accumulated delay in ms
|
||||
timerType: 'count-down' | 'count-up' | 'time-to-end' | 'clock'
|
||||
endAction: 'none' | 'stop' | 'load-next' | 'play-next'
|
||||
linkStart: boolean // chain start to previous event's end
|
||||
countToEnd: boolean // timer counts to planned end time
|
||||
skip: boolean // event is skipped during playback
|
||||
timeWarning: number // ms before end to trigger 'warning' state
|
||||
timeDanger: number // ms before end to trigger 'danger' state
|
||||
custom: { [key: string]: string } // custom field values
|
||||
triggers: AutomationTrigger[]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### \`delay\` — Delay (schedule shift applied to following events)
|
||||
\`\`\`
|
||||
{ type: 'delay', id, duration: number }
|
||||
\`\`\`
|
||||
|
||||
### \`group\` — Group (nested container of entries)
|
||||
\`\`\`
|
||||
{ type: 'group', id, title, colour, note, entries: EntryId[], targetDuration?: number }
|
||||
\`\`\`
|
||||
|
||||
## Time format
|
||||
All time fields are **milliseconds from midnight (local)**. Examples:
|
||||
- 09:00:00 = 32400000
|
||||
- 09:30:00 = 34200000
|
||||
- 14:15:00 = 51300000
|
||||
- duration of 45 min = 2700000
|
||||
|
||||
## Custom fields
|
||||
Custom fields are project-scoped name/type/colour definitions stored at \`ontime://project/custom-fields\`. Each event stores values at \`event.custom[fieldKey]\`.
|
||||
|
||||
## Playback states (runtime only)
|
||||
\`'stop' | 'play' | 'pause' | 'armed' | 'roll'\`. When playback is not \`stop\`, mutating tools warn that changes are visible immediately.
|
||||
|
||||
## Useful resource URIs
|
||||
- \`ontime://schema\` — this document
|
||||
- \`ontime://rundown/current\` — the currently loaded rundown (JSON)
|
||||
- \`ontime://rundowns\` — all rundowns in the project (JSON)
|
||||
- \`ontime://project/info\` — project metadata (JSON)
|
||||
- \`ontime://project/custom-fields\` — custom field definitions (JSON)
|
||||
- \`ontime://docs\` — index of Ontime documentation topics with URLs
|
||||
|
||||
## Further reading
|
||||
Full Ontime documentation: **https://docs.getontime.no**
|
||||
Read \`ontime://docs\` for a topic index with direct links.
|
||||
`;
|
||||
|
||||
// Curated documentation index — agents read this to find official docs on specific topics.
|
||||
const ONTIME_DOCS_MARKDOWN = `# Ontime Documentation Index
|
||||
|
||||
Main site: https://docs.getontime.no
|
||||
|
||||
## Getting started
|
||||
- Installation & setup: https://docs.getontime.no/installation/
|
||||
|
||||
## Core concepts
|
||||
- Rundown: https://docs.getontime.no/concepts/rundown/
|
||||
- Timer types (count-down, count-up, time-to-end, clock): https://docs.getontime.no/concepts/timer/
|
||||
- Time entry format: https://docs.getontime.no/concepts/time-entry/
|
||||
- Event actions (end action, link start): https://docs.getontime.no/concepts/event-actions/
|
||||
- Delays and blocks: https://docs.getontime.no/concepts/delays-and-blocks/
|
||||
|
||||
## Features
|
||||
- Custom fields: https://docs.getontime.no/features/custom-fields/
|
||||
- Automations (triggers, filters, outputs): https://docs.getontime.no/features/automations/
|
||||
- URL presets / shared views: https://docs.getontime.no/features/url-presets/
|
||||
- HTTP Integration: https://docs.getontime.no/api/http/
|
||||
- OSC Integration: https://docs.getontime.no/api/osc/
|
||||
|
||||
## API reference
|
||||
- REST API overview: https://docs.getontime.no/api/
|
||||
- WebSocket events: https://docs.getontime.no/api/websocket/
|
||||
`;
|
||||
import { ONTIME_DOCS_MARKDOWN, ONTIME_SCHEMA_MARKDOWN } from './mcp.schema.js';
|
||||
|
||||
export const RESOURCE_DEFINITIONS: ListResourcesResult['resources'] = [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Single source of truth for Ontime MCP documentation.
|
||||
*
|
||||
* Tool field schemas (EVENT_TIMER_FIELDS, EVENT_WRITABLE_FIELDS) and the schema resource
|
||||
* (ONTIME_SCHEMA_MARKDOWN) are maintained here so that a single edit keeps tool descriptions,
|
||||
* prompt guidance, and the agent-readable reference document in sync.
|
||||
*
|
||||
* Canonical type definitions live in packages/types/src/definitions/core/OntimeEntry.ts.
|
||||
* Update this file when the data model changes.
|
||||
*/
|
||||
|
||||
// ---- Shared event field JSON schemas ----
|
||||
// Imported by mcp.tools.ts and spread into tool inputSchema.properties.
|
||||
|
||||
export const EVENT_TIMER_FIELDS = {
|
||||
timerType: {
|
||||
type: 'string',
|
||||
enum: ['count-down', 'count-up', 'clock', 'none'],
|
||||
description: 'count-down: countdown from duration; count-up: elapsed time; clock: wall clock; none: no timer shown',
|
||||
},
|
||||
endAction: {
|
||||
type: 'string',
|
||||
enum: ['none', 'load-next', 'play-next'],
|
||||
description: 'Action when event ends: none = stop, load-next = cue next event, play-next = auto-start next event',
|
||||
},
|
||||
linkStart: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
"Chain this event's start time to the previous event's end time — changing the first linked event propagates schedule changes to all linked followers",
|
||||
},
|
||||
countToEnd: { type: 'boolean', description: 'Timer counts toward the scheduled end time rather than elapsed time' },
|
||||
timeWarning: { type: 'number', description: 'ms before timeEnd to enter warning state (e.g. 300000 = 5 min)' },
|
||||
timeDanger: { type: 'number', description: 'ms before timeEnd to enter danger state (e.g. 60000 = 1 min)' },
|
||||
} as const;
|
||||
|
||||
export const EVENT_WRITABLE_FIELDS = {
|
||||
cue: { type: 'string', description: 'Short free-form cue label — ask the user what naming convention they prefer' },
|
||||
title: { type: 'string', description: 'Event title shown in the rundown and views' },
|
||||
note: { type: 'string', description: 'Free-text note for production notes or references' },
|
||||
colour: {
|
||||
type: 'string',
|
||||
description: 'Hex colour (#RRGGBB) for visual grouping — ask the user what colour convention they use',
|
||||
},
|
||||
skip: { type: 'boolean', description: 'If true, event is skipped during playback' },
|
||||
...EVENT_TIMER_FIELDS,
|
||||
} as const;
|
||||
|
||||
// ---- Agent-readable schema document ----
|
||||
// Served at ontime://schema. Agents read this once per session to orient themselves
|
||||
// before issuing tool calls.
|
||||
|
||||
export const ONTIME_SCHEMA_MARKDOWN = `# Ontime data model
|
||||
|
||||
A concise reference for how Ontime structures rundowns, events, and related data.
|
||||
|
||||
## Rundown
|
||||
|
||||
A rundown is an ordered list of entries rendered as a show schedule. A project can contain multiple rundowns; one is "loaded" at a time.
|
||||
|
||||
\`\`\`
|
||||
Rundown {
|
||||
id: string
|
||||
title: string
|
||||
order: EntryId[] // top-level entry order
|
||||
flatOrder: EntryId[] // includes entries nested in groups
|
||||
entries: { [id: EntryId]: OntimeEntry }
|
||||
revision: number
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
## Entries
|
||||
|
||||
There are four entry types discriminated by \`type\`:
|
||||
|
||||
### \`event\` — OntimeEvent (a timed show item)
|
||||
\`\`\`
|
||||
{
|
||||
type: 'event'
|
||||
id: EntryId
|
||||
cue: string // human-facing cue label
|
||||
title: string
|
||||
note: string
|
||||
colour: string // hex, e.g. "#4A90D9"
|
||||
timeStart: number // ms from midnight (09:00 = 32400000)
|
||||
timeEnd: number // ms from midnight
|
||||
duration: number // ms (= timeEnd - timeStart)
|
||||
delay: number // accumulated delay in ms (runtime)
|
||||
timerType: 'count-down' | 'count-up' | 'clock' | 'none'
|
||||
endAction: 'none' | 'load-next' | 'play-next'
|
||||
linkStart: boolean // chain start to previous event's end
|
||||
countToEnd: boolean // timer counts to planned end time
|
||||
skip: boolean // event is skipped during playback
|
||||
timeWarning: number // ms before end to trigger 'warning' state
|
||||
timeDanger: number // ms before end to trigger 'danger' state
|
||||
custom: { [key: string]: string } // custom field values
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
### \`delay\` — OntimeDelay (schedule shift applied to following events)
|
||||
\`\`\`
|
||||
{ type: 'delay', id, duration: number }
|
||||
\`\`\`
|
||||
|
||||
### \`group\` — OntimeGroup (nested container of entries)
|
||||
\`\`\`
|
||||
{ type: 'group', id, title, colour, note, entries: EntryId[], targetDuration?: number }
|
||||
\`\`\`
|
||||
|
||||
### \`milestone\` — OntimeMilestone (marker with no timer)
|
||||
\`\`\`
|
||||
{ type: 'milestone', id, cue, title, note, colour }
|
||||
\`\`\`
|
||||
|
||||
## Time format
|
||||
All time fields are **milliseconds from midnight (local)**. Examples:
|
||||
- 09:00:00 = 32400000
|
||||
- 09:30:00 = 34200000
|
||||
- 14:15:00 = 51300000
|
||||
- Duration of 45 min = 2700000
|
||||
|
||||
## Custom fields
|
||||
Custom fields are project-scoped definitions. Get definitions at \`ontime://project/custom-fields\`.
|
||||
Each event stores values at \`event.custom[fieldKey]\`.
|
||||
|
||||
## Playback states (runtime only)
|
||||
\`'stop' | 'play' | 'pause' | 'armed' | 'roll'\`
|
||||
When playback is not \`stop\`, mutating tools warn that changes are visible immediately.
|
||||
|
||||
## Available resources
|
||||
- \`ontime://schema\` — this document
|
||||
- \`ontime://rundown/current\` — the currently loaded rundown (JSON)
|
||||
- \`ontime://rundowns\` — all rundowns in the project (JSON)
|
||||
- \`ontime://project/info\` — project metadata (JSON)
|
||||
- \`ontime://project/custom-fields\` — custom field definitions (JSON)
|
||||
- \`ontime://docs\` — index of Ontime documentation topics with URLs
|
||||
|
||||
## Further reading
|
||||
Full Ontime documentation: **https://docs.getontime.no**
|
||||
`;
|
||||
|
||||
// ---- Documentation index ----
|
||||
// Served at ontime://docs. Agents read this when they need to point users to official docs.
|
||||
|
||||
export const ONTIME_DOCS_MARKDOWN = `# Ontime Documentation Index
|
||||
|
||||
Main site: https://docs.getontime.no
|
||||
|
||||
## Getting started
|
||||
- Installation & setup: https://docs.getontime.no/installation/
|
||||
|
||||
## Core concepts
|
||||
- Rundown: https://docs.getontime.no/concepts/rundown/
|
||||
- Timer types (count-down, count-up, clock, none): https://docs.getontime.no/concepts/timer/
|
||||
- Time entry format: https://docs.getontime.no/concepts/time-entry/
|
||||
- Event actions (end action, link start): https://docs.getontime.no/concepts/event-actions/
|
||||
- Delays and blocks: https://docs.getontime.no/concepts/delays-and-blocks/
|
||||
|
||||
## Features
|
||||
- Custom fields: https://docs.getontime.no/features/custom-fields/
|
||||
- Automations (triggers, filters, outputs): https://docs.getontime.no/features/automations/
|
||||
- URL presets / shared views: https://docs.getontime.no/features/url-presets/
|
||||
- HTTP Integration: https://docs.getontime.no/api/http/
|
||||
- OSC Integration: https://docs.getontime.no/api/osc/
|
||||
|
||||
## API reference
|
||||
- REST API overview: https://docs.getontime.no/api/
|
||||
- WebSocket events: https://docs.getontime.no/api/websocket/
|
||||
`;
|
||||
@@ -25,45 +25,11 @@ import { getState } from '../stores/runtimeState.js';
|
||||
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
import { deleteRundown, renameRundown, rundownListResponse } from './mcp.service.js';
|
||||
import { EVENT_TIMER_FIELDS, EVENT_WRITABLE_FIELDS } from './mcp.schema.js';
|
||||
|
||||
// Graceful truncation to keep tool responses within typical MCP context windows
|
||||
const CHARACTER_LIMIT = 25_000;
|
||||
|
||||
// ---- Shared event field JSON schemas ----
|
||||
// Reused across create_event, update_event, create_events_batch, batch_update_events to avoid repetition.
|
||||
const EVENT_TIMER_FIELDS = {
|
||||
timerType: {
|
||||
type: 'string',
|
||||
enum: ['count-down', 'count-up', 'clock', 'none'],
|
||||
description: 'count-down: countdown from duration; count-up: elapsed time; clock: wall clock; none: no timer shown',
|
||||
},
|
||||
endAction: {
|
||||
type: 'string',
|
||||
enum: ['none', 'load-next', 'play-next'],
|
||||
description: 'Action when event ends: none = stop, load-next = cue next event, play-next = auto-start next event',
|
||||
},
|
||||
linkStart: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
"Chain this event's start time to the previous event's end time — changing the first linked event propagates schedule changes to all linked followers",
|
||||
},
|
||||
countToEnd: { type: 'boolean', description: 'Timer counts toward the scheduled end time rather than elapsed time' },
|
||||
timeWarning: { type: 'number', description: 'ms before timeEnd to enter warning state (e.g. 300000 = 5 min)' },
|
||||
timeDanger: { type: 'number', description: 'ms before timeEnd to enter danger state (e.g. 60000 = 1 min)' },
|
||||
} as const;
|
||||
|
||||
const EVENT_WRITABLE_FIELDS = {
|
||||
cue: { type: 'string', description: 'Short free-form cue label — ask the user what naming convention they prefer' },
|
||||
title: { type: 'string', description: 'Event title shown in the rundown and views' },
|
||||
note: { type: 'string', description: 'Free-text note for production notes or references' },
|
||||
colour: {
|
||||
type: 'string',
|
||||
description: 'Hex colour (#RRGGBB) for visual grouping — ask the user what colour convention they use',
|
||||
},
|
||||
skip: { type: 'boolean', description: 'If true, event is skipped during playback' },
|
||||
...EVENT_TIMER_FIELDS,
|
||||
} as const;
|
||||
|
||||
// ---- MCP tool annotation presets ----
|
||||
// https://modelcontextprotocol.io/docs/concepts/tools#tool-annotations
|
||||
const READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false } as const;
|
||||
|
||||
Reference in New Issue
Block a user