Juggler is an MCP client. Point it at a
server — a local process or a remote endpoint — and that server's tools become
ordinary Juggler tools: the model can call them, each call is an inspectable
context item with its own approval and result view, and they sit in the same list
as read, bash and the rest.
Juggler keeps its own MCP configuration. It does not read another agent's config, so an existing setup elsewhere doesn't carry over — you declare your servers once, here.
Two files, both optional:
~/.juggler/mcp.json every project
<your project>/.juggler/mcp.json this project only
They're merged, and an entry in the project file replaces a global one of the
same name. On Linux the global file follows XDG:
$XDG_CONFIG_HOME/juggler/mcp.json, otherwise ~/.config/juggler/mcp.json. See
The ~/.juggler directory.
Note the path: it is .juggler/mcp.json inside your project, not a .mcp.json
at the project root. Juggler also doesn't look in ~/.claude.json,
.cursor/mcp.json, or anywhere else an agent you already use keeps its servers.
The easiest way to write either file is Settings → MCP servers → Add server, which also gives you a live status list, a Restart button, and each server's log.
If you use the Claude Code CLI provider: Juggler spawns the CLI with
--strict-mcp-configand serves it Juggler's own tools over a private connection. That deliberately ignores the MCP servers configured in the CLI's own settings, so the CLI's toolset is exactly the one Juggler shows you. The servers below are used by every provider, the CLI included.
{
"mcpServers": {
"<name>": { … }
}
}A server Juggler launches as a child process and talks to over stdio. This is the
default, so no transport line is needed:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "ghp_…" }
}
}
}An HTTP endpoint, with any headers it needs:
{
"mcpServers": {
"linear": {
"transport": "http",
"url": "https://mcp.linear.app/mcp",
"headers": { "Authorization": "Bearer lin_api_…" }
}
}
}"type" is accepted as a synonym for "transport", and "streamable-http" as
one for "http", so a server block copied from another agent works as-is.
Juggler stores it under transport next time it writes the file.
| Key | Applies to | What it does |
|---|---|---|
command |
local | The executable to launch. Required for a local server. |
args |
local | Arguments, one per array entry. |
env |
local | Extra environment variables for the child process. |
transport |
all | stdio (the default), http, or sse. |
url |
remote | The endpoint. Required for http/sse. |
headers |
remote | Sent on every request — this is where a token goes. |
enabled |
all | false keeps the entry but never starts it. Default true. |
tools |
all | {"allow": […]} / {"deny": […]} — see below. |
defaultArguments |
all | Fixed arguments merged into every call — see below. |
Juggler sends the static headers you configure and nothing else. There is no
browser sign-in flow and no dynamic client registration, so a server whose only
path is interactive OAuth won't connect on its own.
Two ways round it:
-
Use a token. Most hosted servers accept a personal API token in an
Authorization: Bearer …header, which is the config above. Prefer a read-scoped token where the server offers one. -
Put a proxy in front of it.
mcp-remoteperforms the OAuth exchange, caches the token, and presents the result as a local stdio server:{ "mcpServers": { "linear": { "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.linear.app/mcp"] } } }
Each discovered tool is offered as mcp__<server>__<tool> — so the name you
choose for a server becomes part of every one of its tool names. Keep it short,
with no spaces or /. juggler is reserved for Juggler's own tools.
Two behaviours are worth knowing, because both are decided by the server rather than by you:
- Read-only annotation. A tool that declares itself read-only is treated as a read: it can run in parallel with other reads, and read-only strategies such as Plan and the Explore/Research sub-agents will use it. A tool that says nothing is assumed to modify things, so it needs approval and those strategies withhold it. A server that annotates nothing therefore has no tools available while you're planning.
- Schema quality. The input schema comes from the server as-is. A tool whose schema is malformed is dropped rather than offered, and the drop is named in the log — the rest of the server's tools are unaffected.
Servers often expose far more than you want, and every tool costs schema tokens on every request. Two controls, per server:
{
"mcpServers": {
"memory": {
"command": "memory-server",
"tools": { "deny": ["delete_all"] },
"defaultArguments": { "bank_id": "general" }
}
}
}toolshides tools from the model and blocks calls to them.allow, when present, is a strict allowlist;denysubtracts. An allowlist is the safer choice: a server update can add a destructive tool that a denylist won't catch. Settings → MCP servers → edit gives you a checkbox per tool.defaultArgumentsare merged into every call to that server and removed from the schema the model sees. The configured value wins over anything the model supplies, so a routing key is decided by your config, not by the model.
Settings shows each server's tool count and its approximate token cost per request, which is the number to watch if your context is filling up.
An MCP tool call asks for approval by default — Juggler can't know what a third-party tool does. The approval offers three widths: this tool, all read-only tools on this server, or every tool on that server (trust the server). Granting by read-only only ever covers tools the server itself annotated as read-only.
Four places to look, in order:
- The System Prompt item's Tools section. Select System Prompt at the top of any column: its properties panel lists every tool the model is being offered in that thread, grouped by which server it came from. If your server's tools aren't in that list, the model has never seen them, whatever it says. A server that is configured but not serving gets its own line there, and tools the thread's strategy is holding back are shown struck through rather than silently dropped. Clicking any tool opens the settings that govern it — its server's entry for an MCP tool, so you land on the same form as the per-tool checkboxes below.
- Settings → MCP servers. A dot per server (grey stopped, amber starting, green running, red failed), the first line of the error when it failed, plus Restart and the server's own log output.
/mcpin a conversation, for the same list without leaving the keyboard./mcp restart <name>,/mcp logs <name>, and/mcp reloadalso work.server.log, where every MCP line is tagged[mcp]. See Logs & reporting issues.
For what a past turn actually sent — as opposed to what would be sent now — click the token count in the conversation footer. That opens the round-trip's record, whose tools row lists every tool definition the model received.
A server has 30 seconds to connect. A local server that dies is restarted up to three times, and the tail of its stderr is attached to the error.
| What you see | What it means |
|---|---|
| "No MCP servers yet" | Your config isn't in a file Juggler reads. Check the two paths above. |
| An error banner above the list | mcp.json didn't parse. The message names the position. |
has a "url" but no transport |
A remote entry missing its transport line. Add "transport": "http". |
no command configured |
A local entry with no command. |
unsupported transport "…" |
Typo — it's stdio, http, or sse. |
| 401 / unauthorized | The server wants credentials Juggler isn't sending. See Authentication. |
| Running, tools listed, but the model says the tool doesn't exist | The tool list for a turn is fixed when the turn starts. A server that finished connecting mid-turn shows up on the next one — the Tools section says so when it has tools the last turn didn't carry. |
| The tool exists but is never used while planning | It isn't annotated read-only, so read-only strategies withhold it. |
| A tool is missing from an otherwise healthy server | Either the tools filter excludes it, or its schema was malformed — the log says which. |