Atlas / MCP servers / mrrlin-dev / @mrrlin-dev/external-agents — Multi-LLM MCP Server

@mrrlin-dev/external-agents — Multi-LLM MCP ServerBLOCK

mcp/mrrlin-dev/external-agents

One MCP server routes LLM calls across 20+ providers, using round-robin dispatch and fallback to reduce rate-limit interruptions and cut costs up to 100x.

Verdict
BLOCK
Grade
F
Trust score
59 /100
Exposed tools
8 5r · 3w · 0d
Transport
stdio
License
MIT
Stars
0
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](#-2-minute-setup) [](#-2-minute-setup) [](#-2-minute-setup) [](https://www.npmjs.com/package/@mrrlin-dev/external-agents)

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.

What this is optimizing for

Every design decision in here answers to five goals. They are the reason the proje

Read from source at commit fd3a5703a743OBSERVED · 2026-10-12
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code (npm)
claude mcp add external-agents -- npx -y @mrrlin-dev/[email protected]
03

Exposed tools (8)

5 read · 3 write · 0 destructive.

ToolRiskDescription
dispatchwriteRun a specific agent by id with a prompt. transport (
get_statereadReturn the current external-agents state file (per-agent healthy/not_installed/needs_auth/quota_exhausted/errored_transient with metadata)
get_statsreadAggregate dispatch telemetry from ~/.local/state/external-agents/dispatch-log.jsonl. Returns per-agent counts, tokens, outcomes; per-transport totals.
list_agentsreadList configured agents merged with their current state
pick_agentsreadPick up to N distinct healthy candidates by round-robin (preference_order + last_used_at).
pingreadPing the server
probe_agentwriteProbe a specific agent by id; runs an install-check and updates the state file. Returns the new state.
set_credentialwritePersist an API-key env variable so the next dispatch (and future sessions) see it. Writes to ~/.local/state/external-agents/keys.env (mode 0600).
04

Trust audit

BLOCKgrade F · trust 59/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (2 observation(s))
Network
declared (5 observation(s))
Shell
declared (5 observation(s))
Dependencies
not all pinned
Secrets in source
found

Findings (21)

HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
cli.js:1033
yaml.load(fs.readFileSync(LOCAL_PATH, "utf-8"));
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
lib/registry.js:98
const parsed = yaml.load(fs.readFileSync(p, "utf-8"));
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
lib/registry.js:152
const bundled = yaml.load(raw);
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
lib/registry.js:245
const parsed = yaml.load(fs.readFileSync(LOCAL_PATH, "utf-8"));
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHFilesystem / path · fs.credential_store · CWE-22, CWE-59
agents.yaml:1007
# Requires prior `kiro-cli login`; state at ~/.aws/sso equivalent.
Why it matters. touches a credential store
MEDIUMHard-coded secrets · secret.generic · CWE-798, CWE-321
lib/failure-log.test.js:178
const token = "github_pat_11ABCDEFG0abcdefghijklmnopqrstuvwxyz1234567890AB";
MEDIUMHard-coded secrets · secret.github · CWE-798, CWE-321
lib/failure-log.test.js:178
const token = "github_pat_11ABCDEFG0abcdefghijklmnopqrstuvwxyz1234567890AB";
LOWCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
lib/pool-log-findings.test.js:50
const overlay = yaml.load(
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
LOWFilesystem / path · fs.system_paths · CWE-22, CWE-59
lib/state.test.js:410
assert.equal(displayPath("/etc/passwd", "/Users/alice"), "/etc/passwd");
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
lib/dispatch.files.test.js:110
fs.writeFileSync(outsidePath, "exfiltrated");
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
lib/dispatch.files.test.js:114
assert.ok(!result.includes("exfiltrated"));
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
README.md:83
external-agents ui        # opens http://127.0.0.1:4711
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
lib/dispatch.generate.test.js:20
transports: { generate_new: { url: `http://127.0.0.1:${port}`, model: "fixture" } },
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
lib/dispatch.generate.test.js:46
transports: { generate_new: { url: `http://127.0.0.1:${port}`, model: "fixture" } },
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
lib/dispatch.tempdir.test.js:53
transports: { generate_new: { url: `http://127.0.0.1:${port}`, model: "fixture" } },
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
lib/dispatch.tempdir.test.js:97
url: "http://127.0.0.1:1/never-reached",
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/sdk, js-yaml
Why it matters. 2 dependency range(s) float
Fix. pin exact versions or ship a lockfile
LOWPrompt injection · prompt.transfer_instruction · CWE-94, CWE-1427
README.md:309
<summary><b>Do you send my API keys anywhere?</b></summary>
Why it matters. an instruction to move sensitive data to an outside destination
Fix. remove; a skill never needs the user's secrets off the machine
INFOInventory / provenance · inv.oversize · CWE-1104
docs/hero.png
docs/hero.png
Why it matters. 1071451 bytes not read
INFOInventory / provenance · inv.oversize · CWE-1104
mrrlin-dev-external-agents-0.56.0.tgz
mrrlin-dev-external-agents-0.56.0.tgz
Why it matters. 1570777 bytes not read
INFOSupply chain · prompt.pipe_to_shell · CWE-829, CWE-1357
README.md:63
curl -fsSL https://raw.githubusercontent.com/mrrlin-dev/external-agents/main/install.sh | bash

Gates applied: no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha fd3a5703a743full audit observations/trust-audit/mcp-server/mrrlin-dev__external-agents.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-12fd3a5703a743BLOCKF59first audit
06

Questions

What is the @mrrlin-dev/external-agents MCP server?

One MCP server routes LLM calls across 20+ providers, using round-robin dispatch and fallback to reduce rate-limit interruptions and cut costs up to 100x.

What tools does @mrrlin-dev/external-agents expose?

8 in total: 5 read-only, 3 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is @mrrlin-dev/external-agents safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (59/100) and found 5 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does @mrrlin-dev/external-agents need?

It reads EA_TEST_KEY_2 and MY_ENTRY_API_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does @mrrlin-dev/external-agents run?

It speaks stdio, so it runs as a local process your client starts. It is published on npm as @mrrlin-dev/external-agents at 0.62.0.

How current is this page?

The grade is for one exact copy of the source (fd3a5703a743), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement