@mrrlin-dev/external-agents
This MCP server lets you manage and use a multi-provider pool of external LLM/CLI agents from your coding agent.
Check server health with
pingand list configured agents with their current state.Inspect per-agent status such as healthy, not installed, needs auth, quota exhausted, or transient errors.
Probe a specific agent to refresh its install/auth/availability state.
Store provider API keys locally so future dispatches can use them.
Pick up to N healthy agents round-robin, with optional tag/tier filters, ID exclusions, and cross-provider diversity.
Dispatch a prompt to a specific agent, override transport mode, or escalate to a same-provider strong-tier model.
Read dispatch telemetry such as per-agent counts, token usage, outcomes, and transport totals since a given time.
Provides access to Google Gemini models (7 variants) for LLM dispatch, with per-model quota management and automatic rate-limit handling.
Provides access to NVIDIA Nemotron models (e.g., 550B) via OpenRouter integration for LLM dispatch, available in the free-tier pool.
Provides access to Ollama Cloud models (e.g., gpt-oss 20B/120B) for LLM dispatch, with support for local daemon and round-robin routing.
Click on "Deploy 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., "@@mrrlin-dev/external-agentsdispatch analyze this error log using the cheapest available model"
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.
@mrrlin-dev/external-agents — Multi-LLM MCP Server
🔮 Part of Mrrlin (mrrlin.com) — The autonomous workspace for developers running AI coding agents. We extracted
external-agentsfrom Mrrlin so anyone using Claude Code, OpenAI Codex, or Cursor can leverage free-tier multi-model routing and adversarial review panels. Ships standalone under MIT.
Give your coding agent a pool of 40+ cheaper models to hand work off to. Cut your bill 10-100×.
Changelog: CHANGELOG.md

The problem this solves
You run Claude Code or Codex all day. Most of what it does — reading files to answer one question, running a test suite, renaming a symbol across 30 files, summarizing a diff — does not need a frontier model. But it all bills at frontier prices, on one account, against one rate limit.
Meanwhile you probably already have a handful of separate, mostly-free quota buckets sitting idle: a Google AI Studio key, a Groq key, OpenRouter's :free models, whatever agentic CLIs you're logged into.
external-agents turns those into one pool your primary agent can dispatch into. It picks a healthy provider per call, round-robins across buckets, and when one returns 429 it moves to a different provider and honors that provider's real reset time.
It's also a clean substrate for LLM-Council-style panels: one pick_agents call gives you N picks from N distinct providers, so a jury of models isn't secretly the same model four times.
Related MCP server: freellmpool
What this is optimizing for
Every design decision in here answers to five goals. They are the reason the project exists, and they are measurable — when a change makes one of these numbers worse, that is a regression, whatever else it improved.
A seat that gets handed out is alive.
pickreturning an agent is a claim that a dispatch to it can succeed right now. An agent that has never once answered must not be offered as though it might.A prompt that gets sent fits. The chosen seat's real ceiling — context window, tokens per minute, whatever is left of the current window — has to hold the whole prompt before it goes out. An HTTP 413 or a token-limit 429 is a routing bug, not bad luck.
More successes, fewer failures. A failed dispatch is a round of work thrown away, and inside a consensus panel it is a lost voice — the run gets a thinner verdict, not just a slower one.
Load spreads across the live models of a tier. No key carries a whole tier while its siblings idle, and a broken agent must not be re-offered faster than a working one just because failing is quick.
Provider limits get spent, not admired. A free tier that resets unused every night is tokens thrown in the bin. The pool should approach each bucket's ceiling rather than sit at one percent of it.
Goals 1, 2 and 5 all need the same thing, and it is worth stating plainly: the provider
tells you the answer on every single response. x-ratelimit-limit-tokens,
x-ratelimit-remaining-tokens, x-ratelimit-reset-* — the real ceiling for your key and
how much of it is left, on success as well as on failure. A registry entry is a guess about
that; a response header is a measurement. So the rule this codebase follows is: observation
beats declaration, and a limit discovered by being rejected is a limit that was recorded too
late.
These numbers are watched rather than asserted — see Watching the pool for regressions.
🚀 2-minute setup
curl -fsSL https://raw.githubusercontent.com/mrrlin-dev/external-agents/main/install.sh | bashThe script installs the package, registers the MCP server with Claude Code and/or Codex (whichever it finds), and opens a local dashboard where you paste provider keys inline:

