autorouter-mcp 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +96 -28
  2. package/dist/cli.js +1123 -772
  3. package/package.json +2 -2
  4. package/server.json +3 -3
package/README.md CHANGED
@@ -12,9 +12,12 @@ handful of skills is routinely 20–30k tokens of permanent overhead, paid wheth
12
12
  or not the task touches any of them. It also makes tool selection _worse_: more
13
13
  candidates means more mis-picks.
14
14
 
15
- autorouter is an MCP server that exposes ~4 stable tools and hides everything
16
- else behind a search. The model asks for what it needs in natural language, gets
17
- back a few ranked candidates, reads one schema, and calls it through the router.
15
+ autorouter is an MCP server that exposes a handful of stable tools and hides
16
+ everything else behind a search. The model asks for what it needs in natural
17
+ language, gets back a few ranked candidates with schemas attached, and calls one
18
+ through the router. A tool it actually uses is then promoted into the real tool
19
+ list, so the context is spent on what the session needs rather than on what it
20
+ might.
18
21
 
19
22
  ```
20
23
  find_capabilities({ query: "inspect recent deployment errors" })
@@ -34,6 +37,9 @@ autorouter init --target claude # claude | codex | cursor | vscode
34
37
  autorouter adopt --target claude # ← the step that actually saves context
35
38
  ```
36
39
 
