Skip to content

Commands

Kevin Straub edited this page Aug 2, 2026 · 4 revisions

Every command, its arguments and what it prints. mduct help is the same list in one screen; this page is the version with the edges in it.

Nothing here starts a daemon on purpose. Anything that needs one gets one — the first command that talks to a server autostarts it and blocks until it answers. index, hook run, config, status and doctor never do, which is why they are safe in a shell prompt or a session-start hook.

Calling things

call <server> <tool> [args…]

Invoke one MCP tool. Arguments are key=value (scalar, coerced) or key:=<json> (anything typed); see Arguments & output for the full grammar.

Flag Effect
--args '<json>' merge an object of arguments; - reads it from stdin, @file from a file
--json print only the JSON payload, prose stripped — the flag that makes | jq work everywhere
--raw the full MCP envelope, unformatted
--compact / --no-compact minify (or don't) regardless of mduct config compact
--full print an oversized result anyway
--timeout <s> seconds; the IPC wait is extended past it automatically

Every flag takes --name value or --name=value. A token starting with - that is not a known flag is an error, never a tool argument — --timeout=5 used to arrive at the server as a field called --timeout, with the timeout silently dropped.

Exit codes: 0 success, 1 the call failed, 2 nothing was printed on purpose — either the oversized-list guard tripped (a long result the tool could offer a jq projection for; a big blob of prose is not one) or --json was asked of a result that has no JSON in it. A 2 is a decision, not an error: ask again, differently.

On an argument error the signature is printed after the message, so the retry does not need a mduct schema round trip.

run <tool> [args…]

Run a configured CLI tool with its stored env and argument wrapping. mduct run kubectl get pods is kubectl with the right KUBECONFIG and whatever flags the entry pins. Everything after the tool name is passed through untouched.

env <tool>

That tool's environment as shell exports, for a script that wants the library rather than the binary:

eval "$(mduct env playwright)"   # sets NODE_PATH at the installed version

tools <server> · schema <server> <tool>

tools lists names with argument signatures and one line of description, no schemas. It answers for CLI tools too, so an agent can ask about any capability without knowing which kind it is. schema prints one tool's full JSON schema, which is the thing you fetch once and then don't need again.

index [--refresh]

The capability block: one line per server, signatures where a server is small enough to carry them. Reads a cache the daemon fills as a side effect of use, so it works cold and without a daemon — --refresh fills that cache on purpose, which is what a fresh machine needs.

mcp

Serve the catalogue over MCP: tool names mirrored into an agent's namespace, no schemas, and calling one returns the mduct call … command instead of running it. Meant to be registered by hook install, not typed.

Servers and tools

Command What it does
servers configured servers with connection state; the instance path goes to stderr so stdout stays parseable
add no arguments: an interactive picker (↑↓, / to search, to toggle)
add <name> -- <cmd…> a stdio server
add <name> --url <url> an http server
add <ref> [--as <name>] install from the public registry, version-pinned
add <name> --tool -- <cmd…> a CLI tool
search <query> search the public registry
import [<name>…] lift servers out of your Claude configs
remove <name> delete an entry
enable / disable <name> toggle without deleting

add takes --env K=V (repeatable), --note "text" and --replace; a --tool entry also takes --check <cmd> and --setup <cmd>. import takes --as <name> (one server at a time), --source <file> and --replace.

Write the note for someone choosing between servers with nothing else to go on. It is the line that ends up in every agent's context.

tool status · tool setup <name> · tool update [<name>]

Is it installed, install it, and bump a version-pinned npm tool to the latest. tool status also reports when a pin has fallen behind.

Secrets and OAuth

echo "$TOKEN" | mduct secret set GITLAB_PAT   # or omit the pipe for a hidden prompt
mduct secret list                             # names only, never values
mduct secret rm GITLAB_PAT

Reference a stored secret as ${GITLAB_PAT} anywhere in the config. Resolution prefers the process environment, then the store, so CI can override without editing anything.

auth <server> runs the OAuth sign-in for an http server. The token is stored next to the config and refreshed by the daemon; you do this once.

Daemon, hooks, diagnosis

Command What it does
status daemon up? plus the socket, config and secrets paths of the instance that answered
logs [server] recent daemon activity, filtered to one server if named
shadow nudges against follow-up calls: did the redirect convert?
doctor servers attached directly to an agent that mduct already serves, with the token cost of the duplication
daemon run in the foreground — the way to read a startup failure
daemon --stop stop it; the next call starts a new one
daemon --install install a systemd user unit
config show the per-instance defaults
config compact on|off minify call output by default
config warnAbove <chars|off> the oversized-result guard
--version / -V the version, on stdout, exit 0
help / -h / --help this list; asking for help is not an error, so it exits 0

hook install claude [--settings <file>] [--remove]

Writes both hooks into ~/.claude/settings.json and registers the catalogue in ~/.claude.json. --settings points the whole operation at another installation, including the MCP file next to it.

hook install codex [--remove]

The same, as one marked block in ~/.codex/config.toml. It refuses rather than writing a file TOML would reject if [hooks] or [mcp_servers.mduct] already exist outside that block.

hook run session-start · hook run pre-tool-use

The hook bodies. They read a payload on stdin and are meant to be called by a harness, not by you — but running them by hand is a fair way to see what a hook would have said.

Instances

Every command above operates on one instance, and MDUCT_PROFILE chooses it:

MDUCT_PROFILE=research mduct servers

That is a separate config, separate secrets, separate OAuth tokens and a separate daemon under ~/.config/mduct-research/. No profile means ~/.config/mduct/. When something answers with the wrong servers, mduct status tells you which instance you actually reached — that is the first thing worth checking, and half of what looks like a bug.

Direct overrides still win over the profile: MDUCT_CONFIG, MDUCT_SECRETS, MDUCT_SOCKET, MDUCT_CACHE. Setting only some of them is how people end up talking to a daemon that holds a different config than the one they edited.

Clone this wiki locally