Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
HYDRA_DECK_URLNoThe base URL of the deck server. The MCP server connects to this address. Defaults to http://127.0.0.1:8140.http://127.0.0.1:8140
HYDRA_OUT_PORTNoThe port used by the optional video out process (out/hydra_out.py).8141
HYDRA_DECK_HOMENoDirectory where the deck stores its configuration, live document, and state files.~/.hydra-deck
HYDRA_DECK_PORTNoThe port on which the deck server listens. Used to build the default HYDRA_DECK_URL when not explicitly set.8140
HYDRA_DECK_TOKENNoIf set, this token is sent as X-Hydra-Token when making requests to the deck's control API. Required only if the deck has a token configured.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
hydra_stateA

Which Hydra tabs are connected and whether they can be trusted right now.

Returns every tab with its role (exactly one primary answers; mirrors just follow), its adapter (deck = our page, ojack = the official editor, generic = any other Hydra tab), fps, resolution, speed/bpm, which sources are live, the block names with their authors and the outputs they draw into, and the primary's recent runtime warnings.

Two fields are not formalities: visible false means the tab is in the background. Browsers throttle its frames, so screenshots stall and what you see may be minutes old. Ask for it to be brought to the front rather than working blind. mic 'prompt' means the browser is still waiting for someone to click Allow. Audio-reactive code (a.fft) reads zeros until they do — and nobody may be at the machine. Never assume the click happened.

hydra_documentA

The shared composition: ordered named blocks, each with its code and author, plus the whole thing as one text with // @block <name> separators. When the primary is an existing Hydra tab, tab_editor is that tab's own editor text — the truth about what plays there, including anything typed by hand.

Read this before writing, so you extend the piece instead of talking over it — and so you can see which outputs (o0–o3) are already taken.

hydra_lookA

A screenshot of the primary tab's canvas, as an image, downscaled to max_width pixels wide (64–1920).

This is the only evidence of what the visuals look like. A block that evaluated cleanly can still be black, blown out or static, so look after writing and before describing anything. It shows whatever render() currently shows — one output, or the 4-up grid.

A hidden tab can't be photographed (its frames are throttled, and a minimized window's canvas has no size); the error says so.

hydra_referenceA

Hydra's transform functions, read live from the running engine — so it lists exactly what this tab's hydra-synth has, including anything added with setFunction.

  • no arguments: names grouped by type, plus the primer (idioms and gotchas)

  • name="modulate": that function's inputs and defaults (also fuzzy: name="repeat")

  • type="combineCoord": every function of one type

Types, and what they chain onto: src start a chain: osc, noise, voronoi, shape, gradient, solid, src, prev coord move pixels: rotate, scale, repeat, kaleid, scroll… color change colour: color, brightness, contrast, hue, colorama, luma… combine mix another source in: add, blend, mult, diff, layer, mask combineCoord warp by another source: modulate, modulateScale, modulateRotate…

Check a name here before using one you are not sure of — an invented function is refused by the dry run anyway, but this is cheaper.

hydra_blockA

Write one named block of Hydra code and run it, leaving every other block playing.

name: letters, digits, _ and -, starting with a letter (e.g. "base", "feedback"). Writing an existing name replaces that block — a hard cut; hydra_crossfade fades. code is ordinary Hydra JavaScript.

DRY RUN FIRST. With validate=true (the default) the code runs in a hidden second Hydra instance before it touches the live canvas. A misspelled function comes back as a ReferenceError; a broken shader comes back as the GPU's own compile log. Both are refused with live_untouched: true. Fix and call again — don't disable validation to get past an error. validate=false exists for code that loads extensions.

Human-written blocks are refused (error human_block) unless take=true, which you pass only when the person playing asked you to take that block over.

Things that trip people up:

  • Each output shows one chain: .out() means .out(o0). Four outputs, o0–o3; render(o1) shows one, render() shows all four.

  • Plain numbers are baked into the shader. For motion, pass a function — () => Math.sin(time) — or an array: [1, 2, 4].fast(0.5).

  • Feedback is reading an output back into itself: src(o0).

  • sum() does not compile in hydra-synth 1.4.0. Use add.

Examples: osc(20, 0.1, 0.8).kaleid(4).out() noise(3).modulate(osc(10), 0.2).color(0.9, 0.3, 1).out(o1) src(o0).scale(1.01).rotate(0.01).blend(osc(8), 0.1).out(o0) shape(4, () => 0.3 + a.fft[0] * 0.4).out(o2)

hydra_crossfadeA

