-
Notifications
You must be signed in to change notification settings - Fork 0
Cookbook
Recipes. Paste, adjust the names, move on.
The whole point. A tool that returns 20 issues returns 20 full issues. You wanted three fields.
# measured on a real tracker: 24,568 characters down to 1,768
mduct call tracker list_issues limit=20 --json | jq -c '.issues|map({id,title,status})'--json strips the prose some servers wrap around their payload ("Found 20
issues:"), which is what makes the pipe work at all. It also skips the
oversized-list guard, since you are obviously already slimming the thing.
Don't know the shape? Look once, then project:
mduct call srv some_tool --json | jq 'if type=="array" then .[0] else . end | keys'mduct call tracker list_issues state=open --json \
| jq -r '.[].id' \
| while read -r id; do
mduct call tracker get_issue id="$id" --json | jq -c '{id, title, assignee}'
doneProject the second call as well, or you have moved the wall of text one line down and gained nothing.
# every open MR whose branch no longer exists
mduct call gitlab list_merge_requests project_id=grp/proj state=opened --json \
| jq -r '.[].source_branch' \
| while read -r b; do
git ls-remote --exit-code --heads origin "$b" >/dev/null 2>&1 || echo "stale: $b"
donemduct call srv create_thing --args @payload.json
jq -n '{title:"from a pipe"}' | mduct call srv create_thing --args -Guards live in the daemon, so this holds however the caller phrases the request:
Deny wins over allow. "deny": ["delete_*", "drop_*"] is the other direction
when a server is mostly fine.
export MDUCT_PROFILE=ci # ~/.config/mduct-ci/, own socket, own secrets, own daemon
mduct add tracker --url https://mcp.example.com/mcp
mduct call tracker list_issues --json | jq length
mduct daemon --stop # tidy upNothing is shared with your default instance. Not the config, not the tokens.
"playwright": {
"run": "bunx",
"args": ["playwright@1.61.1"],
"check": "bunx playwright@1.61.1 --version",
"setup": "bunx playwright@1.61.1 install chromium",
"note": "headless browser"
}mduct tool status # shows "↑ update 1.61.1 → 1.62.0" when one is out
mduct tool update playwright # bumps the pin
mduct run playwright test e2e/The env and the wrapping travel with the config, so the tool behaves the same on a laptop and on the build box.
mduct import # what's attached in ~/.claude* and .mcp.json
mduct import gitlab # copy one across; literal tokens land in the secret store
mduct doctor # anything still attached directly AND served here — you want zero
claude mcp remove gitlab # ...then drop the direct attachment, or you pay for both--json is what the text output shows, as data, plus the auth state it never
showed at all.
mduct status --json | jq -r '.servers[] | [.name, .state, .auth.state] | @tsv'
# gitlab connected n/a
# notes idle refreshable
# tracker idle expiredPoll it as often as you like — neither status --json nor servers --json
starts a daemon, and the daemon's answer doesn't postpone its idle sweep either,
so watching the state never changes it. Measured at under 50 ms with nothing
listening.
The one line worth putting in front of a human, before a call fails instead of after:
mduct status --json | jq -r '.servers[] | select(.enabled and .auth.fix) | .auth.fix'
# mduct auth trackerrefreshable deliberately produces nothing here: the daemon renews that one on
the next call. The .enabled guard matters — a server you disabled still reports
its dead login, and you don't want to be told to fix one you turned off. Full
field reference in Commands.
mduct servers # config + connection state
mduct tools srv | head -30 # names and signatures, no schemas
mduct schema srv the_tool # the full schema, only when you need it
mduct call srv the_tool --raw # the MCP envelope, if a result looks wrongSequential calls reuse the same warm connection, so a loop is cheap:
for p in api web worker; do
mduct call gitlab list_pipelines project_id="grp/$p" --json | jq -c "{repo:\"$p\", last:.[0].status}"
doneOne connection per server, and by default one call at a time on it. If the server tolerates concurrency, say so and the loop above overlaps:
"gitlab": { "command": "…", "maxConcurrent": 4 }Measured against the real GitLab API: four calls in 2.8s instead of 6.0s. Start at 3 or 4 and watch the server's rate limit, not mduct's.
set -euo pipefail
if ! out=$(mduct call srv risky_tool id=42 --json 2>err.txt); then
echo "call failed: $(cat err.txt)" >&2 # errors go to stderr, exit code is nonzero
exit 1
fi
echo "$out" | jq -e '.ok' >/dev/nullError messages name the next action, e.g. unknown tool "x" — see: mduct tools srv.