duck-mcp
With this server you can inspect and command a simulated Microduck robot: read telemetry, drive it, trigger tricks, look around, view camera frames, shove it, and reset the episode.
duck_state– get pose, orientation, body-frame velocity, yaw rate, trunk height, upright/sitting status, active policy, velocity command, and ball position.duck_drive– set walking velocity (vx/vy/wz), optionally with a duration after which it stops and returns state.duck_stop– zero velocity intents and return to standing.duck_trick– execute episodic behaviors: sit, stand, ground_pick, kick_left/right, roulade.duck_look– command head gaze (yaw/pitch/roll/neck pitch) through the balance policy.duck_camera– render camera frames from follow/front/side/top views at a chosen distance.duck_push– shove the duck to test push recovery.duck_reset– reset to origin/spawn (destructive, discards episode).The README also describes higher-level capabilities: chained sequences, behavior machines, speech/chirps/emotes, training tools, and autonomous match filming.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@duck-mcpMake the duck do a forward roll and show me the camera view."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
microduck-mcp 🦆
Drive the Pollen Robotics Microduck from any MCP client — Claude Code, Claude Desktop, or your own agent. An AI gets tools to walk the duck around, trigger tricks, shove it, and see it through rendered camera frames.
Today it drives the simulated duck (CPU MuJoCo running the official
pretrained ONNX policies from pollen-robotics/microduck).
The control plane is intents-only — velocities, tricks, gaze — mirroring the
real robot's robotd contract, so a hardware backend can slot in behind the
same tools when your duck arrives.
Out for a walk | Mid-roulade | Waiting for orders |
|
|
|
All frames rendered by the duck_camera tool — this is literally what the AI
sees while driving.
Architecture
MCP client (Claude, ...) duck CLI (humans / scripts) browser: AX debug page
│ stdio │ │ http :8400
▼ ▼ ▼
duck-mcp ────────────► Unix socket, JSON lines ◄──── built-in web UI
│
▼
duck-sim (50 Hz MuJoCo loop,
ONNX policy hot-swapping via
microduck_rl's PolicyInference)Design rationale (tools vs resources, structured output, error semantics) is documented in docs/mcp-design-notes.md.
Related MCP server: MuJoCo MCP Server
Setup
Needs clones of the two official repos (for scenes/policy-runner and the shipped ONNX policies), plus uv:
git clone https://github.com/pollen-robotics/microduck
git clone https://github.com/pollen-robotics/microduck_rl
git clone https://github.com/aj-dev-smith/microduck-mcp
cd microduck-mcp && uv syncRun
Start the sim server (defaults assume the three repos are siblings):
uv run duck-sim --rl-repo ../microduck_rl --policies ../microduck/policiesHeadless by default. To watch in the MuJoCo viewer (macOS needs mjpython):
uv run mjpython -m microduck_mcp.sim_server --viewer \
--rl-repo ../microduck_rl --policies ../microduck/policiesPoke it from a shell:
uv run duck state
uv run duck drive 0.2 # walk forward at 0.2 m/s
uv run duck trick roulade # forward roll
uv run duck cam follow # render a frame, prints the PNG path
uv run duck push # shove it, watch it recover
uv run duck say "hello!" # speak: audio host-side, beak in the sim
uv run duck chirp inquire # nonverbal: one call from its own voice bank
uv run duck emote head_tilt # an authored gesture, played in the simRegister the MCP server with Claude Code:
claude mcp add duck -- uv --directory /path/to/microduck-mcp run duck-mcpMCP tools
All state-returning tools emit typed structured output (DuckState schema,
units documented per field); every mutating tool returns post-action state so
the agent rarely needs a follow-up poll.
Tool | What it does |
| Position, orientation, body-frame velocity, active policy, upright?, plus |
| Velocity intent; with |
| Zero commands → standing policy |
|
|
| Point the head (it's a command to the policy, not a servo write) — also pans the head camera |
| Chain drive/stop/trick/look steps server-side — motion flows through transitions with no client round-trips (arcs, an approach, kick + celebration as one call) |
| Rendered frame: |
| Shove the trunk; tests push recovery |
| Load/arm/hot-reload a behavior machine — autonomy between the agent's decisions (see below) |
| Beak opening 0..1 — the real robot's |
| Speak as the duck: renders the duck's voice, plays it on the host's speakers, lip-syncs the beak live in the sim (see below) |
| One call from the duck's own voice bank — |
| Play an authored gesture — |
| Task ids the GPU box can train — the live |
| Train a new behavior: launches a run in its own tmux session on the GPU box (see below). |
| List training sessions; for one, the wandb URL, latest iteration/reward/ETA, whether it's alive, and a diagnosis if it died |
| Ctrl-C the trainer, then kill the session ( |
| The brains, inspectable and mutable on a live sim: |
| Back to origin, default stance ( |
Honest sensing (fake mediad)
The sim exposes two views of the ball. ball_position_m is God-mode ground
truth. ball_seen is what the robot could actually know: an orange-blob
detector runs on the duck's own 320×240 head-camera render at 5 Hz and
publishes {visible, distance_m, bearing_deg, elevation_deg, age_s} — the
same derived features, not frames contract the real Microduck's mediad
service uses (microduck docs, architecture §2.4). Distance comes from the
blob's solid angle (mean error ~6% out to 1.4 m); a ball behind the duck is
honestly invisible, which makes searching for it a real behavior. The
detector also derives speed_mps by differencing its own world-frame
estimate across ticks — the robot's kinematics cancel its own motion, so a
parked ball reads ~0 even mid-stride while a kicked one reads ~1 m/s, which
is how a machine can decline to kick a rolling ball. Prefer
ball_seen when you want sim work to transfer to hardware.
On the pitch scene the same 5 Hz frame also feeds a goal detector
(goal_seen): the white goal frame is separated from the equally-white
pitch lines and clouds purely by ray elevation computed from the robot's own
kinematics — sky can only exist above the true horizon, painted lines on
the ground sit well below it anywhere on the pitch, and the crossbar (hung
at almost exactly camera height) lives in the narrow band between. Grazing
far-off lines that do reach the band arrive one pixel per image column;
posts stack several, and a dense-column filter drops the difference. Range
comes from the mouth's angular width. Because the goal never moves, a
sighting plus own odometry keeps est_bearing_deg/est_distance_m alive
while the head is tilted down at the ball — which is how the duck can aim a
kick at a goal it currently cannot see.
The behavior machine
The agent doesn't have to drive every step. A machine — TOML source, see
machines/soccer.toml — binds nodes to deterministic
behaviors (search_ball, approach_ball, kick, celebrate, drive,
idle) executed at 50 Hz on the sim thread, with transitions guarded by
expressions over the sensed digest only: ball_seen.*, upright,
elapsed_s. The
guard grammar is a strict whitelist (paths, literals, comparisons,
and/or/not — validated at load, nothing else parses), and ground-truth ball
position is not in the vocabulary: an armed machine plays fair by
construction. Edit the file while it runs; duck machine reload hot-swaps it.
Transitions stream into the AX page's command feed tagged machine.
uv run duck machine load machines/soccer.toml
uv run duck machine arm # duck finds the ball, lines up, kicks — alonemachines/striker.toml is the match-play variant
for the pitch scene: approach_ball runs with aim = true, so before
attacking the ball the duck walks a detour onto the ball→goal line of
fire (steered by goal_seen's dead-reckoned bearing, trunk offset ~35°
left of the line because that is where kick_right actually sends the
ball), kicks only with the remembered goal inside the kick's cone, then
stands and watches — it celebrates only when the referee calls the goal,
and chases the rebound when it doesn't. On the pitch the ball kicks off a
metre from the goal line, where the mouth subtends ±11° and aiming is the
difference between scoring and a throw-in.
Wake nodes: the machine wakes the agent
The interrupt line runs the other way too. A node declaring wake = "reason"
parks a wake pack on entry — reason, a snapshot of the sensed digest, the
recent event tail — and a blocked duck machine wait (or duck machine arm --block-s 300, arm-and-listen in one call) returns it. The agent's loop
becomes: block → wake into context → act (force a node, reload edited
source, speak) → block again.
A robot can't freeze like a paused game while the mind thinks, so the wake
node's own behavior is the holding pattern, and every wake node must declare
its no-answer default in source: either a transition guarded on elapsed_s
(the deadline — the machine answers itself and the late listener finds that
answer in the pack's resolved field) or an explicit
wake_hold = "why parking here forever is safe". Autonomous-first,
mind-optional, by construction. machines/resident.toml
is the idle-life machine built around this; striker.toml wakes on won
(come celebrate) and down (no stand-up policy — bring duck_reset).
Speaking nodes: the machine says what it is doing
A node may also declare say = "...". Entering it forwards the line through
the sim's say annotation verb — the same one duck say uses — so a line the
machine decided to say and one a person asked for are indistinguishable on the
event feed, and the server speaks it host-side if this session has a voice
(duck-sim --no-voice to keep it quiet, --voice-bank for the chirps). It is
an annotation in the same sense wake is: the guards, the behaviors and the
physics play out identically without it, and a server too old to know the key
simply ignores it. striker.toml speaks on celebrate and won — both
reachable only through the referee's call, so the celebration line is earned
by construction. A speaking node may add say_mood = "excited" — a separate
key rather than a table-valued say, so a server too old to know it speaks
the line neutral instead of not at all (striker.toml's celebrate is the
one line in the repo that carries one). A node may carry emote = "..." the
same way, and the two fire together: mouth to say, body to emote (see
Emotes).
The design lineage: deterministic behaviors under guarded transitions, machine source in a git repo, hot-swapped live, and blocking wake delivery — the machine decides what deserves a mind's attention — all patterns borrowed from an MCP instrument built for playing Ocarina of Time, ported from Hyrule to a robot.
Filming a match
duck film shoots an autonomous match and cuts it to an mp4:
uv run duck film # -> ./duck_match.mp4
uv run duck film -o goal.mp4 --takes 3 --select goalEvery frame carries the four things worth showing at once: a broadcast camera
tracking duck and ball (it swings west for the celebration so the goal frame
stops blocking the shot), the duck cam picture-in-picture — the same 70°
head-camera view the detectors run on — a sensed-state HUD reading
ball_seen.* and goal_seen.est_* straight out of the machine digest, and a
control-surface feed of the real events: the MCP calls that armed the
machine, each transition, and the guard expression that fired it. What the
duck knows and why it just did that, on screen, frame by frame.
It runs cold-start takes from known-good spawns and keeps the first that
scored and landed the celebration (--select goal accepts any goal); takes
that never score are discarded, and the goal moment cold-opens the cut so it
becomes the timeline thumbnail. --keep-takes keeps the rushes,
--cap-seconds bounds a take, --machine films a machine other than
striker.toml.
The soundtrack
The film has a voice, and it is cut from the take's own event timeline on
the same sim clock the frames are sampled on — not scored to the picture by
ear. The duck speaks a line as the machine arms, chirps on the kick, and the
referee's goal — only the referee's goal — gets the wheee, with the
celebration line waiting behind it. That last rule is the one this film has,
so it is a test rather than a habit: no wheee on the arm, on a kick, on any
other node, and not a second one when the referee's latch stays lit. There is
no music bed and no choir; every sound is the duck's own voice or its own
voice bank.
The lines are rendered before the shoot, which buys the lip-sync: the same
trajectory that places the audio drives the beak on camera and the meter in
the HUD, so picture and track come from one render. --line-arm and
--line-goal rewrite the script (an empty string deletes a line),
--voice-bank supplies the bank — without one the shoot renders its own with
the sounds crate beside --policies — and --no-audio films silently.
Sound is an enhancement, never a new way for a shoot to fail: no cargo, no crate, no TTS, a mux that errors — each is a note on stderr and a quieter film, and the goal you just filmed still gets cut.
Two things to know. ffmpeg must be on PATH (brew install ffmpeg, or
--ffmpeg /path/to/it) — frames are piped into it raw, and it is deliberately
not a Python dependency; the check runs before the model loads, so a missing
encoder costs a second rather than a shoot. And unlike every other
subcommand, film does not talk to a running duck-sim: filming wants raw
frame buffers, per-take resets and chosen spawns, none of which are socket
intents, so it boots its own headless sim (--rl-repo/--policies, same
defaults as duck-sim) and leaves any sim you have running alone.
The voice (duck say)
The duck speaks, and its beak moves while it does:
uv run mjpython -m microduck_mcp.sim_server --viewer # watchable sim
uv run duck say "hello A J — watch the beak"
uv run duck say "now with chirps" --voice-bank bank/The voice is built to be honestly synthetic — an AI in a duck, not a person
in a duck suit. Text goes through TTS (macOS say for now; the TTS stage is
a one-function boundary meant for a phoneme-timed engine later), gets pitched
~2 semitones up, and is run through the modulation parameters of the duck's
own synthesized personality — the vibrato and amplitude-wobble rates that
seed 42 of the real robot's voice synth uses for its calls. Then chirp
grains are blended into the stressed syllables: a loudness envelope finds
the syllable nuclei with the sharpest attack, and a 90 ms grain of a real
voice-bank chirp rides each one, shaped by the word's own envelope — chirps
as an accent living in the words, not punctuation between them.
The beak lip-sync comes from the same envelope: fast attack, slower
release (a beak snaps open and eases shut), streamed to the sim as mouth
intents (0 closed → 1 open, the real robot's robot.mouth semantics) against
the audio playback clock with absolute deadlines, so the two cannot drift.
The shipped MJCF has no mouth joint, so at load time the sim rebuilds the
model with the soft mouth plate on a mocap body — no new degrees of freedom,
the walk policy sees a byte-identical world — and hinges it from the head's
own kinematics every tick.
The chirp bank is rendered by the real robot's voice code
(pollen-robotics/microduck's
sounds crate):
cargo run -p sounds -- render chirp bank/chirp.wav --seed 42No bank? The duck still talks, just chirpless (with a note). --audio-only
skips the sim, --wav-out keeps the render, and duck mouth 0.6 holds an
expression by hand. Requires say, ffmpeg and afplay on the host —
speech is rendered and played host-side; the sim gets only the beak.
Moods: same duck, different weather
uv run duck say "I found the ball" --mood excited --voice-bank bank/
uv run duck say "the ball went behind the goal" --mood sad--mood neutral | excited | sad | alarmed | smug (and mood= on duck_say).
The recipe above is the duck's identity and it does not move; a mood only
leans on knobs the pipeline already has — pitch, tempo, the two modulation
depths, which bank tag the grains are cut from and how loud, how many
syllables carry one, and how fast the beak shuts. A sad duck is this duck,
slower and lower and cooing over coo*.wav grains; an alarmed one is not
higher but faster and shakier, over alarm*.wav. neutral is the absence of
overrides and renders exactly what it always did. The whole table is eight
named fields per mood in voice.MOODS — retuning by ear is meant to be one
line.
The nonverbal voice (duck chirp)
Words are the borrowed part. The bank the chirp grains come from holds the
duck's own vocabulary — alarm, greet, inquire, peck, chirp, coo,
wheee — and duck chirp <tag> plays one straight, beak driven by that call's
own envelope, no TTS and no ffmpeg in the path:
uv run duck chirp inquire --voice-bank bank/
uv run duck chirp chirp --variant 1 # sorted, so a tag is the same wavOne tag is not the caller's to spend. wheee is the goal celebration, and the
server refuses it unless the referee has a goal on the board this episode —
no goal, no scene with a goal in it, no wheee, whoever is holding the socket.
The film has had that rule since it had sound; here it stops being the film's
discipline and becomes the duck's.
Emotes: the duck's body language
The third channel has no sound in it at all. An emote is a short authored
gesture — keyframed head pose plus beak, optionally a bank call over the top —
living as TOML in emotes/, beside the machines that trigger it:
[emote]
name = "head_tilt"
sound = "inquire"
[[key]]
t = 0.0
[[key]] # channels: neck_pitch, head_pitch, head_yaw,
t = 0.4 # head_roll (radians), mouth (0..1) — omit one and
head_roll = 0.30 # it carries the previous key's value
ease = "smooth" # how to travel INTO this key: smooth | linear | holduv run duck emote --list # what this server has, and whether it parses
uv run duck emote droopFour ship: head_tilt (curiosity), nod (yes), perk_up (alert), droop
(dejected). Signs follow the rest of the codebase — positive pitch looks
down — and values are clamped to the policy's head limits when applied, so a
file can be wrong about taste but not about the neck. The gesture renders to
50 Hz channel arrays and is played by the sim against its own clock, writing
head_offset through the same gaze command duck_look uses (the balance
policy compensates) and the mouth plate the voice drives. Edit a file and the
next trigger plays the edit — mtime-cached, no reload verb.
The head belongs to somebody, which is the whole design: say beats emote
for the beak, emote beats the behavior for the head, and an externally
triggered gesture is refused outright while an armed machine is in
approach_ball or kick (both steer by the head camera; the kick policy fed a
bowed head does not swing at all). A gesture arriving mid-gesture is refused
rather than restarted. Every start and every refusal lands on the event feed,
so the film and the AX page get expressiveness for free.
Emoting nodes
A node may declare emote = "name" alongside say = "...", and both fire on
entry — the mouth says the line, the body plays the gesture. A machine's own
trigger bypasses the head-ownership refusal, because the author already made
that call in source. The grammar validates that the name is a string and
nothing more: naming a gesture the server does not have is a lint warning at
load and a note at fire time, never a rejection, so a machine stays
hot-reloadable onto a server whose emotes/ differs.
machines/resident.toml startles with perk_up on
ball_spotted — the duck visibly notices the ball while the wake pack goes
out to the mind.
Desktop pet (duck-pet)
duck-pet is a macOS overlay that puts the duck on the top edge of your
Dock, where it walks around on its own while you work.
Nothing about it is animated. The app ships no sprites, no keyframes and
no tweens: every frame is a physics step of the same MuJoCo sim, driven by the
same shipped ONNX walk policy, served through the same sim.submit queue as
duck_camera. The sim's ground plane is the Dock's top edge — the camera is
orthographic, so metres-per-pixel is constant at every depth and the mapping is
exact rather than exact-near-the-middle. The window tracks base_x, so when
the controller stumbles the window stops and the duck face-plants on the Dock.
Two invisible walls stand at the mapped screen edges; it physically cannot walk
off. Stop the daemon and the duck freezes mid-step, tinted cool — proof of life,
the same way an unplugged robot is proof of life.
uv run duck pet up # daemon + machine + overlay, detached
uv run duck pet status # both halves alive? which node?
uv run duck pet down # kill both, sweep strays, rm the socketup starts the pair in its own session, so the duck outlives the terminal
that summoned it; pidfiles and per-half logs land in ~/.microduck/pet/.
down also sweeps the feed port and the overlay's process names for strays
from launches it never made — the cure for the "trail of ghost ducks" a night
of manual restarts leaves behind. The launcher deliberately parks the pet on
its own socket and port 8410 so it can never seize a resident duck's default
socket. The three verbs are sugar over the manual recipe, which still works:
uv run duck-sim --scene desktop # headless; --viewer has no offscreen GL
uv run duck machine load machines/pet.toml && uv run duck machine arm
uv run duck-pet # both sides default to port 8400machines/pet.toml is the resident pattern aimed at a
strip of screen: stroll, amble, pause, glance around, turn at the walls, doze
off, and wake nodes for the two states a duck cannot talk itself out of —
fallen (try duck_trick stand) and stuck (a shove would help). stuck
escalates rather than nagging: it tries a leg away from the wall itself, then
parks in a silent wedged node that wakes nobody and retries every ten
minutes, because ambient software gets one chance to be interesting before it
is an interruption.
Because the overlay is a viewer onto the ordinary daemon, Claude
inhabitation needs no new protocol at all: point the MCP server at the same
sim, block on duck machine wait, and every duck_drive / duck_trick /
duck_say plays out on the Dock in front of you. The pet daemon must own the
default socket for that (a --socket instance is invisible to the MCP
tools). Drag the duck with the mouse and it becomes a real duck_push —
the controller staggers, and recovers or falls for real. Everywhere else the
window is click-through, so the Dock underneath still works.
Roughly 18 fps of picture over 50 Hz of physics at the shipped 512 px ×2
supersampled frame; the ask drops to 1 fps on display sleep, screen lock and
occlusion. duck pet state / config / frame / world inspect the same
surface from the CLI without the GUI.
Training new behaviors
The tools above drive a duck that already knows things. These four grow it a
new one: the agent trains a policy on a GPU box, reads the run, and ends up
with the wandb path that microduck_rl's scripts/export.py turns into the
ONNX this sim hot-swaps.
uv run duck train tasks # the live registry
uv run duck train start Mjlab-StandUp-Flat-MicroDuck --smoke # ALWAYS first
uv run duck train start Mjlab-StandUp-Flat-MicroDuck --num-envs 4096
uv run duck train status duck-train-standup-flat-microduck
uv run duck train stop duck-train-standup-flat-microduckEverything runs over ssh on a box named by $DUCK_TRAIN_HOST (default
duck-4090-wsl, an alias that lands directly in Linux). The scripts these
tools build travel on stdin to bash -l -s — never as a quoted ssh
argument — so no remote shell ever re-parses them; the tmux session likewise
runs a ~/logs/<session>.sh written on the box rather than an argument to
tmux new-session. That is not fastidiousness: a training command is
cd && uv run train … | tee log nested two shells deep, and the failure mode
of getting it wrong is finding out twelve hours later.
What the tools enforce, each because of a way this has actually gone wrong:
One session per task, named
duck-train-<slug>. Starting a run for a task that already has one is refused, never replaced.--video True, never a bare--video. mjlab configures tyro withFlagConversionOff, so booleans take a value; the bare flag is a parse error that killed a 12-hour StandUp run at second one.Per-run logs at
~/logs/train_<slug>_<timestamp>.log,tee'd live underset -o pipefailso the recorded exit code is the trainer's and nottee's, and so a re-run never clobbers the previous run's evidence.smoke=Trueis 64 envs / 5 iterations, permicroduck_rl/AGENTS.md: minutes and cents, and it catches ~95% of config errors before you spend a night of GPU time on them.Status is read-only and safe to point at a live run. It parses rsl_rl's own output — iteration, mean reward, episode length, ETA — plus the wandb run path, and diagnoses the known deaths (CLI parse error, full disk, CUDA OOM, traceback).
Stop is honest about what survives: the trainer has no interrupt handler, so a Ctrl-C keeps the last periodic checkpoint (every 50 iterations by default) and nothing since.
One caveat the tools report rather than hide: if the box's WSL distro does not
run systemd as PID 1, WSL tears the distro down seconds after the last
session ends and takes detached tmux with it. duck_train_start checks PID 1
and returns a warning when a launch that "worked" is not going to survive.
Duck cam: watching a run live
scripts/box/launch_viewer.sh (run on the box; see its header) starts mjlab's
viser viewer in a duck-viewer tmux session beside training: a browser
3D scene where the duck runs the newest checkpoint of the newest run, with a
checkpoint panel that hot-loads later ones as training writes them. Tunnel it
with ssh -f -N -L 8080:localhost:8080 duck-4090-wsl and open
http://localhost:8080. Its companion play_viser_patched.py wraps play
to skip command-GUI sliders whose degenerate ranges crash viser on some tasks
(an mjlab bug; the sim itself is fine).
AX debug page
duck-sim also serves an Agent Experience debug page at
http://127.0.0.1:8400 (--web PORT, --web 0 to disable): a live feed of
every command hitting the control socket — tagged by client (mcp, cli,
web) — next to an auto-refreshing camera view and a state dashboard. Open it
beside the MuJoCo viewer to watch what the agent is doing and what it can
see, in real time. Plain stdlib HTTP + one HTML file; all rendering still
happens on the sim thread via the same intent queue as every other client.
Notes
The sim enables the ball's rolling friction at model load (the shipped spec declares it but leaves the geom at
condim=3, where it never applies — a kicked ball glided 27 m and never stopped). With it, a kick runs ~1-2 m and stops; an accidental toe-poke dies in centimeters, which is what makes dribbling and retrying possible at all.The sim server executes all MuJoCo calls on one thread; socket clients only enqueue intents. Multiple clients are fine (MCP + CLI simultaneously).
Policies hot-swap behind the shared 61-dim observation contract exactly as on the robot: driving engages walking, zero command returns to standing, episodic tricks time out back to standing.
Camera rendering is offscreen (no window needed); in
--viewermode on macOS, offscreen rendering may be unavailable — run headless if you need frames.Falls are recoverable without a reset when the
sitstandslot holds a getup policy:duck_trick standfires it from the floor, the resident machine's fall reflex spends two honest attempts before waking anyone, andduck_policyswaps in a better brain the moment one finishes training. (Pollen ships none — the first ones here were trained from scratch viaMjlab-StandUp-*and hot-swapped in live.)
Roadmap
Real-robot backend speaking the daemon's WebSocket API (see
microduckdocsdesign/architecture.md§5.3) behind the same toolsBody-pose intents (crouch/lean while standing)
Optional StandUp policy slot so falls are recoverable without
duck_reset— shipped asduck_policylive hot-swap + the resident machine's try-twice fall reflex, running a self-trained getup brainClose the training loop: a
duck_train_exportthat takes a finished run'swandb_run_pathstraight to an ONNX in the sim's policy dir, so train → export → hot-swap needs no human hands
License
Apache-2.0. Built on microduck and microduck_rl by Pollen Robotics, both Apache-2.0.
Available Tools
8 toolsduck_cameraDuck cameraARead-only
Render a camera frame of the sim. Views: 'follow' (behind the duck),
'front' (facing it), 'side', 'top'. distance in meters (0.4 close-up
to ~1.5 wide). Pair with duck_state for pose numbers.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | follow | |
| distance | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint=true, so the no-side-effect profile is covered. The description adds useful context about views and distance but does not disclose additional behavioral details such as output format or whether the frame is static or animated. There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long and every clause adds distinct, actionable information: what the tool does, valid view values, distance semantics, and a usage hint. There is no filler or repetition of schema defaults.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter, zero-required tool with a readOnly annotation and no output schema, the description covers the key invocation details: valid views, distance range, and a state-pairing tip. The return format is not explicitly described, but 'render a camera frame' makes the output type inferable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only parameter names and defaults, with 0% description coverage and no enums. The description fully compensates by defining each view ('follow' behind the duck, 'front' facing it, 'side', 'top') and giving distance units and a usable range of 0.4 to ~1.5 meters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action and object: 'Render a camera frame of the sim.' The view list and distance range further clarify exactly what kind of camera output is produced. This clearly distinguishes the tool from siblings like duck_drive, duck_push, and duck_state, which are action/state tools rather than rendering tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives an explicit pairing recommendation: 'Pair with duck_state for pose numbers.' It does not explicitly state when not to use it or name alternatives, but for a simple visualization tool the guidance is clear enough for an agent to select it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_driveDrive the duckAIdempotent
Set the walking velocity intent. vx: forward m/s (max ±0.3; the policy tracks ~half the commanded speed, so command 0.25+ for a brisk walk), vy: leftward m/s (max ±0.2), wz: counterclockwise yaw rate rad/s (max ±1.5). Nonzero engages the walking policy; all-zero hands back to standing.
With duration_s (max 10): drive for that long, then stop and return the resulting state — one call instead of drive/poll/stop. Without it the intent persists until changed: the robot keeps walking between your tool calls, and the sim runs in real time, so returned state is already slightly stale when you read it.
| Name | Required | Description | Default |
|---|---|---|---|
| vx | Yes | ||
| vy | No | ||
| wz | No | ||
| duration_s | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavioral context beyond annotations: intents persist across calls, the sim runs in real time, returned state is already slightly stale, nonzero values engage walking, and all-zero returns to standing. It also discloses policy tracking behavior and commanded-speed scaling. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense paragraphs with no filler. The opening sentence states the core purpose, parameter details are grouped logically, and the duration_s alternative is explained in a dedicated paragraph. Every sentence adds operational value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter tool with no schema descriptions, the description covers all parameters, limits, behavioral persistence, and the optional duration mode. The output schema exists, so return values do not need to be described. Nothing essential is missing for an agent to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the full burden for parameter meaning. It explains vx, vy, wz with units, sign conventions, and max magnitudes, plus duration_s semantics and the all-zero special case. Every parameter is given actionable meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Set the walking velocity intent.' The description clearly distinguishes this from siblings by explaining when velocity intents engage the walking policy and when they hand back to standing, and it contrasts the one-call duration mode with drive/poll/stop.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly describes the two usage modes: with duration_s for a self-terminating drive, and without it for persistent intent. It also tells the agent when to use the shorter one-call form instead of drive/poll/stop, which routes to the relevant alternative behavior.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_lookPoint the headAIdempotent
Point the head (radians; caps ~±1.4 yaw, ±1.1 pitch, ±0.31 roll). This is a command to the balance policy, not a servo write — the body compensates. All zeros returns the head to neutral. The gaze intent is sticky — it holds between tool calls until changed.
| Name | Required | Description | Default |
|---|---|---|---|
| head_yaw | No | ||
| head_roll | No | ||
| head_pitch | No | ||
| neck_pitch | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It adds substantial behavior beyond annotations: the command is sticky and persists between calls, all zeros returns to neutral, and the body compensates rather than directly moving a servo. These details meaningfully shape how an agent should invoke and reason about the tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact—three sentences, each carrying distinct value: units/caps, policy behavior, and persistent-state behavior. It is front-loaded and free of filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the main purpose and key behavioral traits, and an output schema exists so return values need not be described. Still, neck_pitch is absent, direction conventions are unclear, and interaction with sibling tools is not addressed, so an agent is left with material gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description compensates by providing units and approximate caps for yaw, pitch, and roll. However, neck_pitch is never mentioned, and sign/direction conventions are not explained, leaving an important parameter underspecified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool points the head and gives units and range caps, which is specific and useful. It does not explicitly differentiate from sibling tools like duck_camera or duck_drive, though the resource ('head') is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives important context: it is a command to the balance policy, not a servo write, and the body compensates. However, it does not name alternatives or give explicit when-to-use vs. when-not-to-use guidance relative to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_pushShove the duckA
Shove the duck: sets trunk velocity to magnitude m/s (max 2.0) in a
world-frame direction (random if angle_deg omitted). Tests push recovery.
| Name | Required | Description | Default |
|---|---|---|---|
| angle_deg | No | ||
| magnitude | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate a non-readonly, non-idempotent mutation. The description adds meaningful behavioral detail: velocity is in m/s with a max of 2.0, direction is world-frame, and angle_deg is randomly chosen when omitted. There is no contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single compact sentence that front-loads the action, then covers the mechanism, constraints, and purpose. Every clause adds useful information with no repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low parameter count and existing annotations, the description covers the core behavior, bounds, and purpose. The output schema exists, so return value explanation is unnecessary. It could be slightly more complete with angle convention details, but it is sufficient for calling correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry parameter meaning. It does: magnitude is velocity in m/s capped at 2.0, and angle_deg defines a world-frame direction that becomes random when omitted. Minor ambiguity remains about the reference axis for angle_deg, so it is not a perfect 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the operation: 'Shove the duck' sets trunk velocity, naming the resource (duck/trunk), the action (set velocity), and the parameterized behavior. It does not explicitly distinguish itself from siblings such as duck_drive or duck_trick, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The use case is implied by 'Tests push recovery,' which tells the agent this is for simulating a push and checking recovery. However, there is no explicit when-to-use versus alternatives like duck_drive or duck_trick, and no exclusions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_resetReset the simADestructiveIdempotent
Reset the sim: duck back to the origin in its default standing pose, ball back to its spawn. Discards the current episode — the escape hatch after a fall (there is no stand-up policy yet).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already signal destructive and idempotent behavior. The description goes beyond them by revealing exactly what changes: the duck returns to origin in its standing pose, the ball returns to spawn, and the current episode is discarded. This is valuable behavioral context for a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences: the first states the reset outcome, the second explains the trigger and rationale. Every clause adds value, with the core action front-loaded and no redundant detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter reset with annotations and an output schema, the description fully covers what happens, when to use it, and why it is the fallback. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has 0 parameters and 0 required inputs, so the description carries no parameter-semantics burden. The schema already fully covers the empty parameter set, and the description naturally communicates a parameterless call.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Reset the sim') and specifies the exact resulting state: 'duck back to the origin in its default standing pose, ball back to its spawn'. This makes the tool's purpose concrete and clearly distinct from sibling action tools like duck_drive or duck_trick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly positions this as the 'escape hatch after a fall' and explains the need with 'there is no stand-up policy yet'. That gives clear trigger conditions. It does not explicitly name an alternative, but no sibling tool provides a reset action, so the context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_stateDuck telemetryARead-only
Current robot state: pose, body-frame velocity, active policy, whether it is upright/sitting/mid-trick, and the ball position. Cheap — poll freely.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so no side effects are expected. The description goes beyond annotations by adding that the tool is 'cheap' and safe to poll freely, which signals performance characteristics. It also clarifies that the state includes posture modes like upright/sitting/mid-trick, giving useful behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, compact sentence that front-loads the core purpose, lists concrete return fields, and ends with actionable usage guidance. No words are wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters, a readOnly annotation, and an existing output schema, the description provides all necessary context. It tells the agent what the tool returns, that it is low-cost, and implicitly that it should be used for telemetry rather than actions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing to document. The description correctly omits parameter details; the baseline of 4 applies because no parameter compensation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as a state-read operation for the robot, listing the specific fields it returns (pose, velocity, active policy, posture status, ball position). This distinguishes it from the sibling action tools like duck_drive and duck_trick, which perform movements rather than report status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Cheap — poll freely' provides explicit guidance that this tool is safe to call frequently, making its usage context clear. It does not explicitly name alternatives or exclusions, but the sibling tools are all action-oriented, so the intended use case of polling status is well implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_stopStopAIdempotent
Zero all velocity intents — the duck stops walking and stands.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already signal mutability (readOnlyHint=false), idempotency (idempotentHint=true), and non-destructiveness. The description adds a useful behavioral detail—all velocity intents are zeroed and the duck stands—but does not discuss side effects like interactions with duck_trick or state persistence.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence immediately conveys the core effect and an accessible metaphor. There is no filler or redundant restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless command with an output schema and simple behavior, the description captures everything an agent needs: it knows the call stops the duck and stands it. No prerequisites or additional context are required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there are no parameter semantics to clarify; the baseline of 4 for a parameterless tool applies. The description imposes no hidden arguments or prerequisites.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a precise action—'Zero all velocity intents'—and adds an observable effect ('the duck stops walking and stands'). This clearly distinguishes it from movement-producing siblings like duck_drive and duck_push.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implicit from the action description: call this to halt the duck. However, it does not explicitly state when to use this tool over duck_reset, duck_drive, or other siblings, and no alternative is named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duck_trickDo a trickA
Trigger a trick: 'sit', 'stand', 'ground_pick' (touch beak to floor), 'kick_left'/'kick_right' (stages the ball at that foot, then kicks), or 'roulade' (forward roll — NOTE: usually ends with the duck down, since no stand-up policy ships yet; follow with duck_reset). Episodic tricks hand control back to standing automatically after a few seconds.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| rpy_deg | Yes | Trunk orientation [roll, pitch, yaw], degrees |
| sitting | Yes | |
| upright | Yes | False once tilted past ~45 deg. There is no self-recovery policy: if the duck falls, use duck_reset. |
| vel_cmd | Yes | Current sticky velocity intent [vx, vy, wz] |
| behavior | Yes | Episodic trick currently running, else null |
| position_m | Yes | Trunk world position [x, y, z], meters |
| sim_time_s | Yes | Sim clock, seconds. The sim runs in real time; this snapshot is stale on arrival. |
| ground_pick | Yes | |
| vel_body_mps | Yes | |
| yaw_rate_rps | Yes | Yaw rate, rad/s, counterclockwise positive |
| active_policy | Yes | Which ONNX policy is driving: standing, walking, sit, ground_pick, kick_left/right, roulade |
| ball_position_m | No | Ball world position [x, y, z], meters (ball scene only) |
| trunk_height_mm | Yes | Trunk height above floor, mm (~116 standing) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses important physical side effects beyond the annotations, including that ground_pick touches the beak to the floor, kicks stage the ball at the indicated foot first, and roulade usually leaves the duck down because no stand-up policy ships yet. It also reveals that episodic tricks automatically hand control back to standing after a few seconds, which is exactly the kind of behavioral context an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core verb and immediately lists options in a scannable inline list. Every clause earns its place: the parentheticals clarify physical behavior, and the trailing note explains an important edge case rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has one required parameter and an output schema, so the description need not document return values. It covers the accepted value set, per-value semantics, post-trick state, a required follow-up action, and automatic control handback, leaving no practical gap for an agent deciding whether and how to invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage and only a bare string 'name' in the schema, the description carries full responsibility for parameter meaning. It compensates completely by listing every accepted value and explaining the effect of each, including the roulade/duck_reset caveat.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Trigger a trick' and enumerates every valid trick value ('sit', 'stand', 'ground_pick', 'kick_left'/'kick_right', 'roulade'), making the operation specific and unambiguous. This clearly separates it from the sibling tools, which are state, drive, push, stop, look, camera, and reset operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended trigger action is clear, and the description gives sequencing advice ('follow with duck_reset' after roulade) plus automatic return-to-standing behavior. However, it never explicitly states when to prefer this tool over sibling alternatives such as duck_drive or duck_push, so usage guidance is mostly implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
8 tool updates
v0.1.0- First observed
duck_camera - First observed
duck_drive - First observed
duck_look - First observed
duck_push - First observed
duck_reset - First observed
duck_state - First observed
duck_stop - First observed
duck_trick
TDQS
Each tool targets a distinct aspect of the duck robot: tricks, state reading, locomotion, perturbation, stopping, head gaze, camera rendering, and reset. Even though duck_stop overlaps slightly with duck_drive(all-zero), the descriptions clearly separate an explicit stop from a velocity command.
All tools share the duck_ prefix and use lowercase snake_case, which is easy to follow. However, the suffixes mix verbs (trick, push, reset) with nouns (state, camera), so the naming is mostly consistent but not perfectly uniform.
Eight tools is well within the ideal range for a robot-control MCP server. Each tool covers a necessary capability: actuation, sensing, perception, perturbation, and recovery, with no obvious bloat or redundancy.
The tool surface covers the core sim-control loop: inspect state, move, trick, push, look, view, stop, and reset. Minor gaps exist, such as no dedicated stand-up command and no ball manipulation beyond trick-triggered kicks, but those are explicitly handled via reset or documented limitations.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Deterministic MiniMindsLab utilities for AI agents over MCP.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control Unreal E…
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Hosted MCP endpoint with realistic fake data for prototyping agents. 12 tools, no setup.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to control a Minecraft bot for movement, building, crafting, and instant schematic-based structure spawning via MCP tools.372Apache 2.0
- AlicenseNot gradedqualityDmaintenanceExposes MuJoCo physics simulation to AI assistants via 65 MCP tools, enabling natural language control of robotics simulation, trajectory optimization, contact analysis, and video export.8MIT
- FlicenseNot gradedqualityDmaintenanceProvides physics simulation capabilities using PyBullet, enabling 3D physics world creation, object loading, force application, and state monitoring through MCP protocol.-
- -licenseNot gradedqualityBmaintenanceAn MCP server that gives AI agents full control and observability of the Webots robot simulator, enabling launch and monitoring of simulations, reinforcement learning training, model evaluation, and interactive scene manipulation.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aj-dev-smith/microduck-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server