Like hydra_block, but fade from what is on screen to the new code over seconds (0.5–30) instead of cutting — the move for a big change mid-set.

How: the new code is dry-run, then a copy runs into a spare output while the old chain keeps playing; a third output blends old into new and is shown; at the end the visible output switches to the new code and both borrowed outputs are blanked.

Needs: one visible output (not the 4-up grid), and two outputs that no other block draws into or reads — otherwise it refuses with no_spare_outputs and says which are in use. The new code should draw into the visible output (.out() / .out(o0) when o0 is shown). The call returns when the fade has finished; mirrors cut instead of fading.

Example (o0 on screen, o2 and o3 free): hydra_crossfade("base", "voronoi(8, 0.3, 0.2).color(1, 0.4, 0.8).out(o0)", seconds=6)

hydra_dropA

Remove one block from the composition and blank the outputs it drew into (unless another block still draws there) — Hydra keeps showing whatever an output was last given, so forgetting the code alone would leave its picture frozen on screen.

Returns blanked (outputs that went black) and restored (blocks run again because they also draw into one of the same outputs — otherwise the dropped chain, having run last, would stay on screen there). Human-written blocks need take=true. The code is gone afterwards; hydra_save first if you might want it back.

hydra_sketchA

Replace the entire composition with a new sketch: dry-run all of it, hush, then run.

Use this to start a fresh idea, not to add to one — hydra_block adds. Split the sketch into blocks with marker lines so each part can be revised on its own later:

// @block base
osc(30, 0.05, 1.2).out(o0)
// @block warp
src(o0).modulate(noise(2), 0.1).out(o1)
render(o1)

Code with no markers becomes one block called main.

If the document holds any human-written blocks this is refused (human_blocks), because a sketch would erase them. Pass take=true only if the person playing asked for a fresh start.

hydra_defineA

Add a custom transform written in GLSL (Hydra's setFunction), usable in any chain afterwards like a built-in.

type and what the body receives / must return: src _st (vec2 coords) -> vec4 colour coord _st -> vec2 coords color _c0 (vec4 incoming colour) -> vec4 combine _c0, _c1 (two colours) -> vec4 combineCoord _st, _c0 -> vec2 glsl is the function BODY only. inputs are its parameters, in order: [{"name": "amount", "type": "float", "default": 0.5}] (types: float, vec4, sampler2D). For combine types, declare the incoming chain first: {"name": "tex", "type": "vec4"}.

It is compiled inside a throwaway chain before anything goes live, so a GLSL mistake comes back as the compiler's own error. On success it is stored as block fn_<name> at the top of the document (so it is defined again before use when a page reloads) and use shows a call to start from.

Example: hydra_define("stripes", "src", "return vec4(vec3(step(0.5, fract(_st.x * count))), 1.0);", inputs=[{"name": "count", "type": "float", "default": 10}]) then: stripes(20).rotate(0.3).out(o1)

hydra_renderA

Show one output full-screen ("o0", "o1", "o2", "o3") or all four in a grid ("all").

Every output keeps rendering either way, so a chain on o1 can feed o0 while only o0 is visible. This does not change the document — to make the choice permanent, put render(o1) in a block.

hydra_transportA

Set the global clock and canvas size. Pass only what you want to change.

speed multiplies time for everything (1 is normal, 0 freezes motion; 0–20). bpm the tempo arrays step to: [1, 2, 3].fast(1) changes value once per beat. width, height render resolution, set together (16–4096). Larger costs fps, and video out sends this size.

This changes the whole piece, human-written blocks included — say so if someone is playing along.

hydra_sourceA

Load an external image stream into s0–s3, then read it in any chain with src(s0).

kind: "image" target = an http(s) URL. It must allow cross-origin use (CORS) or WebGL cannot read it — the error says so. "video" target = an http(s) URL, same CORS rule; loops muted. "cam" target = camera index ("0"). The browser asks for permission: expect state "pending_permission" until someone at the machine clicks Allow, and check hydra_state rather than assuming. "screen" screen capture. Browsers only allow it from a click inside the page, so a remote call usually cannot start it; the error explains. "clear" release the slot.

Returns state: "live" (with the media's size), "pending_permission", or an error. It waits up to four seconds for the source to actually deliver frames. Images and video are loaded on mirrors too; cameras and screen capture are not (each would prompt).

Then: src(s0).kaleid(4).out(o1)

hydra_audioA

Check and tune audio reactivity (Hydra's a object), or switch it on.

With no arguments: the current a.fft band values, volume and microphone permission — a quick way to see whether sound is getting in at all.

enable=true Hydra only listens if it was started with the microphone, so this reloads the deck page with ?audio=1. The piece is replayed afterwards; the browser asks for the mic, and a.fft reads zeros until someone clicks Allow. Video out has to be started again after the reload. bins number of frequency bands in a.fft (1–64; default 4). smooth 0–1: how slowly band values fall (higher = smoother). cutoff noise floor subtracted before scaling. scale how much raw loudness it takes to reach 1. show true draws the band meters on the canvas while you tune; false hides them.

Use it in code inside a function, or it is read once and frozen: shape(4, () => 0.2 + a.fft[0] * 0.5).out(o2)

hydra_video_outA

Send the primary tab's canvas out of the browser as a native video source: a Syphon server named "Hydra" (macOS). TouchDesigner receives it with a Syphon Spout In TOP. TouchDesigner names Syphon senders App:Server, and the publisher runs as Python, so the sender to pick is "Python:Hydra" — plain "Hydra" matches nothing and leaves the TOP on its checkerboard.

With hydra_out.py started with --ndi, the same frames also go out as an NDI source, which receivers list as " (Hydra)". NDI reaches other machines on the network; ndi_connections in the status says whether anything is receiving it.

action: "start", "stop" or "status". fps: 1–60, the capture rate to request.

Needs out/hydra_out.py running — a separate process with its own Python 3.12, because the Syphon library only supports up to 3.12 (see the README). Start waits two seconds, then returns both ends: page_after_2s sent_fps, dropped — what the tab actually sent out_after_2s fps, syphon_clients — what was published, and whether anything is receiving Report those numbers, not the fps you asked for. Frames are dropped rather than queued when the receiver lags, so a high dropped means lower the resolution (hydra_transport) or the fps.

Chromium tabs only (MediaStreamTrackProcessor). The primary must stay visible: a hidden tab stops producing frames.

hydra_hushA

The panic button: blank every output, clear update(), reset speed to 1, and empty the document — every block, human-written ones included, in every connected tab.

The document is archived first (the path comes back as archived), so nothing is lost, but the screen goes black. To change one part, replace that block instead.

hydra_saveA

Save the current composition — every block, with its author — to the sketch library (hydra-mcp/sketches/.json), plus a 480-px thumbnail of what is on screen.

name: letters, digits, _ and -, up to 60. tags: a few words to find it by later ("feedback", "audio", "slow"). An existing name is refused unless overwrite=true.

hydra_loadA

Replace the composition with a saved sketch — the same dry run, hush and run as hydra_sketch, keeping each block's original author.

Refused if the current document holds human-written blocks, unless take=true. Save the current piece first if it is worth keeping. An unknown name returns the list of saved sketches.

hydra_sketchesA

List saved sketches: name, tags, when saved, block names, and the thumbnail path. query filters by a word in the name or tags.

hydra_share_urlA

A hydra.ojack.xyz link that opens the current piece in the official Hydra editor.

Built here from the document text, in the editor's own ?code= format (base64 of the URI-encoded code; verified by loading such a link and reading the editor back). When the primary is an existing Hydra tab, its own editor text is used instead. Nothing is uploaded or posted to Hydra's gallery — the code travels only inside the link, so very long pieces make very long links.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4.1/5.0

Scored across 19 tools

Disambiguation4/5

Most tools map cleanly to a distinct action in the Hydra workflow, and the descriptions are unusually precise. A few close pairs exist — hydra_sketch vs hydra_load both replace the whole composition, and hydra_block vs hydra_crossfade are write operations differing only in transition — but their purposes are clearly separated in the docs.

Naming Consistency4/5

All tools share the hydra_ prefix and lowercase snake_case, which makes the set feel cohesive. However, the names mix nouns (hydra_state, hydra_document, hydra_reference) with verbs (hydra_drop, hydra_render, hydra_save), so the pattern is predictable but not a strict verb_noun convention.

Tool Count3/5

At 19 tools, the server is on the heavy side of the ideal range. The count is defensible given the broad domain — composition editing, state inspection, rendering, media sources, audio, persistence, and video output — but a few tools could plausibly be consolidated without losing clarity.

Completeness4/5

The core composition lifecycle is well covered: read, create, replace, fade, delete, panic, save, load, list, and share. Minor gaps remain, such as no direct way to delete a saved sketch, reorder blocks, or undo changes, but an agent can accomplish the main Hydra workflows without hitting dead ends.