40
+ That is a one-time migration of what you already have. New servers do not need
41
+ it — see [Adding an MCP server](#adding-an-mcp-server).
42
+
37
43
  **`adopt` is not optional.** Registering the router alongside your existing
38
44
  servers is a net _increase_: their schemas are still loaded and the router adds
39
45
  four more tools. `adopt` moves the downstream entries out of the harness config
@@ -72,21 +78,24 @@ Run `autorouter doctor` to see the difference:
72
78
 
73
79
  ```
74
80
  ## Context cost
75
- exposing everything: ~12,400 tokens
76
- router surface: ~700 tokens
77
- still loaded direct: ~11,700 tokens (10,800 servers + 900 skills)
78
- actually saved: ~0 tokens per request (0%)
81
+ exposing everything: ~87,524 tokens
82
+ router surface: ~972 tokens
83
+ best case: ~86,552 tokens saved (99%)
84
+
85
+ per harness (a session only ever runs in one):
86
+ codex still loaded ~35,500 → saves ~51,052 (58%)
87
+ claude, cursor, vscode: fully adopted → saves ~86,552 (99%)
79
88
 
80
89
  ## Not yet adopted
81
- claude
90
+ codex
82
91
  servers: project-tools, docs-search, issue-tracker
83
- plugins: ui-toolkit
84
- skills: code-review, incident-response
85
- → autorouter adopt --target claude
92
+ autorouter adopt --target codex
86
93
  ```
87
94
 
88
- That "still loaded direct" line is what adoption removes. Every removal is backed
89
- up verbatim to `~/.autorouter/adopted/` before anything is written;
95
+ "Still loaded" is what adoption removes, and it is reported per harness rather
96
+ than summed: a session runs in exactly one, so a server still registered in Codex
97
+ costs a Claude Code session nothing. Every removal is backed up verbatim to
98
+ `~/.autorouter/adopted/` before anything is written;
90
99
  `autorouter restore --target claude` puts it back byte for byte.
91
100
 
92
101
  ## How it finds things
@@ -169,12 +178,42 @@ when one of its capabilities is first called.
169
178
  | `skill` | `**/SKILL.md` under your skill paths and plugin `skills/` dirs |
170
179
  | `command`, `agent` | plugin `commands/*.md` and `agents/*.md` |
171
180
 
172
- Skills, commands and agents are also republished as [slash commands](#slash-commands).
181
+ Plugin commands and agents are also republished as [slash commands](#slash-commands);
182
+ skills are searchable but not republished by default, because the prompt list
183
+ that would carry them is permanent context — see [Slash commands](#slash-commands).
173
184
 
174
185
  Harness configs are imported rather than duplicated: `~/.claude.json` (global and
175
186
  per-project) and `.mcp.json`, `~/.codex/config.toml`, `~/.cursor/mcp.json`,
176
187
  `~/.vscode/mcp.json`, and installed Claude Code plugins.
177
188
 
189
+ ## Adding an MCP server
190
+
191
+ Register it with the router directly — it never enters anyone's context:
192
+
193
+ ```sh
194
+ autorouter add linear --url https://mcp.linear.app/mcp
195
+ autorouter add foo -- npx -y foo-mcp # stdio, like `claude mcp add`
196
+ autorouter add --json '{"mcpServers":{"linear":{"url":"…"}}}' # paste the vendor snippet
197
+ autorouter remove linear
198
+ ```
199
+
200
+ The entry is saved before the connection is checked, because the usual reason a
201
+ new server does not answer is that it has no OAuth grant yet — and
202
+ `autorouter login <name>` needs the entry to exist before it can authorize it.
203
+
204
+ **You can also just use the harness.** `claude mcp add foo …` still works: a
205
+ running router notices the harness config changed, moves the entry into its own
206
+ config with the usual backup, and tells you on the next search. So there is no
207
+ second command to remember, and no window where you have forgotten it and are
208
+ paying for that server's schemas on every turn. Set `"autoAdopt": false` to keep
209
+ adoption manual.
210
+
211
+ **From inside a session**, ask for it in words — the router exposes an
212
+ `add_server` tool. Registering a stdio server means this machine will run that
213
+ command from then on, so the first call only reports what would be registered;
214
+ it takes a second call with `confirm: true` to write anything. Set
215
+ `"allowAddServer": false` to withdraw the tool.
216
+
178
217
  ## Configuration
179
218
 
180
219
  `autorouter.json` — looked up at `$AUTOROUTER_CONFIG`, `./.autorouter.json`,
@@ -188,6 +227,10 @@ per-project) and `.mcp.json`, `~/.codex/config.toml`, `~/.cursor/mcp.json`,
188
227
  "exclude": ["media.generate_video"], // never surfaced at all
189
228
  "alwaysExpose": ["code-search.search"], // stays first-class, never adopted
190
229
  "confirm": ["database.execute_statement"], // first call is rejected, must re-issue
230
+ "autoAdopt": true, // move servers added to a harness behind the router
231
+ "allowAddServer": true, // expose the add_server tool to the model
232
+ "promptMode": "commands", // slash commands: "all" | "commands" | "none"
233
+ "activation": "lazy", // promote to a real tool: "eager" | "lazy" | "off"
191
234
  "selector": { "mode": "auto" },
192
235
  "embeddings": {
193
236
  "provider": "voyage",
@@ -198,7 +241,9 @@ per-project) and `.mcp.json`, `~/.codex/config.toml`, `~/.cursor/mcp.json`,
198
241
  ```
199
242
 
200
243
  Env overrides (`AUTOROUTER_IMPORT`, `AUTOROUTER_SELECTOR_MODEL`,
201
- `AUTOROUTER_SELECTOR_MODE`, `AUTOROUTER_EMBEDDINGS_PROVIDER`, …) let each harness
244
+ `AUTOROUTER_SELECTOR_MODE`, `AUTOROUTER_PROMPT_MODE`, `AUTOROUTER_ACTIVATION`,
245
+ `AUTOROUTER_AUTO_ADOPT`, `AUTOROUTER_ALLOW_ADD_SERVER`,
246
+ `AUTOROUTER_EMBEDDINGS_PROVIDER`, …) let each harness
202
247
  pin its own behaviour without a shared global file. `AUTOROUTER_HOME` redirects
203
248
  every home-relative path, for tests and containers.
204
249
 
@@ -206,15 +251,24 @@ every home-relative path, for tests and containers.
206
251
 
207
252
  Adopting a plugin into the router would otherwise cost you its slash commands:
208
253
  Claude Code reads `commands/*.md` off disk, and nothing over MCP can add to that
209
- list. What it _does_ surface as slash commands are MCP prompts, so every skill,
210
- plugin command and subagent in the catalog is republished as one:
254
+ list. What it _does_ surface as slash commands are MCP prompts, so the catalog's
255
+ plugin commands and subagents are republished as ones:
211
256
 
212
257
  ```
213
258
  /mcp__autorouter__find <what you want to do>
214
259
  /mcp__autorouter__plugin_name_command_name
215
- /mcp__autorouter__skill_name
216
260
  ```
217
261
 
262
+ **Skills are not republished by default** (`promptMode: "commands"`). The prompt
263
+ list is permanent context — the host fetches it once and carries it for the whole
264
+ session — and skills are the bulk of it: one plugin shipping 141 of them costs
265
+ ~11.5k tokens on every turn, which is more than adopting that plugin saves. The
266
+ alias is also mostly redundant, since `adopt --skill-mode user-invocable-only`
267
+ leaves a local skill's native `/name` working and a plugin's skills are surfaced
268
+ by the harness on demand rather than injected. Skills stay fully searchable
269
+ either way; set `"promptMode": "all"` to get `/mcp__autorouter__skill_name` back,
270
+ or `"none"` to publish only `find`.
271
+
218
272
  Bodies are substituted the way the native loader substitutes them — `$ARGUMENTS`
219
273
  for everything you typed, `$1`..`$9` positionally — so a command file written for
220
274
  Claude Code behaves identically through the router. `argument-hint` frontmatter
@@ -233,12 +287,18 @@ summary — the same information a native tool listing carries, because a trunca
233
287
  description leaves the model guessing argument names, and a guessed argument is
234
288
  the whole difference between roughly reliable and reliable.
235
289
 
236
- Better still, where the client honours `notifications/tools/list_changed`,
237
- `find_capabilities` **promotes** what it matched to real first-class tools. The
238
- model then makes an ordinary tool call: the host validates arguments against the
239
- real schema, the permission prompt names the real tool rather than
240
- `call_capability`, and the router is not in the execution path at all. It becomes
241
- a loader that decides what is in your tool list, not a middleman on every call.
290
+ Better still, where the client honours `notifications/tools/list_changed`, a tool
291
+ you **use** is **promoted** to a real first-class tool. From then on the model
292
+ makes an ordinary tool call: the host validates arguments against the real
293
+ schema, the permission prompt names the real tool rather than `call_capability`,
294
+ and the router is not in the execution path at all. It becomes a loader that
295
+ decides what is in your tool list, not a middleman on every call.
296
+
297
+ Promotion is deferred to the first successful call (`activation: "lazy"`) because
298
+ a promoted tool is permanent context and a search hit is not evidence of need —
299
+ most of what a search matches is never called. Set `"activation": "eager"` to
300
+ promote every hit as before, or `"off"` to route everything through
301
+ `call_capability` and carry no tool definitions at all.
242
302
 
243
303
  | supports `listChanged` | proxy only |
244
304
  | ----------------------------------------------- | ------------------------------------------------ |
@@ -261,13 +321,17 @@ the model happened to search for.
261
321
 
262
322
  | surface | budget | lifetime |
263
323
  | ------------------------- | --------------------------------- | ---------- |
264
- | promoted tool list | 3,000 tok, LRU eviction | session |
265
- | inline schemas per search | 700 tok, spent top-down | one result |
266
- | prompt list | descriptions clamped to 180 chars | session |
324
+ | promoted tool list | 3,000 tok, LRU eviction, on use only | session |
325
+ | inline schemas per search | 700 tok, spent top-down | one result |
326
+ | prompt list | commands only, clamped to 120 chars | session |
267
327
 
268
- Tools promoted by the search in flight are never evicted — a tool that vanishes
328
+ The tool promoted by the call in flight is never evicted — a tool that vanishes
269
329
  between being offered and being called is worse than one never offered.
270
330
 
331
+ `autorouter doctor` reports the real bill per harness rather than summing across
332
+ them, since a session only ever runs in one: a server still registered in Cursor
333
+ costs a Claude Code session nothing.
334
+
271
335
  Schemas are **compacted** everywhere they are repeated: `$schema`, `title` and
272
336
  `examples` are dropped, and prose is trimmed, more aggressively the deeper it
273
337
  sits. Every structural field survives untouched — names, types, enums, `required`,
@@ -291,6 +355,10 @@ autorouter list --kind skill
291
355
  autorouter doctor
292
356
  autorouter reindex
293
357
 
358
+ autorouter add linear --url https://mcp.linear.app/mcp
359
+ autorouter add foo -- npx -y foo-mcp
360
+ autorouter remove linear
361
+
294
362
  autorouter adopt --target claude --dry-run # preview, change nothing
295
363
  autorouter adopt --target claude --servers-only # skip skills and plugins
296
364
  autorouter adopt --target claude --keep project-tools --keep-plugin ui-toolkit