The first major version of Yaw MCP, and the largest release it has had. Adding a server no longer means restarting your client, an authenticated remote server can actually authenticate, and there is a shell surface wide enough to import, inspect and call servers without an MCP client in the loop. Free, local, no account.
Today @yawlabs/mcp 1.0.0 is on npm: the first 1.x release of the broker we renamed from mcp.hosting in May (that post covers the name and the architecture; this one does not repeat it), and by a wide margin the largest release the project has shipped -- 60 commits against a previous high of 28, merging three lines of work that had run in parallel. A remote server that can finally authenticate. A session that re-reads its own configuration while it runs. And a shell surface for scripts, git hooks and agent loops that do not speak MCP.
One command connects it to a client:
npx -y @yawlabs/mcp@latest install claude-codeSwap claude-code for claude-desktop, cursor, vscode, windsurf or gemini-cli. Inside Yaw Terminal, where Yaw MCP ships bundled, the same step is yaw mcp install claude-code. Node 20 or newer; nothing to sign in to.
The rename post described a dashboard, an account token and a 60-second config poll. None of that exists any more. 0.74.0 retired the hosted control plane: your servers come from ~/.yaw-mcp/bundles.json, your credentials from a local encrypted vault, and the only hosted surfaces left are the public server catalog, fetched on demand by yaw-mcp add, and its browsable form at yaw.sh/mcp/catalog. The releases since made a local-only product hold up: oam became the default runtime for the servers it spawns (0.74.1), tools/list stopped inlining the whole catalog and now advertises the meta-tools plus only what you have activated this session (0.75.0 -- the old shape was 252 tools and roughly 27,000 tokens on the maintainer's own install), the in-session vault passphrase prompt started working (0.78.0), and yaw-mcp's own secrets were stripped from every child process it starts (0.80.0).
1.0.0 is where those lines meet. The project follows semantic versioning, so from here a breaking change to the command surface, the meta-tools or the bundles.json shape means a new major.
0.74.0 removed the poll and wrote the consequence into the changelog: bundles.json is read once at startup, so restart the client after editing it. That has been the most expensive sentence in the product -- every yaw-mcp add, every enable, every credential fix did nothing until you killed the client and threw away the conversation.
The broker now re-reads bundles.json at meta-tool boundaries: at the top of every mcp_connect_* call, and only those, since proxied tool calls are exactly what a reload could invalidate underneath. A change goes through the same loader startup uses, so the project-consent gate re-runs. A namespace with a live tool call keeps its connection until the call drains, and a re-read that fails -- a half-saved edit that will not parse -- keeps the running config and tells discover the file on disk is broken instead of blanking the session. Profile config (blockedTools and the allow and block lists in .yaw-mcp/config.json) is deliberately not reloaded and still needs a restart.
Because this changes what an existing install does with nothing in your config having moved, it ships with an off switch: YAW_MCP_CONFIG_RELOAD=0 (or =false) restores the read-once behaviour exactly. yaw-mcp doctor lists it with the other knobs.
Before 1.0.0 every authenticated remote (HTTP or SSE) MCP server was unreachable: both transports were constructed with a URL and no options, so a token parked in the entry's env went nowhere, the far end answered 401, and the failure read as "server down". A remote entry now takes headers, sent on every request the transport makes, with values that resolve through the same vault env does:
yaw-mcp secrets set linear
yaw-mcp add linear --url https://mcp.linear.app/mcp \
--header 'Authorization: Bearer ${secret:linear}'Same placeholder, same fail-closed refusal: a locked vault, a missing name or a malformed reference refuses the connect before any transport is constructed, so the literal ${secret:linear} can never travel to a third party as a credential. doctor's vault section and mcp_connect_secrets now pick the credential map by the server's shape, so a remote server missing a secret shows up in the reports that exist to catch it.
yaw-mcp import <client> adopts the servers a client already has, carrying command, args, url, headers and env across as they stand and printing key names, never values. The trap is what happens next: the client still launches every one of those servers itself, so each now runs twice. The command says so and offers exactly three answers -- a [y/N] prompt on a TTY, --remove-originals, or --keep-originals -- and refuses to remove anything when the client has no yaw-mcp entry to hand the work to. --dry-run shows the plan without writing.
yaw-mcp call <namespace> <tool> [json] calls one configured tool from a shell, with the vault's credentials. Result text goes to stdout verbatim so it pipes; diagnostics go to stderr. Exit 0 when the tool answered, 1 when it could not be called or answered with an error, 2 when your own config refused it -- the same gates a proxied call gets, checked before anything is spawned: a disabled server, the project profile's allow and deny lists, YAW_MCP_MIN_COMPLIANCE, and blockedTools.
yaw-mcp call <namespace> <tool> '{"key":"value"}' # call one tool, print the result
yaw-mcp call github search --args-stdin < args.json # ...or pipe the argument object in
yaw-mcp call github search --json # the raw MCP envelope, not just its textyaw-mcp status [--json] answers "what is actually set up here" in one side-effect-free read -- the config file in force and its servers, the compliance grades on hand, what the learning store has recorded, which secret names the vault is expected to hold -- without spawning a server, opening the vault or touching the network. Exit 0 on a fresh machine; exit 1 only for a bundles.json that exists and cannot be read or parsed.
Around them: yaw-mcp set <ns> key=value, enable and disable edit one entry without hand-editing JSON; yaw-mcp add takes --command or --url to define a server the catalog does not list; install is idempotent, --repair takes a drifted entry unprompted, and uninstall <client> exists. Inside a session, mcp_connect_find_tool searches tools across every configured server by what they do, contacting and activating nothing.
YAW_MCP_MAX_RESULT_BYTES (default 100000, 0 disables) caps a single proxied tool result. Before it, a tool returning a whole log file landed whole in the model's context. The cut is loud -- a marker names the byte total, what was dropped and how to get the rest -- because a silently truncated log reads to the model as a complete one. structuredContent passes through verbatim and is not capped.
YAW_MCP_TOOL_TOKEN_CAP (default off) gates activation on the estimated token cost of the loaded tool surface. YAW_MCP_SERVER_CAP counts servers, and a slot is a slot: six 3-tool servers and six 60-tool servers both sit exactly at a cap of 6. And the saving this product claims is now measured: mcp_connect_health books what each server sent and what the model actually read, as a pair -- result bytes: 184320 upstream, 96450 to client (48% trimmed).
Before tagging, an audit drove the real CLI against throwaway home directories and came back with one ship-blocker and thirty-one smaller things. The blocker: an entry whose env was not a map -- a bare string, null, an array -- had every variable silently discarded while list, doctor and discover agreed the install was healthy. The loader now warns. The rest, by what you would notice:
reset-learning, try-cleanup and overwriting a stored secret with set env.KEY=<new> preview, prompt on a TTY, and refuse off one with exit 2 while naming the flag; --force bypasses.yaw-mcp on a TTY explains itself instead of printing four JSON log lines and blocking on stdio. It is still a working MCP server the moment stdin is a pipe; YAW_MCP_STDIO=1 forces that.yaw-mcp: warning: ...; setting LOG_LEVEL puts the JSON stream back.yaw-mcp <anything> | head no longer dies with a raw EPIPE stack, and the exit code is the one the command computed rather than the pipe's.YAW_MCP_PREWARM=0 stops yaw-mcp spawning a server at startup just to learn its tool list, for an upstream whose startup is not idempotent."pinned": true on an entry (or yaw-mcp set <ns> pinned=true) exempts it from the idle reaper. Only the boolean true pins; pinned=1 is refused with exit 2.YAW_MCP_PRUNE_RESPONSES=0 still turns it off.GITHUB_TOKEN the child inherited -- is redacted out of a failed server's stderr tail to ***NAME***, not just the values yaw-mcp injected.initialize instructions are surfaced once per namespace at activation, inside a fence that names the server and states the text is data, not instructions.Every MCP client keeps its own config file, so the standard setup is a hand-edited JSON block per client, per machine: the same GitHub server added to Claude Code and Cursor and VS Code separately, API tokens in plaintext env blocks, and every tool from every server loaded into context at session start whether the model uses them or not. (The full per-client map is in The Complete Guide to MCP Server Configuration.)
Yaw MCP is one MCP server that fronts every other MCP server you use. You point each client at it once; from the client's view it exposes a handful of mcp_connect_* meta-tools, and the underlying servers' tools come into context only when a task needs them. mcp_connect_dispatch takes a plain-English intent, ranks your servers against it with BM25 computed locally and loads the top match; discover, activate and deactivate give you manual control; a loaded server auto-unloads after about ten tool calls to other servers. It runs entirely on your machine, with no account and no sign-in. Running as an MCP server, its only outbound calls are two background npm checks -- one for its own updates (YAW_MCP_AUTO_UPGRADE=0 to disable) and, if you have run yaw-mcp sidecars install, a once-a-day check that the managed sidecar packages are current (YAW_MCP_SIDECAR_REFRESH=0 to disable). yaw-mcp add fetches the public catalog on demand. Nothing else leaves your machine.
The path from zero:
npx -y @yawlabs/mcp@latest install claude-code # connect a client
yaw-mcp secrets set gh # store a token in the local vault
yaw-mcp add github --env GITHUB_PERSONAL_ACCESS_TOKEN='${secret:gh}' # add a server, pointed at the vault
yaw-mcp doctor # config, clients, vault, upgrade checkThe installer edits the client's config in place -- correct path and JSON shape for your OS, and on Windows it wraps npx in cmd /c, without which clients hit ENOENT on the npx.cmd shim. Six clients are supported by name: claude-code, claude-desktop, cursor, vscode, windsurf and gemini-cli. Anything else that speaks MCP over stdio works by hand-editing its config: the entry is { "command": "npx", "args": ["-y", "@yawlabs/mcp@latest"] } under mcpServers (VS Code uses servers).
Credentials never sit in a client config. The vault is an encrypted file on your machine (scrypt-derived key, AES-256-GCM); a server references a value with a ${secret:NAME} placeholder in its env (local) or headers (remote), and the value is substituted at spawn or connect time. If the passphrase is absent or a name is not stored, the start is refused -- the literal placeholder is never passed through. The passphrase comes from YAW_MCP_VAULT_PASSPHRASE in yaw-mcp's own env or, if your client supports MCP elicitation, from an in-session prompt.
Two more things worth knowing. Every scored server shows an A-F grade from the 88-test mcp-compliance suite, in yaw-mcp list and inline in discover; YAW_MCP_MIN_COMPLIANCE=B makes activate refuse anything below the floor. And when oam is installed, yaw-mcp hosts the Node-based servers it spawns on it with nothing to configure; yaw-mcp sidecars install pins them to versions written down in ~/.yaw-mcp/sidecars instead of whichever copy the npx cache resolved last.
Breaking changes first.
yaw-mcp servers is deleted. It listed the servers on a hosted account and has been a stub that exits 1 since 0.74.0. It now exits 2 as an unknown subcommand, with a signpost rather than a did-you-mean: yaw-mcp: unknown subcommand "servers". That command was removed -- use `yaw-mcp list` instead. If anything you own shells out to it, switch it to yaw-mcp list.exec output shape. A pipeline that names a return step no longer echoes every other step's full output alongside it. The step keys still come back, and the full bodies still do when no return is named or when the skipped bodies fit a small budget.yaw-mcp list exits 1 on a bundles.json it cannot read, where it exited 0 -- for a broken file only; no file at all is still exit 0. There is no off switch: an exit code that reports the wrong outcome is a defect.bundles.json edit taking effect only after a restart, set YAW_MCP_CONFIG_RELOAD=0.Coming from before 0.74.0, three older changes also apply: Node 20 is the floor (npm on Node 18 refuses with EBADENGINE), yaw-mcp remove confirms on a TTY and refuses off one without --force, and a project-local .yaw-mcp/bundles.json is ignored until yaw-mcp trust approves it.
To move: a client entry that launches npx -y @yawlabs/mcp@latest re-resolves the tag on every spawn and is already on 1.0.0. A global install takes yaw-mcp upgrade --run or npm install -g @yawlabs/mcp@latest. Then yaw-mcp install <client> --repair takes any drift in the client entry unprompted, and yaw-mcp doctor confirms.
yaw-mcp add can installThe source is published so you can read it before you run it -- yaw-mcp spawns processes on your machine and handles your credentials, and you should not have to take that on faith. It is source-available, not open source: free personal and commercial use, no right to offer it to third parties as a competing product.
One broker in front of every MCP server you use.
Free, runs locally, no account. Connect a client in one command, then yaw-mcp add servers from the catalog.
npx -y @yawlabs/mcp@latest install claude-codePublished by Yaw Labs.