{"name":"com.rhylthyme/rhylthyme","slug":"rhylthyme","title":"Rhylthyme","description":"Real-time multi-track schedules for cooking, lab protocols, events and workouts. Validate and share.","url":"https://mcp.market/server/rhylthyme","rating":null,"grade":"B","score":81,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":0,"stars":null,"forks":null,"downloads_week":null,"last_push_at":null,"license":null},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":"https://github.com/rhylthyme/rhylthyme-mcp","website":"https://www.rhylthyme.com","version":"1.3.0","remotes":[{"type":"streamable-http","url":"https://mcp.rhylthyme.com/mcp"}],"packages":[],"tools":[{"name":"analyze_schedule","description":"Resolve a Rhylthyme program onto the clock and report what the live runner will do: every step's start/end (seconds from start and, if you pass `finishAt` or `startAt`, ISO wall-clock times), total makespan, the critical path, `bindingConstraints` (what gates each critical-path edge — an in-flight cap, a saturated task, an offset, or a plain dependency), resource conflicts tagged `kind: \"maxConcurrent\"` (more steps claim a task than its maxConcurrent allows) or `kind: \"inFlight\"` (more instances of a replicated step are between it and its barrier than `replicates.maxInFlight` allows), `inFlight` windows per replicated step, peak concurrency vs. declared actors, and per-track slack (instances get their own sub-track rows, tagged with `parentTrackId` / `instanceOf`). Use it to answer 'when do I start the potatoes so everything is ready at 6pm?' (pass finishAt), to find why a schedule is longer than expected (critical path and binding constraints — e.g. the cooling rack, not the oven), or to check equipment contention before visualizing. Pure computation; also returns validation findings so you can fix problems in the same turn.\n\n**Analysing against real history.** Pass `history` (run records from **load_run**, or from `rhylthyme runs` on disk) and every step with enough measurements gains `predicted: {seconds, low, high, basis, n}` beside its planned duration, plus top-level `predictedMakespan` and `predictedCriticalPath`. `basis` is `\"identical\"` (runs of the same program version, environment and variance factors — their median), `\"model\"` (a per-step regression on the factors that correlate) or `\"none\"` (no usable measurement). Simpler still: give `program_id` (a UUID from **list_my_programs**) plus `token` and the tool loads the caller's own recorded runs of that program for you. `useDurations: \"predicted\"` then recomputes the makespan, itinerary, critical path and conflicts from the predicted durations instead of the authored ones; the default stays `\"planned\"` so a program is analysed on what it says.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program":{"type":"object","properties":{},"additionalProperties":{},"description":"Rhylthyme program JSON (any shape — validation errors come back in the result, not as a schema rejection)."},"finishAt":{"description":"ISO 8601 datetime the whole program should END at (e.g. '2026-11-26T18:00:00-05:00'). Start times are computed backwards from it.","type":"string"},"startAt":{"description":"ISO 8601 datetime the program STARTS at. Ignored when finishAt is given.","type":"string"},"history":{"description":"Recorded runs of this program (`runs` schema 0.1.0-alpha documents, as load_run returns them in `run`). Supplying them adds `predicted` per step and `predictedMakespan` / `predictedCriticalPath` to the result. Only runs that measure the executor count — completed, wall clock, speed 1 — and within them only steps a person ended, unpaused.","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"program_id":{"description":"Library program UUID: with `token` and no `history`, the caller's own recorded runs of this program are loaded and used as the history.","type":"string"},"token":{"description":"Your Rhylthyme access token from the login tool. Only needed with `program_id`, to load your recorded runs; analysis itself needs no login.","type":"string"},"predictionContext":{"description":"How to condition the prediction. Everything is optional; with none of it the lookup uses the program's own hash and the factors each run recorded.","type":"object","properties":{"environmentId":{"description":"Predict for this environment; runs recorded elsewhere are not \"identical\".","type":"string"},"userTags":{"description":"The variance factors of the run being planned, e.g. {\"turkeyKg\": 7, \"oven\": \"gas\"} — the values the model is evaluated at.","type":"object","properties":{},"additionalProperties":{}},"userId":{"description":"Prefer this person's own runs for the identical-context lookup before falling back to everyone's.","type":"string"},"programVersion":{"description":"`sha256:<hex>` of the exact program JSON being planned; defaults to the hash of `program`.","type":"string"},"minIdentical":{"description":"Identical-context runs needed before their median is used (default 3).","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"minModel":{"description":"Measurements needed before a regression is fitted rather than a median (default 8).","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"corrThreshold":{"description":"Minimum |Pearson r| for a factor to enter the model (default 0.3).","type":"number"},"verdicts":{"description":"Inferentiality verdicts per step (`rhylthyme runs report`); a step marked executor-controlled gets no prediction.","type":"object","properties":{},"additionalProperties":{}}},"additionalProperties":{}},"useDurations":{"default":"planned","description":"Which duration set the makespan, wall-clock itinerary, critical path, conflicts and slack are computed from. \"planned\" (default) analyses the program as authored; \"predicted\" analyses it as history says it will actually run. Needs `history` (or `program_id` + `token`) to differ.","type":"string","enum":["planned","predicted"]}},"required":["program"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"calibrate_program","description":"Propose new durations for one of the user's saved programs from its recorded runs, with the evidence. For every non-fixed step with enough runs a person ended by hand: the median becomes the proposed default, the 10th/90th percentiles the proposed min/max, widened so the author's own range is never narrowed. A fixed step that consistently overruns gets a \"consider variable\" note and no number, because only the author can decide that. The result is a per-step table (n, median, IQR, current, proposed, delta) plus what accepting the lot would do to the makespan and the critical path. **It never saves anything**: pass `accept` to get the calibrated program back — each changed duration carrying `calibratedFrom` — and then save_program if the user wants it kept. Requires a login token; the runs are private to whoever ran them.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program":{"description":"The program JSON to calibrate. Omit it and `program_id`'s saved JSON is used, so the usual call is just an id.","type":"object","properties":{},"additionalProperties":{}},"program_id":{"description":"Library program UUID (from list_my_programs). Names the program whose recorded runs are the evidence, and — with no `program` — the JSON to calibrate.","type":"string"},"history":{"description":"Run records to use instead of the ones stored against `program_id` (`runs` schema 0.1.0-alpha).","type":"array","items":{"type":"object","properties":{},"additionalProperties":{}}},"k":{"description":"Measurements a step needs before it gets a proposal (default 5). A step under it is reported as skipped with its statistics, not silently dropped.","type":"integer","minimum":1,"maximum":9007199254740991},"since":{"description":"Only runs started on or after this date (YYYY-MM-DD or ISO), e.g. to calibrate on the last month's cooks only.","type":"string"},"accept":{"description":"Step ids to accept, or \"all\". The result then also carries the calibrated program with `calibratedFrom` beside each written duration. NOTHING IS SAVED either way — pass that program to save_program if the user wants it kept.","anyOf":[{"type":"string","const":"all"},{"type":"array","items":{"type":"string"}}]},"token":{"description":"Your Rhylthyme access token from the login tool","type":"string"}},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"create_environment","description":"Create a Rhylthyme environment definition with resource constraints for a workspace (lab, kitchen, bakery, etc.). Returns environment JSON; copy its resourceConstraints into the program (or reference it by environmentId) before calling **visualize_schedule**.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["kitchen","laboratory","bakery","airport","restaurant","manufacturing","hospital","workshop","event","gym","general"]},"description":{"type":"string"},"actors":{"description":"How many people can work at once (default 1).","type":"integer","minimum":1,"maximum":9007199254740991},"resourceConstraints":{"minItems":1,"type":"array","items":{"type":"object","properties":{"task":{"type":"string"},"maxConcurrent":{"type":"integer","minimum":1,"maximum":9007199254740991},"description":{"type":"string"}},"required":["task","maxConcurrent"],"additionalProperties":{}}}},"required":["name","type","resourceConstraints"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_renderer_source","description":"Returns the source code of the open-source Rhylthyme timeline renderer (Apache-2.0, ~9KB, zero dependencies). Use this when you're building an HTML artifact and the artifact sandbox blocks external scripts (e.g., Claude.ai's CSP only allows cdnjs.cloudflare.com). The returned text is plain JavaScript with a UMD wrapper — paste it verbatim inside a `<script>…</script>` block in your artifact, then call `Rhylthyme.renderTimeline(container, program)` where `program` is the Rhylthyme program JSON. After this call, the global `Rhylthyme` object exposes: `renderTimeline(container, program)`, `renderTimelineSvg(program)`, `computeStepTimings(program)`, `parseSeconds(value)` and `stepDurationSeconds(step)`.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"import_from_source","description":"Import a recipe or lab protocol from an external source into a Rhylthyme program. Sources: spoonacular (recipes, preferred), themealdb (recipes, fallback), protocolsio (lab protocols), cooklang (.cook recipe URL — action must be 'import', query is the URL; GitHub blob URLs are auto-converted), opentrons (Opentrons Protocol API v2 .py — pass URL as query, or paste source via text; action must be 'import'), benchling (the user's connected library). Actions: search (no login needed), import and random (need the user's Rhylthyme token from **login**). After import, run the returned program through **visualize_schedule**. Pass `enrich: true` with action='import' to split the import into parallel tracks with cross-track triggers (one model call, capped per day; inferred steps are marked `metadata.inferred`).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"source":{"type":"string","enum":["themealdb","protocolsio","spoonacular","cooklang","opentrons","benchling","llm-text"]},"action":{"type":"string","enum":["search","import","random"]},"query":{"description":"Search keywords (search), or the URL / id to import (import).","type":"string"},"text":{"description":"Raw source text (Opentrons .py) when the user pasted it instead of a URL.","type":"string"},"enrich":{"description":"Split the import into parallel tracks with cross-track triggers (action='import' only). Runs the relationship turn of the plan_schedule prompt server-side against the imported step list: steps, durations and resources are kept as imported, tracks and start triggers are inferred, and any step the model adds is marked `metadata.inferred`. Costs a model call and is capped per day; if it fails you still get the un-enriched program.","type":"boolean"},"token":{"description":"User's Rhylthyme access token from the **login** tool. Required for action='import' and action='random' on every source, and for anything with source='benchling'. Not needed for action='search' on public sources.","type":"string"}},"required":["source","action"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"import_text","description":"Turn a block of pasted text — a recipe, a lab protocol, a run-of-show, a training plan — into a validated multi-track Rhylthyme program. Use when the user pastes the steps themselves and no structural importer fits (no URL, no supported service, a photo they transcribed, a PDF they copied out of). Runs four model turns server-side: read-back, schema check, step extraction with the exact source span each step came from, then tracks and triggers. Needs the user's Rhylthyme token from **login**; costs a model call per turn and is capped per day. Returns the program plus a step→span table, so you can show the user which words each step came from and which steps were inferred.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"text":{"type":"string","description":"The source text itself: the recipe, protocol, run sheet or plan, as the user wrote or pasted it. Paste all of it — turn 1 reads it back and a long source is extracted in chunks."},"environmentType":{"type":"string","description":"Where the work happens: kitchen, lab, events, gym, or generic. Fills the scenario prompt's environment slot and becomes the program's environmentType."},"deadline":{"description":"When everything must be finished, if the user said: \"18:00\", \"dinner at six\", an ISO datetime.","type":"string"},"hints":{"description":"Equipment and people limits in the user's own words, e.g. 'one oven, two burners, one cook'. Used as the scenario prompt's environment and as the resource constraints to expect.","type":"string"},"token":{"description":"User's Rhylthyme access token from the **login** tool. Required: this import runs model calls on the server.","type":"string"}},"required":["text","environmentType"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_my_programs","description":"List your saved Rhylthyme schedules. Requires a login token from the login tool.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"token":{"type":"string","description":"Your Rhylthyme access token from the login tool"}},"required":["token"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_public_runs","description":"List the runs other people have contributed for one exact program version: when each ran, how it ended, actual against planned total, and the variance factors that run was recorded with. Contribution is opt-in per run and contributed records carry no user id and no step notes, so this is anonymous, aggregate evidence about how long a program really takes. **No login needed.** Identify the program either by `program_hash` (`sha256:<hex>`, as `programVersion` in a run record) or by passing the `program` JSON, which is hashed here.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program_hash":{"description":"Canonical program hash, \"sha256:\" plus 64 hex characters — the programVersion field of a run record, or programs.program_hash.","type":"string"},"program":{"description":"The program JSON to look up instead of a hash; it is hashed here with the same canonical hash the runtimes record.","type":"object","properties":{},"additionalProperties":{}},"limit":{"description":"How many contributed runs to return, newest first (default 50).","type":"integer","minimum":1,"maximum":200}},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_runs","description":"List the recorded executions of one saved program, newest first: when it ran, how it ended, and the actual makespan against the planned one. A run record is written whenever the live timeline is played (or the terminal runner is used); it is what makes the planned durations checkable against reality. Requires a login token; runs are private to whoever ran them.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program_id":{"type":"string","description":"The program UUID from list_my_programs or the program's URL"},"token":{"description":"Your Rhylthyme access token from the login tool","type":"string"}},"required":["program_id"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"load_program","description":"Load a specific saved program by ID. Returns a markdown summary plus a live-timeline URL.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"token":{"type":"string","description":"Your Rhylthyme access token"},"program_id":{"type":"string","description":"The program UUID from list_my_programs"}},"required":["token","program_id"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"load_public_recipe","description":"Load a single public recipe / protocol / workout / event template by id. Returns a markdown summary plus a live-timeline URL (no visualize_schedule call needed).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program_id":{"type":"string","description":"Program UUID (from search_public_recipes)"}},"required":["program_id"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"load_run","description":"Open one recorded execution by run id: planned versus actual start, end and duration for every step, what ended each step (a person, a timer, an abort), time the clock was paused, and the recorded variance factors. Use it to see where a plan drifts from reality. Requires a login token.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"run_id":{"type":"string","description":"The run UUID from list_runs"},"token":{"description":"Your Rhylthyme access token from the login tool","type":"string"}},"required":["run_id"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"login","description":"Sign in to your Rhylthyme account so you can list and save your schedules and import from external sources. Opens a browser page where you log in (Google, Apple, or email). After signing in, copy the token displayed on the page and provide it here. Tokens expire after about an hour; if a later call reports an auth error, call login again for a fresh one.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"token":{"description":"Paste the access token shown on the login page after you sign in. Leave empty on the first call to get the login URL.","type":"string"}},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"preview_timeline","description":"Render a Rhylthyme program as a static Gantt-chart image so the user can SEE what the live timeline looks like, without committing to opening the live URL. Use this when the user asks for a 'preview' or 'picture' of the timeline, or when you have just built a freehand program and want to give the user a visual before they commit. The tool returns ONLY an image plus a one-line caption — no recipe prose, no ingredient list, no copyright concerns. Just the structural visualization of which step runs when on which track.\n\nPair with **visualize_schedule** when the user wants the full shareable interactive URL too. This tool is for the visual-only quick preview case.\n\n**Planned versus actual.** Pass `run` — a recorded run of the same program, as **load_run** returns it in `run` — and the picture becomes a comparison: each step's real bar over a thin ghost bar at its planned position, outlined green where it finished early and amber where it ran late. That is the fastest way to show a person where a plan drifted.\n\n**Rendering option for HTML-artifact-capable clients (Claude.ai etc.):** Claude.ai's artifact sandbox blocks external scripts from non-cdnjs sources, so a `<script src=\"https://kitchen.rhylthyme.com/...\">` tag will fail. To render the timeline yourself with the official Rhylthyme look, call **get_renderer_source** first to fetch the renderer's full source as a string, then embed that source verbatim inside a `<script>…</script>` block in your HTML artifact, followed by your program JSON and a call to `Rhylthyme.renderTimeline(document.getElementById('t'), program)`. The renderer is open-source (Apache-2.0), zero-dependency, ~9KB.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program":{"type":"object","properties":{},"additionalProperties":{},"description":"Rhylthyme program JSON (same shape visualize_schedule accepts)."},"run":{"description":"Optional recorded run of the SAME program (`runs` schema 0.1.0-alpha — the `run` object from load_run). Draws planned-vs-actual: the actual bars over ghost bars at the planned positions, coloured by the sign of each step's end deviation.","type":"object","properties":{},"additionalProperties":{}}},"required":["program"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"save_program","description":"Save a Rhylthyme program to your account. If a program with the same programId already exists, it will be updated. Requires a login token.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"token":{"type":"string","description":"Your Rhylthyme access token"},"program":{"type":"object","properties":{"schemaVersion":{"default":"0.1.0","type":"string"},"programId":{"type":"string","description":"Kebab-case identifier"},"name":{"type":"string","description":"Human-readable name"},"description":{"type":"string"},"environmentType":{"description":"kitchen | laboratory | event | gym | bakery | manufacturing | general …","type":"string"},"environment":{"description":"Optional environmentId whose resourceConstraints apply.","type":"string"},"actors":{"description":"How many people are available to work steps concurrently.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"tracks":{"minItems":1,"type":"array","items":{"type":"object","properties":{"trackId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"steps":{"type":"array","items":{"type":"object","properties":{"stepId":{"type":"string","description":"Unique across the WHOLE program."},"name":{"type":"string"},"description":{"type":"string"},"task":{"description":"Resource this step occupies; must match a resourceConstraints[].task.","type":"string"},"tasks":{"type":"array","items":{"type":"string"}},"duration":{"type":"object","properties":{"type":{"type":"string","enum":["fixed","variable","indefinite"],"description":"fixed: exact seconds. variable: min/max with a default, user can end early. indefinite: runs until the user ends it (give defaultSeconds for planning)."},"seconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"minSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"maxSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"defaultSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"triggerName":{"type":"string"}},"required":["type"],"additionalProperties":{}},"startTrigger":{"type":"object","properties":{"type":{"description":"programStart: at t=0. programStartOffset: offsetSeconds after t=0. afterStep: when stepId ends (or starts, with event='start') plus offsetSeconds. afterStepWithBuffer: after stepId ends plus bufferSeconds. manual: user taps to start. onAbort: only if stepId is aborted.","type":"string","enum":["programStart","programStartOffset","afterStep","afterStepWithBuffer","manual","onAbort"]},"stepId":{"description":"Referenced step (afterStep / afterStepWithBuffer / onAbort).","type":"string"},"event":{"description":"afterStep anchor: the referenced step's end (default) or start.","type":"string","enum":["start","end"]},"offsetSeconds":{"description":"Delay after the anchor. Negative values ('start 20m before X ends') require the referenced step to be indefinite.","anyOf":[{"type":"number"},{"type":"string"}]},"bufferSeconds":{"description":"afterStepWithBuffer: gap after the referenced step ends.","anyOf":[{"type":"number"},{"type":"string"}]},"choiceId":{"description":"Only run this step if the user picked this option on the referenced step's choice.","type":"string"},"triggerName":{"type":"string"},"logic":{"description":"Compound trigger: wait for all / any of `triggers`.","type":"string","enum":["all","any"]},"triggers":{"type":"array","items":{"type":"object","properties":{"type":{"description":"programStart: at t=0. programStartOffset: offsetSeconds after t=0. afterStep: when stepId ends (or starts, with event='start') plus offsetSeconds. afterStepWithBuffer: after stepId ends plus bufferSeconds. manual: user taps to start. onAbort: only if stepId is aborted.","type":"string","enum":["programStart","programStartOffset","afterStep","afterStepWithBuffer","manual","onAbort"]},"stepId":{"description":"Referenced step (afterStep / afterStepWithBuffer / onAbort).","type":"string"},"event":{"description":"afterStep anchor: the referenced step's end (default) or start.","type":"string","enum":["start","end"]},"offsetSeconds":{"description":"Delay after the anchor. Negative values ('start 20m before X ends') require the referenced step to be indefinite.","anyOf":[{"type":"number"},{"type":"string"}]},"bufferSeconds":{"description":"afterStepWithBuffer: gap after the referenced step ends.","anyOf":[{"type":"number"},{"type":"string"}]},"choiceId":{"description":"Only run this step if the user picked this option on the referenced step's choice.","type":"string"},"triggerName":{"type":"string"}},"additionalProperties":{}}}},"additionalProperties":{}},"choice":{"description":"Branch point: downstream steps with a matching choiceId only run for that option.","type":"object","properties":{"prompt":{"type":"string"},"options":{"minItems":2,"type":"array","items":{"type":"object","properties":{"choiceId":{"type":"string"},"label":{"type":"string"}},"required":["choiceId"],"additionalProperties":{}}}},"required":["options"],"additionalProperties":{}},"replicates":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":9007199254740991},"mode":{"type":"string","enum":["parallel","stagger","serial"]},"delay":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."}},"required":["count"],"additionalProperties":{}},"canAbort":{"type":"boolean"}},"required":["stepId","name","duration","startTrigger"],"additionalProperties":{}}},"replicates":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":9007199254740991},"mode":{"type":"string","enum":["parallel","stagger","serial"]},"delay":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."}},"required":["count"],"additionalProperties":{}}},"required":["trackId","name","steps"],"additionalProperties":{}}},"resourceConstraints":{"type":"array","items":{"type":"object","properties":{"task":{"type":"string"},"maxConcurrent":{"type":"integer","minimum":1,"maximum":9007199254740991},"description":{"type":"string"}},"required":["task","maxConcurrent"],"additionalProperties":{}}},"metadata":{"type":"object","properties":{"ingredients":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"measure":{"type":"string"}},"required":["name"],"additionalProperties":{}}},"serves":{"anyOf":[{"type":"string"},{"type":"number"}]},"sourceUrl":{"type":"string"},"attribution":{"type":"string"},"thumbnail":{"type":"string"}},"additionalProperties":{}}},"required":["programId","name","tracks"],"additionalProperties":{},"description":"Rhylthyme program JSON. Read rhylthyme://guide/authoring for the rules."}},"required":["token","program"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"search_public_recipes","description":"Search the public Rhylthyme catalog of cookable recipes, lab protocols, event templates, and workouts. Returns up to 50 matching programs (id, name, description, view URL) — no sign-in required. The catalog is split by environment: pass environment='kitchen' (default), 'laboratory', 'event' or 'gym' to pick the collection. Pass an id to **load_public_recipe** for the full schedule (its result already includes the live URL).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"query":{"default":"","type":"string","description":"Keyword to search (matches name and description). Empty returns the most recent entries."},"environment":{"default":"kitchen","description":"Which catalog to search. Defaults to \"kitchen\"; use \"laboratory\", \"event\" or \"gym\" for the other collections.","type":"string","enum":["kitchen","laboratory","gym","event","events"]},"limit":{"default":20,"type":"integer","minimum":1,"maximum":50}},"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"validate_program","description":"Check a Rhylthyme program for structural and scheduling errors BEFORE visualizing or saving it: missing/duplicate ids, dangling afterStep references, dependency cycles, steps that overlap within a track, tasks with no resourceConstraint, unparseable durations, invalid choice references, and schema 0.3.0-alpha `instances`/`replicates` misuse (E_INSTANCES_ON_SINGLE, E_EACH_WITH_REPLICATES, E_EACH_COUNT_MISMATCH, E_INFLIGHT_GT_COUNT, E_INFLIGHT_NO_CHAIN). Every finding has a `code`, a `message` and a `fix` hint — apply the fixes and re-run until `valid` is true. Warnings (e.g. tracks that finish far apart, W_UNBARRIERED_CHAIN) are advisory; `info` notes (I_IMPLICIT_BARRIER: a replicated step referenced without `instances`) suggest making a barrier explicit. Pure computation: no network, no side effects, safe to call repeatedly.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"program":{"type":"object","properties":{},"additionalProperties":{},"description":"Rhylthyme program JSON (any shape — validation errors come back in the result, not as a schema rejection)."}},"required":["program"],"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"visualize_schedule","description":"Render a multi-step parallel schedule as a live timeline (cooking, lab protocols, event run-of-show, training). **Call this for ANY schedule you produce — imported, catalog match, or built freehand.** A schedule belongs in a visualization, never in prose. The program is validated first (same checks as validate_program); invalid programs are refused with fix hints instead of being published. Returns a markdown preview (cover photo if any, equipment list, ingredient list, ASCII Gantt timeline, chronological itinerary, schedule check) and a shareable rhylthyme.com URL with the interactive view.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"program":{"type":"object","properties":{"schemaVersion":{"default":"0.1.0","type":"string"},"programId":{"type":"string","description":"Kebab-case identifier"},"name":{"type":"string","description":"Human-readable name"},"description":{"type":"string"},"environmentType":{"description":"kitchen | laboratory | event | gym | bakery | manufacturing | general …","type":"string"},"environment":{"description":"Optional environmentId whose resourceConstraints apply.","type":"string"},"actors":{"description":"How many people are available to work steps concurrently.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"tracks":{"minItems":1,"type":"array","items":{"type":"object","properties":{"trackId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"steps":{"type":"array","items":{"type":"object","properties":{"stepId":{"type":"string","description":"Unique across the WHOLE program."},"name":{"type":"string"},"description":{"type":"string"},"task":{"description":"Resource this step occupies; must match a resourceConstraints[].task.","type":"string"},"tasks":{"type":"array","items":{"type":"string"}},"duration":{"type":"object","properties":{"type":{"type":"string","enum":["fixed","variable","indefinite"],"description":"fixed: exact seconds. variable: min/max with a default, user can end early. indefinite: runs until the user ends it (give defaultSeconds for planning)."},"seconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"minSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"maxSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"defaultSeconds":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."},"triggerName":{"type":"string"}},"required":["type"],"additionalProperties":{}},"startTrigger":{"type":"object","properties":{"type":{"description":"programStart: at t=0. programStartOffset: offsetSeconds after t=0. afterStep: when stepId ends (or starts, with event='start') plus offsetSeconds. afterStepWithBuffer: after stepId ends plus bufferSeconds. manual: user taps to start. onAbort: only if stepId is aborted.","type":"string","enum":["programStart","programStartOffset","afterStep","afterStepWithBuffer","manual","onAbort"]},"stepId":{"description":"Referenced step (afterStep / afterStepWithBuffer / onAbort).","type":"string"},"event":{"description":"afterStep anchor: the referenced step's end (default) or start.","type":"string","enum":["start","end"]},"offsetSeconds":{"description":"Delay after the anchor. Negative values ('start 20m before X ends') require the referenced step to be indefinite.","anyOf":[{"type":"number"},{"type":"string"}]},"bufferSeconds":{"description":"afterStepWithBuffer: gap after the referenced step ends.","anyOf":[{"type":"number"},{"type":"string"}]},"choiceId":{"description":"Only run this step if the user picked this option on the referenced step's choice.","type":"string"},"triggerName":{"type":"string"},"logic":{"description":"Compound trigger: wait for all / any of `triggers`.","type":"string","enum":["all","any"]},"triggers":{"type":"array","items":{"type":"object","properties":{"type":{"description":"programStart: at t=0. programStartOffset: offsetSeconds after t=0. afterStep: when stepId ends (or starts, with event='start') plus offsetSeconds. afterStepWithBuffer: after stepId ends plus bufferSeconds. manual: user taps to start. onAbort: only if stepId is aborted.","type":"string","enum":["programStart","programStartOffset","afterStep","afterStepWithBuffer","manual","onAbort"]},"stepId":{"description":"Referenced step (afterStep / afterStepWithBuffer / onAbort).","type":"string"},"event":{"description":"afterStep anchor: the referenced step's end (default) or start.","type":"string","enum":["start","end"]},"offsetSeconds":{"description":"Delay after the anchor. Negative values ('start 20m before X ends') require the referenced step to be indefinite.","anyOf":[{"type":"number"},{"type":"string"}]},"bufferSeconds":{"description":"afterStepWithBuffer: gap after the referenced step ends.","anyOf":[{"type":"number"},{"type":"string"}]},"choiceId":{"description":"Only run this step if the user picked this option on the referenced step's choice.","type":"string"},"triggerName":{"type":"string"}},"additionalProperties":{}}}},"additionalProperties":{}},"choice":{"description":"Branch point: downstream steps with a matching choiceId only run for that option.","type":"object","properties":{"prompt":{"type":"string"},"options":{"minItems":2,"type":"array","items":{"type":"object","properties":{"choiceId":{"type":"string"},"label":{"type":"string"}},"required":["choiceId"],"additionalProperties":{}}}},"required":["options"],"additionalProperties":{}},"replicates":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":9007199254740991},"mode":{"type":"string","enum":["parallel","stagger","serial"]},"delay":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."}},"required":["count"],"additionalProperties":{}},"canAbort":{"type":"boolean"}},"required":["stepId","name","duration","startTrigger"],"additionalProperties":{}}},"replicates":{"type":"object","properties":{"count":{"type":"integer","minimum":1,"maximum":9007199254740991},"mode":{"type":"string","enum":["parallel","stagger","serial"]},"delay":{"anyOf":[{"type":"number"},{"type":"string"}],"description":"Seconds as a number, or a time string like \"5m\", \"1h30m\", \"90s\"."}},"required":["count"],"additionalProperties":{}}},"required":["trackId","name","steps"],"additionalProperties":{}}},"resourceConstraints":{"type":"array","items":{"type":"object","properties":{"task":{"type":"string"},"maxConcurrent":{"type":"integer","minimum":1,"maximum":9007199254740991},"description":{"type":"string"}},"required":["task","maxConcurrent"],"additionalProperties":{}}},"metadata":{"type":"object","properties":{"ingredients":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"measure":{"type":"string"}},"required":["name"],"additionalProperties":{}}},"serves":{"anyOf":[{"type":"string"},{"type":"number"}]},"sourceUrl":{"type":"string"},"attribution":{"type":"string"},"thumbnail":{"type":"string"}},"additionalProperties":{}}},"required":["programId","name","tracks"],"additionalProperties":{},"description":"Rhylthyme program JSON. Read rhylthyme://guide/authoring for the rules."},"allowInvalid":{"default":false,"description":"Publish even if validation reports errors. Only use when the user explicitly wants an imperfect draft shared; the live page may show wrong timings.","type":"boolean"}},"required":["program"],"$schema":"http://json-schema.org/draft-07/schema#"}}],"scan":{"score":81,"grade":"B","scanned_at":"2026-09-18T04:54:22.976Z","report":{"scannerVersion":"0.1.2","scannedAt":"2026-09-18T04:54:22.894Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 1903ms"]},"poisoning":{"score":13,"max":15,"notes":["18 tool descriptions checked"]},"auth":{"score":3,"max":15,"notes":["open endpoint exposes 4 write-action tools with no auth"]},"maintenance":{"score":15,"max":15,"notes":["last push 1 days ago"]},"identity":{"score":10,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year","website matches verified namespace"]}},"findings":[{"id":"auth.open-write","severity":"high","component":"auth","title":"Write-action tools reachable without authentication"},{"id":"poison.long-description","severity":"low","component":"poisoning","title":"Unusually long tool description (over 2,000 characters)","evidence":"tool analyze_schedule: …Resolve a Rhylthyme program onto the clock and report what the live runner will do: every step's start/end (seconds from start and, if you pass `finishAt` or `startAt`, ISO wall-clock times), total makespan, the critical path, `bindingConstraints` (what gates each critical-path edge — an in-flight cap, a saturated task, an offset, or a plain dependency), resource conflicts tagged `kind: \"maxConcurrent\"` (more steps claim a task than its maxConcurrent allows) or `kind: \"inFlight\"` (more instances of a replicated step are between it and its barrier than `replicates.maxInFlight` allows), `inFlight` windows per replicated step, peak concurrency vs. declared actors, and per-track slack (instances get their own sub-track rows, tagged with `parentTrackId` / `instanceOf`). Use it to answer 'when do I start the potatoes so everything is ready at 6pm?' (pass finishAt), to find why a schedule is longer than expected (critical path and binding constraints — e.g. the cooling rack, not the oven), or to check equipment contention before visualizing. Pure computation; also returns validation findings so you can fix problems in the same turn. **Analysing against real history.** Pass `history` (run records from **load_run**, or from `rhylthyme runs` on disk) and every step with enough measurements gains `predicted: {seconds, low, high, basis, n}` beside its planned duration, plus top-level `predictedMakespan` and `predictedCriticalPath`. `basis` is `\"identical\"` (runs of the same program version, environment and variance factors — their median), `\"model\"` (a per-step regression on the factors that correlate) or `\"none\"` (no usable measurement). Simpler still: give `program_id` (a UUID from **list_my_programs**) plus `token` and the tool loads the caller's own recorded runs of that program for you. `useDurations: \"predicted\"` then recomputes the makespan, itinerary, critical path and conflicts from the predicted durations instead of the authored ones; the default stays `\"planned\"` so a program is analysed on what it says.…"}],"inputs":{"probes":[{"url":"https://mcp.rhylthyme.com/mcp","reachable":true,"authRequired":false,"latencyMs":1903,"serverInfo":{"name":"rhylthyme-mcp","version":"1.3.0"}}],"packages":[],"repo":{"found":true,"owner":"rhylthyme","repo":"rhylthyme-mcp","archived":false,"pushedAt":"2026-09-17T14:37:46Z","stars":0,"openIssues":0,"ownerType":"Organization","ownerCreatedAt":"2025-06-16T20:30:31Z","license":"MIT"}}}},"grade_history":[],"reviews":[]}