Then restart your MCP client. Your agent now has the tools.
npm install -g @mrrlin-dev/external-agents
# Register with whichever host(s) you use
claude mcp add external-agents external-agents-mcp
codex mcp add external-agents -- external-agents-mcp
# Set up keys
external-agents ui # opens http://127.0.0.1:4711Requires Node ≥ 20. Works on macOS and Linux; Windows via WSL.
How much do I have to set up before this is useful?
Nothing, if you're already logged into an agentic CLI. Entries backed by a subscription you already have — claude, codex, cursor-agent, ollama, opencode, kiro-cli, agy — need no API key at all; they're usable the moment the binary is on your PATH and logged in.
Everything else is incremental. Each key you paste lights up more of the pool, and none of them are required:
Paste this | Get | Cost |
| Gemini Flash | Free tier, no card |
| Llama 3.3 70B, gpt-oss 120B/20B, Llama 3.1 8B | Free tier, no card |
| 5 | Free tier, no card |
| DeepSeek v4 flash + v4 pro (reasoner) | Prepaid, needs a small top-up |
Signup for each is about a minute. The dashboard links straight to the right page and has a paste box next to it.
What your agent gets
Two MCP tools, available automatically after setup:
dispatch(agent_id, prompt)— run a prompt on a specific pool member. Auto-retries on a different provider if the first is rate-limited, and honors the provider's own reset time rather than a made-up 1-hour default.Pass
cwd(an existing directory — a git worktree, say) and a direct CLI will inspect and edit files in place.cwddoes not grant filesystem access to HTTP-based models; give those context withfilesinstead. Whencwdis a git repo, thefileslist that comes back is the git-changed set, not the whole tree.A
cwdthat is a git repo also gets a short provenance header prepended to the prompt — branch, commit and subject, drift versus upstream, whether the worktree is dirty — and the same facts come back to you asrepo. This is what stops a worker pointed at a stale checkout from producing an accurate report about code that is no longer there and having it read as a hallucination. It's read-only and never fetches. If you want that to be a hard precondition rather than a note,external-agents dispatch --require-base origin/mainrefuses to dispatch at all when the checkout doesn't contain that ref — exit 6 for a wrong checkout, 2 for a usage error. Being ahead of the ref is fine; the base is a floor, not an equality check.pick_agents(n, min_distinct_providers)— ask for N healthy agents from N different providers. This is the primitive for fan-out: jury-style review, self-consistency checks, your own consensus loop.
Both tools carry the routing guidance below in their descriptions, so any model reading the schema at runtime picks up the same bias.
Everything is also available from the terminal — external-agents pick, dispatch, status, stats, audit — if you'd rather script it than go through MCP. Run external-agents with no arguments for the full list.
What's in the pool
28 bundled entries, 25 enabled out of the box. The rest are paid upgrades that stay off until you opt in.
Provider | Entries | What you need |
Google AI Studio | Gemini 3.6 Flash; Gemini 3.1 Pro (off — no free tier) |
|
Groq | gpt-oss 120B, gpt-oss 20B, Qwen3.6 27B |
|
OpenRouter | 5 |
|
Antigravity | Gemini Flash/Pro, Claude Sonnet 4.6, Claude Opus 4.6, gpt-oss 120B |
|
Anthropic | Claude Opus 4.8, Sonnet 5, Haiku 4.5 |
|
Codex | GPT-5.4 (CLI default) and GPT-5.4-mini |
|
Ollama Cloud | gpt-oss 20B, gpt-oss 120B |
|
DeepSeek | v4-flash, v4-pro (both off until you add a key) |
|
cursor-agent / opencode / kiro-cli | one agentic CLI reviewer each | the respective CLI |
Got a second Google project? Google AI Studio can rate-limit an entire project at once, separately from each model's own per-minute limit — so a second key from the same account is a genuinely independent bucket, not a retry of the first. The dashboard's "+ Add another key" clones the provider's models under a new slug (google → google2 → google3…) and stores it in your local overlay, where it stays removable. The same applies to any key-based provider here.
Google's strong-tier model is the one bundled entry that's off by default: Gemini 3.1 Pro has a free-tier allowance of zero, so reaching it at all needs billing enabled. It stays bundled so you can flip it on if that's what you want. If you want a strong model for free instead, the pool has nine — Nemotron Ultra and Super on OpenRouter, gpt-oss 120B on Groq and Ollama, and Claude Opus / Gemini Pro through Antigravity.
DeepSeek ships disabled because its API is prepaid — with no key and no balance it can't answer anything, so it stays out of your pool until you add DEEPSEEK_API_KEY, at which point both entries turn themselves on.
Cerebras (removed in 0.13.0) and Z.ai (removed in 0.22.0) are no longer bundled — both need paid-provider setup. Add them back locally with add-model if you have a plan.
Missing a provider? Suggest it — the dashboard has a form that opens a pre-filled issue.
Keeping the pool honest
Providers deprecate models, free tiers rotate, keys expire. The bundled registry tells you what exists; only a real call tells you what your account can still reach.
external-agents audit # every enabled entry with an HTTP transport
external-agents audit --provider google # just one bucket
external-agents audit --include-disabled # include switched-off entries tooOne round-trip per entry, concurrent per provider so you don't trip rate limits, and the verdicts are written to state.json — so the dashboard and dispatch immediately reflect ground truth:
✓ healthy— key works, model exists⚠ needs_auth— 401/403, paste or refresh the key✗ model_unavailable— key is fine, this model isn't on your tier⏳ rate_limited— hit the current limit, will recover? errored_transient— something went wrong once; expires by itself after 15 minutes! probe_error— the probe command couldn't run here at all (usuallyPATH). Says nothing about the agent, so nothing is written
audit also sweeps this package's own temp directories once it's done, reporting what went. Those directories hold each dispatch's generated.md — the model's full response, in plain text — and the OS only reclaims them after about a month. The window defaults to 3 days; EXTERNAL_AGENTS_TEMP_RETENTION_DAYS changes it, and a negative value turns the sweep off. Nothing outside this package's own prefixes is ever touched, symlinks are skipped rather than followed, anything sitting on a different filesystem (a mount point) is left alone, and nothing modified in the last 15 minutes is removed whatever the window says — so a dispatch running right now can't lose its workdir even if the window is set to zero.
Switched-off entries are skipped by default: they can't be dispatched anyway, and for a prepaid provider auditing one spends real money to learn nothing. external-agents status shows a use column so a green healthy next to a switched-off entry can't be misread as "available".
Day to day, external-agents ui is the same information as a page: live provider state, usage, and a paste box per provider. It binds to loopback only. Individual entries have an on/off switch (external-agents toggle <id> --disabled) if you want one out of rotation without deleting anything.
When something fails and you want to know why
external-agents stats keeps a 400-character preview of the last error per agent — enough for the dashboard, rarely enough to fix anything. The preview is a tail, so a CLI that prints a banner and then throws gets the banner clipped in and the exception clipped out.
The sidecar failure log is the other half. It is off by default and records nothing until you switch it on:
external-agents failures onFrom then on every failed attempt is appended whole to ~/.local/state/external-agents/failures.jsonl — one JSON object per line:
dispatch — full stdout, full stderr, the exact argv, the cwd, the HTTP request and the provider's untruncated response body
audit and credential verify — the raw probe output the hint clips to 200 characters
read-only probe — including the case where a declared read-only command wrote to the canary
pre-dispatch refusals — unknown agent, disabled agent,
--require-basemismatch, no escalation candidate. These never reach the dispatch log at all, and they are the ones hardest to reconstruct later: nothing was spawned, so there is no exit code to find.
Each row also carries the classification drawn from that output (needs_auth, quota_exhausted, model_unavailable, harness_failure), so a model reading the file can tell "your key is wrong" from "this model no longer exists" from "your PATH is broken" without re-deriving it.
That is the intended use. The log is written to be pasted:
external-agents failures tail 50 # raw JSONL — hand it to a model and ask what to fix
external-agents failures status # is it on, how big, which agents fail most
external-agents failures off
external-agents failures clearThe switch lives in ~/.local/state/external-agents/config.json, not in the package — so npm i -g @mrrlin-dev/external-agents@latest cannot silently turn it back off. EXTERNAL_AGENTS_FAILURE_LOG=1 (or =0) overrides the file for a single run; EXTERNAL_AGENTS_FAILURE_LOG_FILE points the sink somewhere else.
Everything stays on your disk — the file is 0600 and nothing is transmitted anywhere. Secrets are stripped on the way in: every key-shaped environment value this process is holding is blanked by exact match (in its escaped form too, for the pass that runs over the serialised line), plus a pattern pass for tokens it never held, plus a shape pass for a password embedded in a connection string, plus a final pass over the serialised line. Which names count as key-shaped is a list, and a list is only as complete as the conventions someone thought of — KEY, TOKEN, SECRET, AUTH, PAT, PSK and their neighbours are in it.
The tool does not write your prompt down — prompt_text is dropped and the prompt positional in the argv becomes a byte count; --with-prompts opts back in. That is not the same as a promise that no prompt text is in the file: many CLIs echo the prompt back on stdout, and raw.stdout is captured whole, which is the whole point of the sink. Read the file before you paste it somewhere you wouldn't paste the prompt.
The other log: dispatch-log.jsonl
Beside it sits a second, much smaller file — one ~300-byte row per dispatch, no prompt text, no raw streams, written whether the call succeeded or not. That one is always on, and it stays that way: it is where get_stats, doctor and the observed-limit ledger get their numbers, and every defect this pool has fixed in that area was found by reading it rather than by reading code. There is no switch, because a pool that has quietly stopped measuring itself looks exactly like a healthy one.
What it is not allowed to do is grow forever on your disk:
Retention is 30 days, and it is measured in days rather than bytes on purpose. Every question anyone asks this file is a question about time —
--since 24h,doctor's measured-allowance window — and a byte cap answers those only by coincidence of how busy you were: a quiet month keeps a year of dead rows, a busy week drops the far end of a window you were still asking about. Nothing errors in either direction, which is what makes bytes the wrong axis.EXTERNAL_AGENTS_DISPATCH_LOG_RETENTION_DAYSchanges the window;EXTERNAL_AGENTS_DISPATCH_LOG_MAX_BYTESis a 32 MiB backstop for a burst that outruns the age rule inside one window, and it says on stderr when it trims.Trimming happens when the oldest row is about a fifth of a window overdue, not the moment it crosses the line — so the file settles between 30 and 36 days and gets rewritten every few days instead of on every single dispatch. Only one process trims at a time. An abandoned lock is reclaimed by checking whether its holder is still running — never by how old it looks, because a lock's age cannot distinguish an abandoned prune from a slow one. In the one case liveness gets wrong (a recycled pid) the tool tells you, with the command to clear it, rather than guessing.
EXTERNAL_AGENTS_DISPATCH_LOG_FILEpoints it somewhere else — the same overridefailures.jsonlhas.The file is
0600(re-checked on every write, not only at creation), and the one free-text field in a row — the 400-character error preview kept on failures — goes through the same redaction as the sidecar.
Adding your own model
An internal endpoint, a beta model, anything not bundled:
external-agents add-model \
--id kimi-k2-instruct \
--provider groq \
--model moonshotai/kimi-k2-instruct \
--url https://api.groq.com/openai/v1/chat/completions \
--env GROQ_API_KEY \
--tags free,fastThat writes to ~/.local/state/external-agents/agents.local.yaml, layered over the bundled registry — same id replaces, new id appends. Package upgrades never clobber it. Full walkthrough: docs/adding-a-provider.md.
Watching the pool for regressions
The five goals above are checked, not assumed:
external-agents doctor # last 24h
external-agents doctor --since 7d # a wider window
external-agents doctor --json # machine-readable, same checksOne check per goal, each carrying the evidence that lets you verify or dismiss it and the command that fixes it. Exit code is 1 only on a high-severity finding and 0 otherwise, so it is safe to run unattended and only shouts when something actually broke.
Check | Goal | Means |
| 2 | An HTTP 413 happened. With measured ceilings this should be unreachable. |
| 2 | An enabled HTTP seat has no ceiling, declared or observed — nothing can protect it. |
| 1 | An agent was dispatched repeatedly and never once succeeded. |
| 3 | The window fell below the floor. |
| 4 | One seat is taking far more than its share of a tier. |
| 5 | A known allowance is going unspent, and nothing says the family is capped elsewhere. |
Every day, without being asked
Point a scheduler at it. doctor is the tested half — thresholds, evidence, a
remedy per finding, an exit code — and whatever runs it on a timer is the other
half. A Claude Code scheduled task works well, because the interesting part of a
daily check is not running the command but deciding what in its output is worth
waking somebody for:
Run `external-agents audit` then `external-agents doctor --since 24h --json`.
Report only findings with severity "high", plus anything that changed since
yesterday. If nothing is high and nothing changed, reply with one line.Run audit before doctor, and that order is the design: audit is one
max_tokens: 1 ping per HTTP entry, and the probe response carries the
provider's real rate-limit ceiling — so the measuring pass repairs the commonest
finding instead of merely reporting it. A watchdog that fixes what it can is
worth keeping; one that only complains gets muted.
Routing philosophy — be smart, not lavish
pick_agents defaults to tier: "weak" on purpose. Most tasks don't need a frontier model.
Single-file edits, refactors, glue code, summaries, format conversions, well-scoped bug fixes, docstrings, test cases — a Gemini Flash, Groq gpt-oss, DeepSeek, or OpenRouter :free model gets you the same correct answer as Claude Opus or Codex Pro, faster and for a fraction of the cost.
Reach for strong tier (Claude Opus, Codex, DeepSeek Reasoner, Nemotron Ultra) when the task is genuinely one of these:
Multi-step debugging with an unclear root cause
Architecture or API-shape decisions
Novel algorithms, math-heavy transforms
Ambiguous requirements the model has to disambiguate
If a weak-tier agent gets it wrong, the first move is to sharpen the spec, not escalate the tier. escalate_to_pro is a retry lever, not a default — reaching for a bigger model hides prompt-engineering failures behind expensive compute, and you'll pay for it on every subsequent call too.
Related: --effort <level> controls reasoning depth where the provider supports it. Use high for planning, design, and review; leave it off for mechanical edits. See docs/effort.md for the verified per-agent table.
🔮 Mrrlin uses this (and you can too)
Mrrlin (mrrlin.com) is the autonomous engineering workspace this engine was extracted from.
In Mrrlin, autonomous agents collaborate across software lifecycles under clear human oversight:
🛡️ 4-Model Consensus Panels: High-stakes architecture specs and PR diffs are reviewed by an adversarial panel: GPT + Gemini Pro alongside two dynamic free-tier terminal reviewers from this exact pool. Stacking free tiers keeps the incremental compute cost of cross-model verification near zero.
🌿 Ephemeral Worktrees: Coding agents run inside isolated Git worktrees (
~/.mrrlin/worktrees), significantly reducing branch interference and file conflicts during parallel execution.⚡ Autopilot & Triage: Background coordinators auto-triage incoming tasks, formulate execution plans, and assign the most cost-effective model tier for each step.
🎚️ Multi-Tier Autonomy: Tasks declare clear boundaries:
auto(hands-off),minimal_human(sign off only on sensitive actions), orhuman_only.
You don't need Mrrlin to use external-agents — this package is completely standalone. But if you are building multi-agent workflows or looking for a unified workspace, check out mrrlin.com.
FAQ
No. Keys live in ~/.local/state/external-agents/keys.env (mode 0600) and are read into the MCP server's environment. The dashboard that accepts them binds to loopback only, never to a network interface. Subscription tokens stay wherever their own CLI put them (codex login, claude login) — this package never reads or moves them. Nothing is transmitted anywhere except to the provider you're dispatching to.
Yes, if you're logged into at least one agentic CLI — claude, codex, cursor-agent, ollama, opencode, kiro-cli, or agy. Those entries are subscription-backed and need zero key setup. Free-tier API providers stack on top whenever you feel like adding them.
Reload the page — since 0.39.0 the dashboard and the MCP server re-read the key store on every request, so a key added from a terminal shows up on the next poll. If it persists, the value is probably being shadowed by the same variable exported in your own shell, which always wins over the stored one.
Every real call updates state from the response headers and error body. Cooldown uses the provider's own reset time, parsed from x-ratelimit-reset-*, Retry-After, and error payloads. If Google says the quota resets in 42 hours, it waits 42 hours instead of guessing an hour and hammering a wall.
npm i -g symlinks external-agents-mcp into your global bin directory (usually /opt/homebrew/bin on macOS, /usr/local/bin on Linux), which is on your PATH. claude mcp add writes that literal string into ~/.claude.json, and Claude Code spawns it as a child process — ordinary PATH resolution. No hosting, no daemon, no registry lookup.
🔮 About Mrrlin
external-agents is an open-source component of Mrrlin — an autonomous engineering workspace designed for solo developers and small teams scaling their output with AI coding agents.
🌐 Website: mrrlin.com
💡 Philosophy: Docs-first multi-agent orchestration, consensus review gates, and verifiable code execution.
License
MIT. Issues and pull requests welcome.
Available Tools
8 toolsdispatchA
Run a specific agent by id with a prompt. transport ('generate_new' | 'edit_exists' | 'read_only') overrides the default. With cwd, edit_exists is preferred when declared; otherwise generate_new is preferred. escalate_to_pro=true uses the same-provider strong-tier entry instead.
read_only: use when the agent must NOT be able to write — e.g. a reviewer dispatched into a live repo it is judging. Selects a declared read_only command, or an implicit generate_new (HTTP has no filesystem access at all). An entry with only edit_exists and no read_only errors rather than silently falling back to the write-capable command.
ROUTING NOTE: for the same task, weak-tier free-tier models (Gemini flash, Groq Qwen, DeepSeek, OpenRouter :free) are usually correct AND fast enough. Use dispatch against Claude Opus, Codex Pro, or any strong-tier subscription model ONLY when the task genuinely needs frontier capability. escalate_to_pro is a retry lever, not a default. If a weak agent's output is wrong, first ask whether the SPEC was ambiguous (fix the spec, re-dispatch weak) before escalating tier — reaching for stronger models hides prompt-engineering failures behind expensive compute.
cwd: absolute path of an existing directory (e.g. a git worktree) for an edit_exists agent to run IN and edit files in place. When an agent declares edit_exists, supplying cwd selects it by default. generate_new (HTTP) ignores cwd and has no filesystem access. When cwd is a git repo, the returned files list is the git-changed set, not the whole tree.
files: array of {path, lines?, label?} entries. Their contents are read from disk and prepended to the prompt as a structured context block. CRITICAL for generate_new agents (they have ZERO filesystem access — without files they hallucinate code shapes). Optional for edit_exists: direct CLIs can inspect cwd themselves; attach files only when you need to constrain or highlight context. Paths resolve relative to cwd. IMPORTANT: when using files, ALWAYS pass cwd (the repo root) — it serves as the containment basedir for path resolution and security. Without cwd, paths resolve against the MCP server process cwd, which is likely wrong.
By default this refuses a prompt larger than agent_id's known token-per-minute ceiling (the same declared/observed limit pick_agents checks before seating one) instead of sending it and getting a live HTTP 413. Pick a different (or larger-ceiling) agent_id, or set allow_oversized_prompt=true to send it anyway.
| Name | Required | Description | Default |
|---|---|---|---|
| cwd | No | ||
| files | No | Attach file contents to the prompt so the agent sees real code, not hallucinated shapes. Each entry: { path: 'relative/or/absolute', lines?: '10-50', label?: 'short name' }. Paths resolve relative to cwd (or process cwd). The contents are prepended to the prompt as a structured context block. Essential for generate_new agents (no filesystem access); optional for edit_exists because direct CLIs can read cwd. | |
| prompt | Yes | ||
| agent_id | Yes | ||
| transport | No | ||
| escalate_to_pro | No | ||
| allow_oversized_prompt | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses the oversized-prompt refusal and the resulting 413 avoidance, path containment/security behavior via cwd, that generate_new has zero filesystem access, that an entry with only edit_exists and no read_only errors instead of silently falling back, and that the returned files list is the git-changed set rather than the whole tree. These are non-obvious traits an agent could not infer from the schema.
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?
Purpose is front-loaded and each paragraph maps to a parameter or behavior, so the structure is clean. It runs long and repeats the 'generate_new has no filesystem access' point three separate times, which is more verbosity than the complexity strictly requires.
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 7-parameter execution tool with no annotations and no output schema, this covers what an agent needs: transport selection precedence, escalation policy, file-context requirements, containment rules, error behavior, and prompt-size limits. Even the return value's meaning (git-changed set vs whole tree) is explained without an output schema.
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 only 14%, so the description must compensate, and it does for cwd, files, transport, escalate_to_pro, and allow_oversized_prompt — including the default-selection logic (cwd + edit_exists preferred) and relative-path resolution rules. agent_id and prompt get no elaboration beyond the opening sentence, which is the only real gap.
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 opening sentence gives a specific verb and resource: 'Run a specific agent by id with a prompt.' That is unambiguous and easy to tell apart from pick_agents (selection) or list_agents (enumeration). It never names a sibling explicitly, so differentiation is implicit rather than stated.
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?
Explicit when-to-use rules are everywhere: use read_only 'when the agent must NOT be able to write, e.g. a reviewer dispatched into a live repo it is judging,' use escalate_to_pro only for genuine frontier tasks, attach files for generate_new but only sparingly for edit_exists. The routing note even prescribes a diagnostic order (fix the spec before escalating tier), which is unusually strong guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_stateA
Return the current external-agents state file (per-agent healthy/not_installed/needs_auth/quota_exhausted/errored_transient with metadata)
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It states the tool returns a state file, which implies a read-only operation with no side effects. However, it does not explicitly confirm safety or disclose any permissions needed, which is acceptable for a simple read-only tool but leaves some ambiguity.
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 sentence that conveys all necessary information without extraneous words. It is front-loaded with the action and resource, and every word adds 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?
Given that there is no output schema, the description provides key return value semantics (possible states and metadata). It is sufficient for a simple read tool, though additional details about metadata format could be added.
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 input schema has zero parameters, so the description does not need to add parameter details. Per the scoring guidelines, 0 parameters yields a baseline of 4.
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 uses a specific verb 'Return' and clearly identifies the resource as 'the current external-agents state file', listing the possible per-agent states (healthy, not_installed, etc.) and noting it includes metadata. This distinguishes it from sibling tools like list_agents and probe_agent, which operate on individual agents or lists.
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 implies the tool is for retrieving the overall state of external agents, but it does not explicitly state when to use it versus alternatives (e.g., probe_agent for a single agent, list_agents for just listing). No exclusions or context are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_statsA
Aggregate dispatch telemetry from ~/.local/state/external-agents/dispatch-log.jsonl. Returns per-agent counts, tokens, outcomes; per-transport totals.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | ISO 8601 datetime; only rows with ts >= since included |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Reveals data source file path but does not mention read-only nature, error handling, or permissions. No annotations to contradict.
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 concise sentences; front-loaded with action and source, followed by output details. No wasted words.
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?
Complete for a simple read-only tool; includes source and output. Minor gap: no note on file existence or size implications.
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 covers the only parameter well; description adds no extra parameter context beyond confirming ISO 8601.
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?
Clearly states it aggregates dispatch telemetry from a specific file path and lists output categories. Distinct from sibling tools which focus on agent interaction.
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?
Implied usage for retrieving telemetry, but no explicit guidance on when to use vs alternatives or conditions to avoid.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_agentsA
List configured agents merged with their current state
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry full behavioral disclosure. It states the tool 'lists' (implying read-only) but does not clarify permissions, pagination, rate limits, or what 'merged with their current state' means concretely. Minimal transparency beyond basic action.
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, well-structured sentence that immediately conveys the tool's purpose. No extraneous words or details. Highly concise and front-loaded.
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 is simple with no parameters and no output schema. The description covers the core function but omits details about output format, potential errors, or limitations. For a list tool, it could be more complete (e.g., mention if it returns all agents or paginated). Adequate but not comprehensive.
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?
Baseline is 4 for 0 parameters. The input schema has no parameters, so the description does not need to add parameter semantics. It correctly conveys that no inputs are required.
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 verb ('list') and the resource ('configured agents') with a specific qualifier ('merged with their current state'). This distinguishes it from sibling tools like 'pick_agents' (selection) and 'get_state' (single agent state).
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?
No explicit guidance on when to use this tool versus alternatives. While the purpose is clear, the description does not mention when not to use it or compare with siblings like 'get_stats' or 'probe_agent'. Usage is implied by the simple listing action.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pick_agentsA
Pick up to N distinct healthy candidates by round-robin (preference_order + last_used_at). Optional min_distinct_providers enforces cross-provider diversity, counted per provider FAMILY: google3 and google4 are two API keys for one source, not two opinions. A model is never seated twice while an unseated one is available, so a panel gets distinct voices rather than clones of one model. Exclusion uses the same identity: filter.exclude_ids drops every entry serving the same model as each named id (excluding gemini-3.6-flash-6 will NOT seat gemini-3.6-flash-5 instead), and filter.exclude_providers matches by family, so 'google' covers google3..8.
ROUTING NOTE: omitting filter.tier defaults to tier='weak' here — enforced, not just advisory, so a forgotten tier can't silently draw a strong (costlier/slower) candidate instead. Most atomic tasks (single-file edits, refactors, glue code, summaries, format conversions, well-scoped fixes) get the same quality answer from a weak-tier free-tier model as from Claude Opus or Codex Pro, in a fraction of the time and cost. Reach for strong-tier by passing filter.tier='strong' explicitly, ONLY when the task actually needs deep reasoning: multi-step debugging, architecture decisions, ambiguous requirements, novel algorithms. Frontier ≠ better output for the long tail of routine work; often it is slower with no quality gain. Be smart, not lavish.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | ||
| filter | No | ||
| min_distinct_providers | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the round-robin ordering key, the dedupe rule ('never seated twice while an unseated one is available'), provider-family semantics for google3..8, and that the tier default is enforced rather than advisory — a non-obvious behavior an agent could otherwise get wrong. It never states what the call returns or whether picked candidates are reserved/locked, which keeps it off a 5.
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 operative facts are front-loaded, but the ROUTING NOTE balloons into advocacy — 'Frontier ≠ better output for the long tail of routine work; often it is slower with no quality gain. Be smart, not lavish.' — which is persuasion rather than specification and inflates the definition well past what the agent needs to select correctly.
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?
No annotations, no output schema, a nested filter object and 0% schema coverage mean the description is the only documentation. It covers selection, dedupe, exclusion and tier default thoroughly, but leaves `filter.tags` and the return shape (a list of ids? agent objects?) unaddressed — gaps an agent must guess at before calling.
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 compensate and largely does: exclude_ids matching by model identity (with a concrete gemini-3.6-flash-6 example), exclude_providers matching by family, min_distinct_providers counting per family, and filter.tier's enforced default are all explained. However, `filter.tags` is never mentioned and `n` is only implied by 'up to N', leaving two of five properties without semantics.
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 concrete verb and resource — 'Pick up to N distinct healthy candidates by round-robin' — and immediately names the selection algorithm (preference_order + last_used_at). An agent can tell this apart from list_agents (enumerate) or dispatch (execute) without opening any schema.
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 ROUTING NOTE is explicit when-to-use guidance: default tier='weak' is enforced, strong-tier is reserved for 'multi-step debugging, architecture decisions, ambiguous requirements, novel algorithms,' and routine atomic tasks are enumerated as weak-tier appropriate. This is exactly the when/when-not/alternative structure a 5 requires.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pingA
Ping the server
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description bears full responsibility for behavioral disclosure. It only states 'Ping the server,' which implies a read-only connectivity check but provides no details about side effects, error behavior, or response format.
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, concise sentence with no wasted words. It is appropriately front-loaded and efficient.
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 tool's simplicity (no parameters, no output schema), the description is largely complete. However, it could benefit from stating what the response indicates (e.g., success/failure), but this is a minor gap for a trivial ping 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?
The tool has zero parameters with 100% schema coverage, so the description adds no parameter info, but none is needed. The baseline for no parameters is 4.
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 'Ping the server' uses a clear verb ('Ping') and resource ('server'), and it is distinct from sibling tool names like pick_agents, get_stats, etc., which are all agent-related.
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?
No guidance is provided on when to use this tool versus alternatives. For a simple health-check tool, usage is implied but not explicitly stated, and there are no exclusions or comparisons to siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
probe_agentB
Probe a specific agent by id; runs an install-check and updates the state file. Returns the new state.
| Name | Required | Description | Default |
|---|---|---|---|
| agent_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses the side effect (updates state file) and return value (new state). Since no annotations are provided, it carries the full burden; however, it does not explain what 'probe' means in detail or mention permissions.
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 sentence with no unnecessary words. It is front-loaded with the main action. Could be slightly improved with structured bullet points.
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 simple tool with one parameter and no output schema, the description covers the action, side effect, and return value. However, lacking usage guidelines and parameter details, it is adequate but not comprehensive.
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 only parameter 'agent_id' has no schema description (0% coverage). The description adds minimal meaning beyond the parameter name and label, saying 'by id' but not clarifying format or constraints.
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 action (probe an agent), the specific operation (install-check and state update), and the return value (new state). This distinguishes it from siblings like 'list_agents' or 'get_state'.
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?
No guidance on when to use this tool versus alternatives like 'ping' or 'get_state'. The description implies it's for installation checking but doesn't specify prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_credentialA
Persist an API-key env variable so the next dispatch (and future sessions) see it. Writes to ~/.local/state/external-agents/keys.env (mode 0600).
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | ||
| env_name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: it writes to a specific file (~/.local/state/external-agents/keys.env) with permissions (mode 0600) and persists across sessions. It also explains the impact on dispatch. This is comprehensive.
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 sentence that front-loads the purpose ('Persist an API-key env variable') and includes specific details (file path, permissions, effect on dispatch) without any redundant information.
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 simple credential-setting tool with 2 required parameters and no output schema, the description covers all essential aspects: what it does, where it writes, persistence behavior, and impact on dispatch. No gaps remain.
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 description adds meaning beyond the schema by stating the tool deals with API-key env variables, implying env_name is the variable name and value is the key value. Though schema coverage is 0%, the description provides enough context to infer parameter roles.
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 persists an API-key environment variable for future sessions, specifying the verb 'persist', the resource 'API-key env variable', and the effect on dispatch and future sessions. It also includes the file path and permissions, making the purpose 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 implies usage for setting persistent environment variables that affect dispatch and future sessions. While it does not explicitly state alternatives or when not to use, the sibling tools are unrelated, so no confusion arises. A clear when-to-use context is provided.
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.
2 tool updates
v0.63.0- Changed
dispatch4 fields changed- added
Input schema / properties / allow_oversized_promptAdded value: +{ + "type": "boolean" +} - added
Input schema / properties / cwdAdded value: +{ + "type": "string" +} - added
Input schema / properties / filesAdded value: +{ + "description": "Attach file contents to the prompt so the agent sees real code, not hallucinated shapes. Each entry: { path: 'relative/or/absolute', lines?: '10-50', label?: 'short name' }. Paths resolve relative to cwd (or process cwd). The contents are prepended to the prompt as a structured context block. Essential for generate_new agents (no filesystem access); optional for edit_exists because direct CLIs can read cwd.", + "items": { + "properties": { + "label": { + "description": "Display label in the context block. Defaults to the path.", + "type": "string" + }, + "lines": { + "description": "Line range, e.g. '10-50'. Omit for entire file.", + "type": "string" + }, + "path": { + "description": "File path (absolute or relative to cwd)", + "type": "string" + } + }, + "required": [ + "path" + ], + "type": "object" + }, + "type": "array" +} - changed
Input schema / properties / transport / enumPrevious value: -[ - "generate_new", - "edit_exists" -]New value: +[ + "generate_new", + "edit_exists", + "read_only" +]
- Changed
pick_agents1 field changed- added
Input schema / properties / filter / properties / exclude_providersAdded value: +{ + "items": { + "type": "string" + }, + "type": "array" +}
8 tool updates
v0.29.0- First observed
dispatch - First observed
get_state - First observed
get_stats - First observed
list_agents - First observed
pick_agents - First observed
ping - First observed
probe_agent - First observed
set_credential
TDQS
Scored across 8 tools
Most tools have clearly distinct purposes: probe_agent mutates state via install-check, get_stats reads telemetry, set_credential writes keys, pick_agents selects candidates, dispatch runs them. The one soft overlap is get_state vs list_agents, both returning agent state (one raw state file, one merged with config), which an agent could occasionally conflate.
Consistent snake_case and predominantly verb_noun (get_state, list_agents, probe_agent, set_credential, pick_agents). Minor deviations are bare verbs 'ping' and 'dispatch', which still read naturally in context.
Eight tools is well-scoped for an agent-discovery/dispatch server: health, listing, probing, credentials, selection, execution, telemetry, and a liveness check. Each earns its place with no redundant filler.
Core lifecycle is covered: discover agents, check/probe health, set credentials, select candidates, dispatch, and inspect telemetry. Minor gaps exist—no way to add/remove/disable agents or cancel an in-flight dispatch—but agents can work around these via config files.
Maintenance
Related MCP Connectors
Pay-per-call ($0.01 USDC) model-routing for AI coding agents: which LLM to call, cost vs. quality.
Cost-optimized LLM model routing recommendations for autonomous AI agents
Real-time, drift-verified LLM pricing across 31 providers with cost+quality model routing.
AI routing, memory, guardrails, and governance. Routes across Claude, GPT, Gemini.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenancePools 178 enabled chat routes across 23 LLM providers behind a single OpenAI-compatible (plus experimental Anthropic-compatible) endpoint, so coding agents and existing apps can run on free tiers with automatic failover, usage tracking, and no API keys when a keyless route is live. It runs as a CLI, Python library, or local proxy with optional Tailnet serving and per-agent routing.-
- FlicenseNot gradedqualityAmaintenanceExposes 178 enabled chat routes across 23 cataloged LLM providers behind one OpenAI-compatible endpoint, so agents can query pooled free-tier and keyless models with automatic failover and per-day usage tracking. It can also report live provider capacity and health when a route is rate limited or down.-
- FlicenseNot gradedqualityAmaintenancePools enabled free-tier, keyless, and trial LLM chat routes behind a single OpenAI-compatible endpoint with automatic failover and local usage tracking, so coding agents and OpenAI/Anthropic-compatible tools can run on free models without changing their code. It also exposes provider health, capacity, model inventory, and routing-mode tooling so clients can discover and use whichever chat routes are currently accessible, including some that require no API key.-
- FlicenseNot gradedqualityAmaintenancePools enabled free-tier and keyless LLM chat routes behind a single OpenAI-compatible (plus experimental Anthropic-compatible) endpoint, letting coding agents and existing OpenAI-compatible clients query many providers with automatic failover, latency-aware routing, and local per-day usage tracking, even starting without credentials when a keyless route is up.-