@ken-jo/agent-connector 0.4.91 → 0.4.92
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.
- package/README.md +301 -560
- package/dist/{action-L44DXFHT.js → action-CVIEPX4U.js} +14 -14
- package/dist/{amazon-q-B52EY2SV.js → amazon-q-TIT7FIW3.js} +5 -5
- package/dist/{amp-UXABVUKC.js → amp-NF3OAAUG.js} +5 -5
- package/dist/{antigravity-RZHN53VB.js → antigravity-7LPK7QOY.js} +6 -6
- package/dist/{antigravity-cli-JO6GUTV7.js → antigravity-cli-MDEMPPAH.js} +47 -16
- package/dist/antigravity-cli-MDEMPPAH.js.map +1 -0
- package/dist/{chunk-QKLJU4JX.js → chunk-2Y2MZRLP.js} +56 -2
- package/dist/chunk-2Y2MZRLP.js.map +1 -0
- package/dist/{chunk-UBB7T54N.js → chunk-3C5AASHM.js} +3 -3
- package/dist/{chunk-BLTVZACS.js → chunk-447JWFZO.js} +9 -9
- package/dist/{chunk-HORHRHNG.js → chunk-4NHXLXSD.js} +2 -2
- package/dist/chunk-5Z36KVU2.js +590 -0
- package/dist/chunk-5Z36KVU2.js.map +1 -0
- package/dist/{chunk-AY3RGRTT.js → chunk-6TF7MHG5.js} +2 -2
- package/dist/{chunk-R6LML2YS.js → chunk-7UT6OB52.js} +2 -2
- package/dist/{chunk-G4CEELKO.js → chunk-AY3VFNOH.js} +5 -5
- package/dist/{chunk-4HVQ7IUM.js → chunk-DI5S6TXJ.js} +17 -4
- package/dist/chunk-DI5S6TXJ.js.map +1 -0
- package/dist/{chunk-LAIITCMW.js → chunk-FBCBHEGB.js} +5 -5
- package/dist/{chunk-4NSU3KWX.js → chunk-FJCUKXGX.js} +2 -2
- package/dist/{chunk-ZMLVR4J7.js → chunk-FO5CEXXN.js} +2 -2
- package/dist/{chunk-IXOQDZWC.js → chunk-GZGLCCEE.js} +5 -1
- package/dist/chunk-GZGLCCEE.js.map +1 -0
- package/dist/{chunk-LF76VPGQ.js → chunk-IBLYVAWH.js} +28 -6
- package/dist/chunk-IBLYVAWH.js.map +1 -0
- package/dist/{chunk-4FWETID5.js → chunk-IVAWP6HH.js} +2 -2
- package/dist/{chunk-NBUEL74R.js → chunk-JFXL4HYA.js} +3 -3
- package/dist/{chunk-KIRCPLM4.js → chunk-JO2IM2JL.js} +538 -226
- package/dist/chunk-JO2IM2JL.js.map +1 -0
- package/dist/{chunk-NWLRJNXM.js → chunk-JVO6NBTT.js} +3 -3
- package/dist/{chunk-25CPWJA7.js → chunk-KA55FISM.js} +43 -43
- package/dist/{chunk-QARPXSIV.js → chunk-L26PSQTY.js} +4 -4
- package/dist/{chunk-YYNXIUR2.js → chunk-M2H7JURF.js} +2 -2
- package/dist/{chunk-56R2ER7K.js → chunk-NBYKLUF6.js} +2 -2
- package/dist/{chunk-VVFDU4IX.js → chunk-WFEHWTLM.js} +12 -5
- package/dist/{chunk-VVFDU4IX.js.map → chunk-WFEHWTLM.js.map} +1 -1
- package/dist/{chunk-LN76OGNR.js → chunk-Z2MRSS2I.js} +2 -2
- package/dist/{claude-code-WS4NAGZT.js → claude-code-7RS4YVGZ.js} +9 -9
- package/dist/cli/sdk.js +7 -7
- package/dist/cli.js +1 -1
- package/dist/{cline-NNMVCECA.js → cline-BZQAUYPC.js} +5 -5
- package/dist/{codebuddy-RBEZGXBG.js → codebuddy-G42IKGKB.js} +5 -5
- package/dist/{codebuff-RJIDSEU3.js → codebuff-5RLTLZAU.js} +5 -5
- package/dist/{codex-ZZ434GYR.js → codex-XHAMJILX.js} +11 -5
- package/dist/{codex-ZZ434GYR.js.map → codex-XHAMJILX.js.map} +1 -1
- package/dist/{continue-MNM7YVJY.js → continue-JLIB7R7X.js} +6 -6
- package/dist/{copilot-cli-SMTX5F65.js → copilot-cli-XZSUYNQZ.js} +5 -5
- package/dist/{crush-NYDBHIJE.js → crush-ESERLVLT.js} +5 -5
- package/dist/{cursor-AOELDNZU.js → cursor-FUDOV5VK.js} +6 -6
- package/dist/{detect-3S46RUMK.js → detect-Z5BDTY6B.js} +4 -4
- package/dist/{devin-PRJY2TTD.js → devin-Y7PWKVHY.js} +5 -5
- package/dist/{doctor-3CUBPQKU.js → doctor-GAP27PP2.js} +25 -21
- package/dist/doctor-GAP27PP2.js.map +1 -0
- package/dist/{droid-PTCH2K7Y.js → droid-DTO5POTK.js} +5 -5
- package/dist/{gemini-cli-QGLN2UMS.js → gemini-cli-RBIG6U2F.js} +5 -5
- package/dist/{goose-DQ6GSZ5O.js → goose-VGNOP5J2.js} +6 -6
- package/dist/{grok-cli-5QD235UB.js → grok-cli-2RFBK6J3.js} +5 -5
- package/dist/{hermes-E47IG63A.js → hermes-NUKFWZI5.js} +6 -6
- package/dist/{hook-P6EKDINW.js → hook-XPR3AHDI.js} +14 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/install-O32TDIZP.js +382 -0
- package/dist/install-O32TDIZP.js.map +1 -0
- package/dist/{introspect-DYOIX8Ov.d.ts → introspect-BkId4LGP.d.ts} +1 -1
- package/dist/{jetbrains-copilot-T2EPKROP.js → jetbrains-copilot-FXZ5AOTS.js} +23 -7
- package/dist/jetbrains-copilot-FXZ5AOTS.js.map +1 -0
- package/dist/{junie-SQ4SDLGK.js → junie-TSXIZSCE.js} +5 -5
- package/dist/{kilo-OU2ZLZKB.js → kilo-JLH3KVZJ.js} +5 -5
- package/dist/{kilo-cli-NMWGYF4F.js → kilo-cli-5W36VJQZ.js} +5 -5
- package/dist/{kimi-Z7L2LEEI.js → kimi-R62W7HKZ.js} +5 -5
- package/dist/{kiro-4IN5IH46.js → kiro-AUJMGIBL.js} +5 -5
- package/dist/{leaderboard-LF5SP6X2.js → leaderboard-YWMOSJBC.js} +5 -5
- package/dist/{mimo-code-G2CBZ4M6.js → mimo-code-PGLFFVER.js} +5 -5
- package/dist/{mistral-vibe-TRQDHAWV.js → mistral-vibe-36CZVQNQ.js} +5 -5
- package/dist/{mux-JNM3F2NW.js → mux-HWL4N5KH.js} +5 -5
- package/dist/{nemoclaw-SHA4IUML.js → nemoclaw-QPHETUXM.js} +6 -6
- package/dist/{omp-OOVUNXME.js → omp-3TFMTJ5U.js} +5 -5
- package/dist/{open-interpreter-4PKL56AA.js → open-interpreter-UTBKE2EH.js} +5 -5
- package/dist/openclaw-RYFO5TLY.js +17 -0
- package/dist/{opencode-W2RK4M7G.js → opencode-JX7GBE5Q.js} +5 -5
- package/dist/{openhands-5LNH3BKB.js → openhands-AZW4PXJ3.js} +5 -5
- package/dist/{package-2EAIYSJ4.js → package-2KKUGZFS.js} +12 -12
- package/dist/{pi-BUADR5MJ.js → pi-MRI3EBWU.js} +5 -5
- package/dist/{qwen-code-TUJNHKNI.js → qwen-code-ISR6BEET.js} +6 -6
- package/dist/{roo-code-L5F7S6QH.js → roo-code-6TSCME4R.js} +5 -5
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +12 -12
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +10 -10
- package/dist/{serve-K62FW3V7.js → serve-EPRN7F2X.js} +14 -14
- package/dist/{status-E5MCFZM6.js → status-B2PG6YKR.js} +10 -10
- package/dist/{statusline-LIPF2KVP.js → statusline-5ERFMYSM.js} +13 -13
- package/dist/{telemetry-4OC56NTM.js → telemetry-ZMCAWBWB.js} +10 -10
- package/dist/{trae-Z7CQ2A2Q.js → trae-7KDCYIMN.js} +5 -5
- package/dist/{types-C4qMgbJn.d.ts → types-D0RqWxT8.d.ts} +43 -0
- package/dist/{uninstall-2YYKN5DX.js → uninstall-M76BHLTH.js} +35 -25
- package/dist/uninstall-M76BHLTH.js.map +1 -0
- package/dist/{upgrade-55AFPJEF.js → upgrade-JLSCNAQA.js} +23 -17
- package/dist/upgrade-JLSCNAQA.js.map +1 -0
- package/dist/{usage-3PB3WZSL.js → usage-5I72HWCR.js} +2 -2
- package/dist/{usage-event-KD5FW6W4.js → usage-event-HIX4ZI45.js} +13 -13
- package/dist/{vscode-copilot-LU5NC4ZS.js → vscode-copilot-LILHAPJI.js} +20 -5
- package/dist/vscode-copilot-LILHAPJI.js.map +1 -0
- package/dist/{warp-4PPG5LOM.js → warp-KJUCWEA3.js} +5 -5
- package/dist/{windsurf-3T3RVXKM.js → windsurf-5TGGQR5I.js} +5 -5
- package/dist/{zed-ZF2OQ75O.js → zed-EL3JCZ25.js} +5 -5
- package/package.json +1 -1
- package/dist/antigravity-cli-JO6GUTV7.js.map +0 -1
- package/dist/chunk-4HVQ7IUM.js.map +0 -1
- package/dist/chunk-7HUUINPB.js +0 -201
- package/dist/chunk-7HUUINPB.js.map +0 -1
- package/dist/chunk-IXOQDZWC.js.map +0 -1
- package/dist/chunk-KIRCPLM4.js.map +0 -1
- package/dist/chunk-LF76VPGQ.js.map +0 -1
- package/dist/chunk-QKLJU4JX.js.map +0 -1
- package/dist/doctor-3CUBPQKU.js.map +0 -1
- package/dist/install-7DMK53SB.js +0 -96
- package/dist/install-7DMK53SB.js.map +0 -1
- package/dist/jetbrains-copilot-T2EPKROP.js.map +0 -1
- package/dist/openclaw-BD56E5MV.js +0 -17
- package/dist/uninstall-2YYKN5DX.js.map +0 -1
- package/dist/upgrade-55AFPJEF.js.map +0 -1
- package/dist/vscode-copilot-LU5NC4ZS.js.map +0 -1
- /package/dist/{action-L44DXFHT.js.map → action-CVIEPX4U.js.map} +0 -0
- /package/dist/{amazon-q-B52EY2SV.js.map → amazon-q-TIT7FIW3.js.map} +0 -0
- /package/dist/{amp-UXABVUKC.js.map → amp-NF3OAAUG.js.map} +0 -0
- /package/dist/{antigravity-RZHN53VB.js.map → antigravity-7LPK7QOY.js.map} +0 -0
- /package/dist/{chunk-UBB7T54N.js.map → chunk-3C5AASHM.js.map} +0 -0
- /package/dist/{chunk-BLTVZACS.js.map → chunk-447JWFZO.js.map} +0 -0
- /package/dist/{chunk-HORHRHNG.js.map → chunk-4NHXLXSD.js.map} +0 -0
- /package/dist/{chunk-AY3RGRTT.js.map → chunk-6TF7MHG5.js.map} +0 -0
- /package/dist/{chunk-R6LML2YS.js.map → chunk-7UT6OB52.js.map} +0 -0
- /package/dist/{chunk-G4CEELKO.js.map → chunk-AY3VFNOH.js.map} +0 -0
- /package/dist/{chunk-LAIITCMW.js.map → chunk-FBCBHEGB.js.map} +0 -0
- /package/dist/{chunk-4NSU3KWX.js.map → chunk-FJCUKXGX.js.map} +0 -0
- /package/dist/{chunk-ZMLVR4J7.js.map → chunk-FO5CEXXN.js.map} +0 -0
- /package/dist/{chunk-4FWETID5.js.map → chunk-IVAWP6HH.js.map} +0 -0
- /package/dist/{chunk-NBUEL74R.js.map → chunk-JFXL4HYA.js.map} +0 -0
- /package/dist/{chunk-NWLRJNXM.js.map → chunk-JVO6NBTT.js.map} +0 -0
- /package/dist/{chunk-25CPWJA7.js.map → chunk-KA55FISM.js.map} +0 -0
- /package/dist/{chunk-QARPXSIV.js.map → chunk-L26PSQTY.js.map} +0 -0
- /package/dist/{chunk-YYNXIUR2.js.map → chunk-M2H7JURF.js.map} +0 -0
- /package/dist/{chunk-56R2ER7K.js.map → chunk-NBYKLUF6.js.map} +0 -0
- /package/dist/{chunk-LN76OGNR.js.map → chunk-Z2MRSS2I.js.map} +0 -0
- /package/dist/{claude-code-WS4NAGZT.js.map → claude-code-7RS4YVGZ.js.map} +0 -0
- /package/dist/{cline-NNMVCECA.js.map → cline-BZQAUYPC.js.map} +0 -0
- /package/dist/{codebuddy-RBEZGXBG.js.map → codebuddy-G42IKGKB.js.map} +0 -0
- /package/dist/{codebuff-RJIDSEU3.js.map → codebuff-5RLTLZAU.js.map} +0 -0
- /package/dist/{continue-MNM7YVJY.js.map → continue-JLIB7R7X.js.map} +0 -0
- /package/dist/{copilot-cli-SMTX5F65.js.map → copilot-cli-XZSUYNQZ.js.map} +0 -0
- /package/dist/{crush-NYDBHIJE.js.map → crush-ESERLVLT.js.map} +0 -0
- /package/dist/{cursor-AOELDNZU.js.map → cursor-FUDOV5VK.js.map} +0 -0
- /package/dist/{detect-3S46RUMK.js.map → detect-Z5BDTY6B.js.map} +0 -0
- /package/dist/{devin-PRJY2TTD.js.map → devin-Y7PWKVHY.js.map} +0 -0
- /package/dist/{droid-PTCH2K7Y.js.map → droid-DTO5POTK.js.map} +0 -0
- /package/dist/{gemini-cli-QGLN2UMS.js.map → gemini-cli-RBIG6U2F.js.map} +0 -0
- /package/dist/{goose-DQ6GSZ5O.js.map → goose-VGNOP5J2.js.map} +0 -0
- /package/dist/{grok-cli-5QD235UB.js.map → grok-cli-2RFBK6J3.js.map} +0 -0
- /package/dist/{hermes-E47IG63A.js.map → hermes-NUKFWZI5.js.map} +0 -0
- /package/dist/{hook-P6EKDINW.js.map → hook-XPR3AHDI.js.map} +0 -0
- /package/dist/{junie-SQ4SDLGK.js.map → junie-TSXIZSCE.js.map} +0 -0
- /package/dist/{kilo-OU2ZLZKB.js.map → kilo-JLH3KVZJ.js.map} +0 -0
- /package/dist/{kilo-cli-NMWGYF4F.js.map → kilo-cli-5W36VJQZ.js.map} +0 -0
- /package/dist/{kimi-Z7L2LEEI.js.map → kimi-R62W7HKZ.js.map} +0 -0
- /package/dist/{kiro-4IN5IH46.js.map → kiro-AUJMGIBL.js.map} +0 -0
- /package/dist/{leaderboard-LF5SP6X2.js.map → leaderboard-YWMOSJBC.js.map} +0 -0
- /package/dist/{mimo-code-G2CBZ4M6.js.map → mimo-code-PGLFFVER.js.map} +0 -0
- /package/dist/{mistral-vibe-TRQDHAWV.js.map → mistral-vibe-36CZVQNQ.js.map} +0 -0
- /package/dist/{mux-JNM3F2NW.js.map → mux-HWL4N5KH.js.map} +0 -0
- /package/dist/{nemoclaw-SHA4IUML.js.map → nemoclaw-QPHETUXM.js.map} +0 -0
- /package/dist/{omp-OOVUNXME.js.map → omp-3TFMTJ5U.js.map} +0 -0
- /package/dist/{open-interpreter-4PKL56AA.js.map → open-interpreter-UTBKE2EH.js.map} +0 -0
- /package/dist/{openclaw-BD56E5MV.js.map → openclaw-RYFO5TLY.js.map} +0 -0
- /package/dist/{opencode-W2RK4M7G.js.map → opencode-JX7GBE5Q.js.map} +0 -0
- /package/dist/{openhands-5LNH3BKB.js.map → openhands-AZW4PXJ3.js.map} +0 -0
- /package/dist/{package-2EAIYSJ4.js.map → package-2KKUGZFS.js.map} +0 -0
- /package/dist/{pi-BUADR5MJ.js.map → pi-MRI3EBWU.js.map} +0 -0
- /package/dist/{qwen-code-TUJNHKNI.js.map → qwen-code-ISR6BEET.js.map} +0 -0
- /package/dist/{roo-code-L5F7S6QH.js.map → roo-code-6TSCME4R.js.map} +0 -0
- /package/dist/{serve-K62FW3V7.js.map → serve-EPRN7F2X.js.map} +0 -0
- /package/dist/{status-E5MCFZM6.js.map → status-B2PG6YKR.js.map} +0 -0
- /package/dist/{statusline-LIPF2KVP.js.map → statusline-5ERFMYSM.js.map} +0 -0
- /package/dist/{telemetry-4OC56NTM.js.map → telemetry-ZMCAWBWB.js.map} +0 -0
- /package/dist/{trae-Z7CQ2A2Q.js.map → trae-7KDCYIMN.js.map} +0 -0
- /package/dist/{usage-3PB3WZSL.js.map → usage-5I72HWCR.js.map} +0 -0
- /package/dist/{usage-event-KD5FW6W4.js.map → usage-event-HIX4ZI45.js.map} +0 -0
- /package/dist/{warp-4PPG5LOM.js.map → warp-KJUCWEA3.js.map} +0 -0
- /package/dist/{windsurf-3T3RVXKM.js.map → windsurf-5TGGQR5I.js.map} +0 -0
- /package/dist/{zed-ZF2OQ75O.js.map → zed-EL3JCZ25.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,248 +1,176 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="site/public/mascot.png" alt="agent-connector mascot — a pixel-art lobster worker in a tool belt" width="160" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# agent-connector
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
### Deploy one MCP to every agent CLI.
|
|
8
|
+
|
|
9
|
+
Write your server + hooks once with `defineConnector()`, then `install` it into
|
|
10
|
+
the native config — or `package` it as a real plugin — across **42 agent CLIs**
|
|
11
|
+
(Claude Code, Codex, Cursor, Copilot, Gemini, OpenCode, Warp, Zed…).
|
|
8
12
|
|
|
9
13
|
[](https://www.npmjs.com/package/@ken-jo/agent-connector)
|
|
10
14
|
[](LICENSE)
|
|
11
15
|

|
|
12
16
|

|
|
13
17
|

|
|
14
|
-

|
|
15
19
|

|
|
16
|
-

|
|
17
21
|

|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
>
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
install flows, then chasing each platform's quirks.
|
|
44
|
-
|
|
45
|
-
agent-connector is the middleware that does it for you:
|
|
46
|
-
|
|
47
|
-
1. **One API, every platform.** Declare your server + hooks once with
|
|
48
|
-
`defineConnector({...})`; the CLI detects every installed host and renders the
|
|
49
|
-
right native config in each — install, uninstall, upgrade, doctor.
|
|
50
|
-
2. **Token telemetry, by default.** No host reports per-tool usage back to an MCP
|
|
51
|
-
server. agent-connector measures your server's *own* bytes (args in, results
|
|
52
|
-
out, tool schemas) and tokenizes them locally — so you get a
|
|
53
|
-
platform-independent answer to *"which of **your server's own tools** (the MCP
|
|
54
|
-
your connector declares and wraps) cost the most context?"*, with **aggregate
|
|
55
|
-
counts only, stored locally, zero egress by default.** Per-tool telemetry is
|
|
56
|
-
automatic for **stdio** servers only; remote (`http`/`sse`/`ws`) servers are
|
|
57
|
-
registered but **not wrapped** (the proxy cannot intercept remote transports),
|
|
58
|
-
so they yield no per-tool telemetry.
|
|
59
|
-
|
|
60
|
-
> Status: **35 platforms, all 3 hook paradigms** (exceeds the
|
|
61
|
-
> [tokscale](https://github.com/junhoyeo/tokscale) token-leaderboard coverage).
|
|
62
|
-
>
|
|
63
|
-
> | Paradigm | Platforms |
|
|
64
|
-
> |---|---|
|
|
65
|
-
> | `json-stdio` (full hook dispatch) | CodeBuddy · Claude Code · Codex CLI · Cursor · VS Code Copilot · JetBrains Copilot · GitHub Copilot CLI · Gemini CLI · Qwen CLI · Kiro · Kimi CLI · Crush · Goose · Hermes · Droid (Factory) · OpenHands · Antigravity · Antigravity CLI · Continue · Amazon Q · Grok CLI · Devin CLI |
|
|
66
|
-
> | `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
|
|
67
|
-
> | `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
|
|
68
|
-
>
|
|
69
|
-
> …plus the telemetry core. Adding a platform = **one registry entry + one
|
|
70
|
-
> adapter**. (Google Antigravity is now fully supported, including the `agy` CLI,
|
|
71
|
-
> as Gemini CLI sunsets.) See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
72
|
-
|
|
73
|
-
## Verification
|
|
74
|
-
|
|
75
|
-
The full single-API contract is **install-verified across the platform set**. A
|
|
76
|
-
sample connector declaring **all four launch surfaces** — MCP server **+**
|
|
77
|
-
lifecycle hooks **+** slash commands **+** tools (skills + subagents) — was
|
|
78
|
-
installed into an isolated environment for every adapter and inspected on disk
|
|
79
|
-
(the full 35-platform sweep below — now locked by a committed registry-driven
|
|
80
|
-
install-roundtrip harness that, for every adapter, drives the real install →
|
|
81
|
-
uninstall into an isolated HOME and asserts on-disk placement + zero residue):
|
|
82
|
-
|
|
83
|
-
- **35 / 35 platforms — zero missing, zero failed surfaces.** Each surface is
|
|
84
|
-
written where the host supports it and gracefully *skip-warned* (never silently
|
|
85
|
-
dropped) where it does not, across all three hook paradigms — JSON/TOML/YAML
|
|
86
|
-
hook entries (`json-stdio`), synthesized + registered plugin modules
|
|
87
|
-
(`ts-plugin`), and MCP-only graceful degradation.
|
|
88
|
-
- **Live hook dispatch + telemetry, proven end-to-end.** Hooks fire with the
|
|
89
|
-
correct allow / deny / context decisions through the universal entrypoint, and
|
|
90
|
-
the telemetry serve-proxy records per-MCP token usage in vivo — both the
|
|
91
|
-
🔌 MCP/plugin and 🖥️ host/user leaderboards verified against real CLI logs.
|
|
92
|
-
- **Runtime-activated, headlessly — 10 real host CLIs.** **Claude Code · Codex ·
|
|
93
|
-
OpenCode · Kilo CLI · OpenClaw · qwen-code · Hermes · Gemini CLI · GitHub
|
|
94
|
-
Copilot CLI · Antigravity CLI (agy)** each genuinely loaded the config, spawned
|
|
95
|
-
our telemetry serve-wrapper, completed the MCP handshake, and were captured *in
|
|
96
|
-
vivo* by our own telemetry store. Most via their own `mcp list`/`reconnect` handshake with
|
|
97
|
-
no API key, login, or model turn; Codex, Gemini CLI & Copilot CLI on real
|
|
98
|
-
logged-in sessions (Codex/Gemini recorded actual tool-call rows). Each row now
|
|
99
|
-
carries the correct `hostPlatform` (the install target is baked into the
|
|
100
|
-
wrapper as `--host`). Kimi also spawned the server (its probe tears the pipe
|
|
101
|
-
down before the row flushes).
|
|
102
|
-
- **Committed live host-CLI driver — 20 real CLIs.** A reusable
|
|
103
|
-
`scripts/verify-host.mjs` installs each host's actual binary into an isolated
|
|
104
|
-
HOME and verifies install → placement → clean-uninstall: **12 confirm offline
|
|
105
|
-
config-acceptance** (Codex · Gemini CLI · Copilot CLI · Antigravity CLI · Amp ·
|
|
106
|
-
qwen-code · Droid · Cursor · Kimi + OpenCode · Kilo CLI · MiMoCode) and **3 of
|
|
107
|
-
those fire a live hook** (OpenCode · Kilo CLI · MiMoCode → handler ran to our
|
|
108
|
-
event log); the other 8 (Claude Code · Codebuff · Crush · Continue · OpenClaw ·
|
|
109
|
-
Goose · Amazon Q · OMP) reach install-placement + clean-uninstall. So amp,
|
|
110
|
-
goose, codebuff & omp — previously config-write-only — are now exercised
|
|
111
|
-
against their real CLIs. The remaining 15 hosts (IDE extensions / GUI editors,
|
|
112
|
-
no headless CLI) stay covered by the install-roundtrip harness above.
|
|
113
|
-
- **Clean uninstall + `--purge`.** Every installed surface reverses; `--purge`
|
|
114
|
-
deregisters the connector record and tears down the home binary when no
|
|
115
|
-
connectors remain (35 / 35).
|
|
116
|
-
- **Full `npm test` suite passing** · `tsc` clean · build green.
|
|
117
|
-
|
|
118
|
-
The 0.2.0 additions — the `memory` surface, the `nativeHooks` passthrough, and
|
|
119
|
-
`configPatch` — went through the same bar: dogfooded against real connector
|
|
120
|
-
migrations (context-mode, oh-my-claudecode) and verified in isolated-home
|
|
121
|
-
installs before landing (see [`CHANGELOG.md`](CHANGELOG.md)).
|
|
122
|
-
|
|
123
|
-
**Dogfood result:** the context-mode connector migration — porting a real
|
|
124
|
-
multi-host plugin to `defineConnector` — collapsed **~20,322 lines of
|
|
125
|
-
hand-maintained per-host code down to ~76 lines** (a 99.63% reduction). The
|
|
126
|
-
other hand-maintained surfaces — MCP registration, hook entries, memory files —
|
|
127
|
-
dissolved into the same single config declaration.
|
|
128
|
-
|
|
129
|
-
Coverage was confirmed by **installing the real, not-yet-present agent CLIs into
|
|
130
|
-
isolated homes and observing their actual config** — which caught defects a
|
|
131
|
-
static code/web audit missed. See the reports under
|
|
132
|
-
[`docs/research/`](docs/research/).
|
|
23
|
+
**Two audiences:** connector developers start at [Quick start](#quick-start);
|
|
24
|
+
if you already run an agent CLI and just want token totals, jump straight to
|
|
25
|
+
[`usage`](#token-telemetry--usage).
|
|
26
|
+
|
|
27
|
+
- [Quick start](#quick-start) — depend on the SDK, declare a connector, install it
|
|
28
|
+
- [Ship it](#ship-it-direct-install-or-a-marketplace-plugin) — direct install or a marketplace plugin
|
|
29
|
+
- [What you define once](#what-you-define-once) — server, hooks, and the other surfaces
|
|
30
|
+
- [How it works](#how-it-works) — single home binary, per-project data, hook paradigms
|
|
31
|
+
- [CLI](#cli) — every command at a glance
|
|
32
|
+
- [Token telemetry & usage](#token-telemetry--usage) — per-tool telemetry vs. connector-free `usage`
|
|
33
|
+
- [Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem) — emit the official MCP standard artifacts
|
|
34
|
+
- [Verification](#verification) — how the 42-platform contract is proven
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<a href="examples/showcase-demo/">
|
|
38
|
+
<img src="examples/showcase-demo/demo.gif" width="820"
|
|
39
|
+
alt="agent-connector showcase: define a connector once, ship it as your own branded CLI, install it via each host's native marketplace, and drive every CLI with one command." />
|
|
40
|
+
</a>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center"><sub>
|
|
44
|
+
Define once → ship it as your own branded CLI → users install via their host's native marketplace → one command drives every CLI.
|
|
45
|
+
<a href="examples/showcase-demo/">Regenerate this demo.</a>
|
|
46
|
+
</sub></p>
|
|
133
47
|
|
|
134
48
|
## Quick start
|
|
135
49
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
### Agent-CLI end user
|
|
142
|
-
|
|
143
|
-
> **Audience B** — you already run agent CLIs (Claude Code / Codex / Cursor / …)
|
|
144
|
-
> and have **not** authored a connector. You just want to know how many tokens
|
|
145
|
-
> your agent CLIs are burning.
|
|
50
|
+
agent-connector is an **SDK you depend on**, not a global tool. Add it to the
|
|
51
|
+
package that holds your connector, declare the connector once, then `install` —
|
|
52
|
+
it deploys to every detected agent CLI in that host's own native config. The
|
|
53
|
+
linear path is: **get a server → declare it → install**.
|
|
146
54
|
|
|
147
|
-
**
|
|
148
|
-
|
|
149
|
-
|
|
55
|
+
**0. You need an MCP server file first.** The config below points at
|
|
56
|
+
`./my-mcp-server.mjs`, so that file must exist before you install. Don't have an
|
|
57
|
+
MCP server yet? Copy
|
|
58
|
+
[`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
|
|
59
|
+
(a self-contained ~35-line stub) as `./my-mcp-server.mjs`, or follow the
|
|
60
|
+
[official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server).
|
|
150
61
|
|
|
151
62
|
```bash
|
|
152
|
-
#
|
|
153
|
-
|
|
63
|
+
# 1. add agent-connector as a DEPENDENCY of your connector package
|
|
64
|
+
npm install @ken-jo/agent-connector
|
|
65
|
+
```
|
|
154
66
|
|
|
155
|
-
|
|
156
|
-
|
|
67
|
+
```js
|
|
68
|
+
// 2. agent-connector.config.mjs — declare your server + hooks once
|
|
69
|
+
import { fileURLToPath } from "node:url";
|
|
70
|
+
import { defineConnector } from "@ken-jo/agent-connector";
|
|
157
71
|
|
|
158
|
-
|
|
159
|
-
npx @ken-jo/agent-connector usage export --format csv --out usage.csv
|
|
160
|
-
```
|
|
72
|
+
const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
|
|
161
73
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
> antigravity-cli, trae, warp** — are reported as skipped (`requires sync — no
|
|
173
|
-
> local cache found`) unless a local cache already exists, since agent-connector
|
|
174
|
-
> does not populate that cache.
|
|
175
|
-
|
|
176
|
-
> **That's the entire agent-CLI track.** Everything below this point is the
|
|
177
|
-
> MCP-developer track. ([back to top](#agent-connector))
|
|
178
|
-
|
|
179
|
-
### MCP developer
|
|
180
|
-
|
|
181
|
-
> **Audience A** — you write an MCP server + hooks once and deploy them across
|
|
182
|
-
> every detected host, measuring **your own server's** per-tool tokens.
|
|
183
|
-
|
|
184
|
-
**Step 0 — write your MCP server.** agent-connector deploys and wraps an MCP
|
|
185
|
-
server you already have (or are about to write). If you haven't built one yet,
|
|
186
|
-
the [official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server)
|
|
187
|
-
is the fastest on-ramp — pick your language, follow the tutorial, and come back
|
|
188
|
-
with a working stdio server binary or script. The
|
|
189
|
-
[`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
|
|
190
|
-
in this repo is a self-contained ~35-line stub you can copy as a template.
|
|
74
|
+
export default defineConnector({
|
|
75
|
+
id: "acme-db",
|
|
76
|
+
server: {
|
|
77
|
+
transport: "stdio",
|
|
78
|
+
command: "node",
|
|
79
|
+
args: [serverPath],
|
|
80
|
+
},
|
|
81
|
+
// hooks, telemetry, and more surfaces — see "What you define once" below
|
|
82
|
+
});
|
|
83
|
+
```
|
|
191
84
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
85
|
+
> While developing, `server.command` can be `node` + a local file path (as
|
|
86
|
+
> above); once your server is a published package, switch to `npx` + the package
|
|
87
|
+
> name (`command: "npx", args: ["-y", "@acme/acme-db-mcp"]`) — the form the
|
|
88
|
+
> [site quick-start](https://agent-connector.ai) teaches.
|
|
196
89
|
|
|
197
90
|
```bash
|
|
198
|
-
#
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
# 3a. ship a branded CLI so YOUR users drive it (auto-scoped — no --connector):
|
|
204
|
-
acme-db detect # which platforms are installed here?
|
|
205
|
-
acme-db install --dry-run # preview every change across the detected hosts
|
|
206
|
-
acme-db install # deploy across the hosts detected on this machine
|
|
207
|
-
acme-db doctor # health-check every detected platform — add --probe for a live MCP handshake (initialize → ping → tools/list)
|
|
208
|
-
acme-db upgrade # day 2: re-render configs + heal the home-binary pointer (aliases: sync, update)
|
|
209
|
-
acme-db leaderboard # acme-db's token footprint vs the boards
|
|
210
|
-
acme-db package # OR distribute: marketplace plugin (9 formats) — or --format mcp-server-json | mcpb for the MCP Registry / an MCPB bundle (see "Publish to the MCP ecosystem")
|
|
211
|
-
acme-db uninstall # full inverse — removes everything install wrote; --purge clears framework state; --dry-run works here too
|
|
212
|
-
|
|
213
|
-
# 3b. …or just run it from the project with npx — still no global install:
|
|
214
|
-
npx @ken-jo/agent-connector detect
|
|
215
|
-
npx @ken-jo/agent-connector install
|
|
91
|
+
# 3. deploy across the agent CLIs detected on this machine
|
|
92
|
+
npx @ken-jo/agent-connector detect # which platforms are installed here?
|
|
93
|
+
npx @ken-jo/agent-connector install --dry-run # preview every change first
|
|
94
|
+
npx @ken-jo/agent-connector install # write native config in each host
|
|
216
95
|
```
|
|
217
96
|
|
|
218
97
|
> `install` targets only the hosts actually **detected** on this machine (or an
|
|
219
98
|
> explicit `--targets` / `connector.targets` list), intersected with the
|
|
220
|
-
>
|
|
99
|
+
> 42-adapter registry — there is no "install to all 42 unconditionally" path.
|
|
100
|
+
> A global `npm i -g` is **not** required: `npx @ken-jo/agent-connector …` runs
|
|
101
|
+
> straight from your project.
|
|
221
102
|
|
|
222
|
-
|
|
223
|
-
> required for the flow above — `npx @ken-jo/agent-connector …` runs it straight from
|
|
224
|
-
> your project. Install it globally only if you want to poke at the CLI by hand
|
|
225
|
-
> outside any connector package.
|
|
103
|
+
## Ship it: direct install or a marketplace plugin
|
|
226
104
|
|
|
227
|
-
|
|
105
|
+
Same one definition, your choice of distribution.
|
|
228
106
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
107
|
+
**Direct install** — `agent-connector install` writes each host's native MCP +
|
|
108
|
+
hook + content-surface config in place, with no per-platform marketplace
|
|
109
|
+
submission or review. This is the Quick start path above.
|
|
110
|
+
|
|
111
|
+
**Marketplace plugin** — `agent-connector package` turns the connector into a
|
|
112
|
+
real plugin/extension bundle (manifest + bundled commands, agents, skills,
|
|
113
|
+
hooks, MCP) from one definition. Hooks + MCP keep the telemetry serve-wrapper,
|
|
114
|
+
so a marketplace-installed connector still reports per-tool tokens for its stdio
|
|
115
|
+
server. `--format all` emits **10 host formats**:
|
|
235
116
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
117
|
+
| Format | Hosts |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `claude-plugin` | Claude Code · Codex · VS Code Copilot · OpenClaw · OMP |
|
|
120
|
+
| `codex-plugin` | Codex (`.codex-plugin/` manifest variant) |
|
|
121
|
+
| `copilot-plugin` | GitHub Copilot CLI |
|
|
122
|
+
| `factory-plugin` | Droid |
|
|
123
|
+
| `gemini-extension` | Gemini CLI |
|
|
124
|
+
| `qwen-extension` | Qwen Code |
|
|
125
|
+
| `agy-plugin` | Antigravity (CLI + IDE) |
|
|
126
|
+
| `cursor-plugin` | Cursor |
|
|
127
|
+
| `kimi-plugin` | Kimi CLI |
|
|
128
|
+
| `npm-plugin` | OpenCode · Kilo CLI · Pi |
|
|
129
|
+
|
|
130
|
+
Two official **MCP standard artifacts** are opt-in (they need a `publish` block,
|
|
131
|
+
so they're excluded from `--format all`) — `mcp-server-json` (an MCP Registry
|
|
132
|
+
`server.json`) and `mcpb` (a one-click MCPB bundle); see
|
|
133
|
+
[Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem).
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# emit every host format (mcp-server-json + mcpb are opt-in by name)
|
|
137
|
+
agent-connector package --format all --out ./dist-plugin
|
|
138
|
+
agent-connector package --format gemini-extension --out ./ext # or just one
|
|
139
|
+
|
|
140
|
+
# e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
|
|
141
|
+
# /plugin install <connector-id>@agent-connector
|
|
142
|
+
# e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
|
|
244
143
|
```
|
|
245
144
|
|
|
145
|
+
> **Embedded-path caveat.** Most host bundles bake in the absolute home-bin
|
|
146
|
+
> launcher path of the machine that ran `package`, so they're valid for a
|
|
147
|
+
> **local install on that same machine/home**. For shared distribution use
|
|
148
|
+
> `npm-plugin` or the MCP standard artifacts, or re-run `package` per machine.
|
|
149
|
+
|
|
150
|
+
**Let agent-connector drive the host's own install flow** with `install --method
|
|
151
|
+
marketplace`:
|
|
152
|
+
|
|
153
|
+
- **What it does** — stages the bundle, registers a local marketplace where the
|
|
154
|
+
host has one, then runs the host's plugin-install verb (or, for npm-plugin
|
|
155
|
+
hosts, writes a local `file://` entry); headless and idempotent. Other
|
|
156
|
+
marketplace-format hosts print the exact manual commands.
|
|
157
|
+
- **Host coverage** — live-verified for Claude Code, Codex, OpenCode, Kilo
|
|
158
|
+
(CLI + ext), and Antigravity (CLI + IDE) on Linux, Windows, and macOS; Droid
|
|
159
|
+
and Qwen Code have the driver shipped but pending a live host; Gemini CLI is
|
|
160
|
+
legacy (sunsetting toward Antigravity — driver kept for existing installs).
|
|
161
|
+
- **Safety + reversal** — a guard refuses installing the same connector by BOTH
|
|
162
|
+
methods, `uninstall --method auto` reverses whichever method is installed, and
|
|
163
|
+
`doctor` checks registration drift.
|
|
164
|
+
|
|
165
|
+
### Ship a branded CLI
|
|
166
|
+
|
|
167
|
+
A connector developer can ship their **own** bin instead of having users type
|
|
168
|
+
`agent-connector`. `createConnectorCli({ name, connector })` (from the
|
|
169
|
+
`@ken-jo/agent-connector/cli` export) exposes **every** subcommand under your
|
|
170
|
+
brand, fully delegated and **auto-scoped** to your connector — so your users
|
|
171
|
+
never install agent-connector globally or type `--connector`. See
|
|
172
|
+
[`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
|
|
173
|
+
|
|
246
174
|
```js
|
|
247
175
|
#!/usr/bin/env node
|
|
248
176
|
// bin.mjs — every agent-connector subcommand, branded as `acme-db`
|
|
@@ -258,142 +186,21 @@ process.exitCode = await createConnectorCli({
|
|
|
258
186
|
}).run();
|
|
259
187
|
```
|
|
260
188
|
|
|
261
|
-
After a consumer installs **your** package
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
acme-db leaderboard # the 🔌 MCP/plugin section, scoped to acme-db
|
|
269
|
-
acme-db telemetry report --by tool # per-tool tokens for acme-db's own wrapped server
|
|
270
|
-
acme-db --help # every agent-connector subcommand, branded
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
**Auto-scoping is pure argument injection over the SAME single home binary.** A
|
|
274
|
-
branded subcommand is the matching agent-connector command with your connector
|
|
275
|
-
pre-injected — `acme-db leaderboard` ≈ `agent-connector leaderboard --connector
|
|
276
|
-
acme-db`, `acme-db install` ≈ `agent-connector install --connector
|
|
277
|
-
./agent-connector.config.mjs`. `serve` and `hook` still route through the one
|
|
278
|
-
`~/.agent-connector` home binary every host config points back to, so branded
|
|
279
|
-
tools share that infrastructure. An explicit `--connector` / `--connector-id`
|
|
280
|
-
always overrides the injected default.
|
|
281
|
-
|
|
282
|
-
### Author + test offline — the Connector SDK (`/sdk`, `/sdk/test`)
|
|
283
|
-
|
|
284
|
-
```ts
|
|
285
|
-
import { defineConnector, defineHook, hostsSupporting } from "@ken-jo/agent-connector/sdk";
|
|
286
|
-
import { simulate, explain } from "@ken-jo/agent-connector/sdk/test";
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
`@ken-jo/agent-connector/sdk` is the consolidated **authoring** surface — it
|
|
290
|
-
re-exports `defineConnector`, the full `define*` family, the introspection
|
|
291
|
-
helpers, and public types from one import site (the root export is unchanged;
|
|
292
|
-
`/sdk` is additive).
|
|
293
|
-
|
|
294
|
-
**`define*` typed helpers** — each is a typed identity function (`(def) => def`)
|
|
295
|
-
that gives you per-surface type inference and a single import site:
|
|
296
|
-
`defineCommand`, `defineSkill`, `defineSubagent`, `defineMemory`,
|
|
297
|
-
`defineConfigPatch`, `defineNativeHook`. `defineHook` is event-parameterized
|
|
298
|
-
so the handler payload narrows to the concrete event type:
|
|
299
|
-
|
|
300
|
-
```ts
|
|
301
|
-
const guard = defineHook("PreToolUse", {
|
|
302
|
-
handler(evt) {
|
|
303
|
-
// evt.toolName is typed as PreToolUseEvent — not the union
|
|
304
|
-
return evt.toolName === "acme_write"
|
|
305
|
-
? { decision: "ask", reason: "Confirm write" }
|
|
306
|
-
: { decision: "allow" };
|
|
307
|
-
},
|
|
308
|
-
});
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
**Introspection** (async — adapters load lazily):
|
|
312
|
-
|
|
313
|
-
- `hostsSupporting(surface)` → `Promise<PlatformId[]>` — which registered hosts
|
|
314
|
-
honor a surface (`"hooks"` | `"statusline"` | `"memory"` | …).
|
|
315
|
-
- `capabilitiesOf(host)` → `Promise<PlatformCapabilities | undefined>`.
|
|
316
|
-
- `surfaceSupport(host, surface)` → `Promise<boolean>` — convenience single-pair check.
|
|
317
|
-
|
|
318
|
-
**Offline harness** (`@ken-jo/agent-connector/sdk/test`) answers *"does my
|
|
319
|
-
handler / HUD actually work on host X?"* before you touch a real host:
|
|
320
|
-
|
|
321
|
-
- `explain(connector)` → `Promise<ExplainRow[]>` — the per-host × per-declared-surface
|
|
322
|
-
matrix. Each row is `{ host, surface, support: "native"|"skip-warn"|"disabled", reason }`.
|
|
323
|
-
Only surfaces the connector actually declares are included. The `hooks` row is judged
|
|
324
|
-
against **your connector's specific declared events** — a Stop-only connector reports
|
|
325
|
-
`skip-warn` (not `native`) on a host that cannot fire Stop, naming the dead events.
|
|
326
|
-
- `explainHooks(connector, hosts)` → `Promise<HookEventVerdict[]>` — the per-`(host, event)`
|
|
327
|
-
honor matrix (`honored | degraded | dropped` + reason), powered by `simulate()`. This is
|
|
328
|
-
what `agent-connector doctor --explain` prints — the trustworthy per-event diagnostic,
|
|
329
|
-
no hand-enumeration of `(host, event)` pairs.
|
|
330
|
-
- `simulate(connector, { surface, host, event?, input })` → `Promise<{ honored, hostReply?, reason }>`
|
|
331
|
-
— runs the **real** adapter parse→handler→format chain offline and judges the
|
|
332
|
-
actual `(event, decision)` contract. It encodes each host's real honor / drop /
|
|
333
|
-
degrade quirks — not substring guessing:
|
|
334
|
-
|
|
335
|
-
```ts
|
|
336
|
-
// Does codex honor a context injection on UserPromptSubmit?
|
|
337
|
-
const result = await simulate(connector, {
|
|
338
|
-
surface: "hooks",
|
|
339
|
-
host: "codex",
|
|
340
|
-
event: "UserPromptSubmit",
|
|
341
|
-
input: { hookEventName: "UserPromptSubmit", prompt: "explain this" },
|
|
342
|
-
});
|
|
343
|
-
// → { honored: false, reason: "drops context on UserPromptSubmit (no stdout path)" }
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
> Other verdicts the harness encodes: a `deny` on `Stop`/`SubagentStop` is
|
|
347
|
-
> continuation/persistence → `honored:true` (reason explains); `deny` on
|
|
348
|
-
> `SubagentStart`/`PostToolUseFailure` degrades to a context note →
|
|
349
|
-
> `honored:false`; a PermissionRequest `ask` is honored by the host's native
|
|
350
|
-
> dialog → `honored:true`. Matcher-scoped handlers that don't match the input
|
|
351
|
-
> are not run. The harness mirrors the runtime exactly — tolerant stdin,
|
|
352
|
-
> matcher filtering, real verdict.
|
|
353
|
-
|
|
354
|
-
### Two ways to ship: direct install **or** a marketplace package
|
|
355
|
-
|
|
356
|
-
Same one definition, your choice of distribution:
|
|
357
|
-
|
|
358
|
-
- **Direct install** (above) — `install` writes each host's native MCP + plugin/
|
|
359
|
-
extension config in place; no per-platform marketplace submission or review.
|
|
360
|
-
- **Marketplace install** — `install --method marketplace` drives the host's own
|
|
361
|
-
plugin flow end-to-end for **10 hosts**: Claude Code, Codex, OpenCode, Kilo
|
|
362
|
-
(CLI + ext), Antigravity (CLI + IDE) — live-verified on Linux, Windows, and
|
|
363
|
-
macOS — plus Droid and Qwen Code (driver shipped, pending a live host) and
|
|
364
|
-
Gemini CLI (legacy — sunsetting toward Antigravity; driver kept for existing
|
|
365
|
-
installs). It stages the bundle, registers a local marketplace where the host
|
|
366
|
-
has one, then runs the host's plugin-install verb (or, for npm-plugin hosts,
|
|
367
|
-
writes a local `file://` entry); headless and idempotent. `uninstall --method
|
|
368
|
-
auto` reverses whichever method is installed, a guard refuses installing the
|
|
369
|
-
same connector by BOTH methods, and `doctor` checks registration drift. Other
|
|
370
|
-
marketplace-format hosts print the exact manual commands.
|
|
371
|
-
- **Marketplace package** — `agent-connector package` turns the connector into a
|
|
372
|
-
marketplace/extension bundle (manifest + bundled commands, agents, skills,
|
|
373
|
-
hooks, MCP) for **9 host formats** (plus 2 official MCP standard artifacts —
|
|
374
|
-
see *Publish to the MCP ecosystem*) across the ecosystem, from one definition:
|
|
375
|
-
`claude-plugin` (Claude Code · Codex · VS Code Copilot · OpenClaw · OMP) ·
|
|
376
|
-
`codex-plugin` · `factory-plugin` (Droid) · `gemini-extension` (Gemini CLI) ·
|
|
377
|
-
`qwen-extension` · `agy-plugin` (Antigravity CLI/IDE) · `cursor-plugin` ·
|
|
378
|
-
`kimi-plugin` · `npm-plugin` (OpenCode / Kilo CLI / Pi). Hooks + MCP keep the
|
|
379
|
-
telemetry serve-wrapper, so a marketplace-installed connector still reports
|
|
380
|
-
per-tool tokens (for its stdio server).
|
|
189
|
+
After a consumer installs **your** package, the `acme-db` bin is on their PATH
|
|
190
|
+
and every command is scoped to your connector (`acme-db install` ≈
|
|
191
|
+
`agent-connector install --connector ./agent-connector.config.mjs`). Auto-scoping
|
|
192
|
+
is pure argument injection over the SAME single home binary; `serve` and `hook`
|
|
193
|
+
still route through the one `~/.agent-connector` home binary every host config
|
|
194
|
+
points back to. An explicit `--connector` / `--connector-id` always overrides
|
|
195
|
+
the injected default.
|
|
381
196
|
|
|
382
|
-
|
|
383
|
-
# emit all 9 host formats (mcp-server-json + mcpb are opt-in by name — they need publish{})
|
|
384
|
-
agent-connector package --format all --out ./dist-plugin
|
|
385
|
-
agent-connector package --format gemini-extension --out ./ext # or one
|
|
386
|
-
# e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
|
|
387
|
-
# /plugin install <connector-id>@agent-connector
|
|
388
|
-
# e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
|
|
389
|
-
```
|
|
197
|
+
## What you define once
|
|
390
198
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
## Define once
|
|
199
|
+
A single `defineConnector({...})` declares your MCP **server** + lifecycle
|
|
200
|
+
**hooks**, and optionally the additional surfaces — **commands**, **skills**,
|
|
201
|
+
**subagents**, **memory**, **statusline**, **actions**, plus host-native escape
|
|
202
|
+
hatches. agent-connector renders each surface into every detected host's native
|
|
203
|
+
format, or *skip-warns* (never silently drops) where a host can't support it.
|
|
397
204
|
|
|
398
205
|
```ts
|
|
399
206
|
import { fileURLToPath } from "node:url";
|
|
@@ -424,42 +231,6 @@ export default defineConnector({
|
|
|
424
231
|
});
|
|
425
232
|
```
|
|
426
233
|
|
|
427
|
-
> **Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` in `command`, `args`,
|
|
428
|
-
> `env`, `url`, or `headers` to reference an environment variable, or
|
|
429
|
-
> `"${env:VAR:-default}"` to supply a fallback. On hosts with **native**
|
|
430
|
-
> interpolation (Claude Code, Cursor, VS Code Copilot, amp, codebuff) the token
|
|
431
|
-
> is written through to the host config and resolved at runtime — the secret is
|
|
432
|
-
> never baked into a file. Every other host has **no** native interpolation, so
|
|
433
|
-
> the value is resolved to a **literal at install time**. An unset variable with
|
|
434
|
-
> no default resolves to an **empty string**; on a literal-resolving host that
|
|
435
|
-
> would silently bake `""` where a secret was meant, so `install` now emits a
|
|
436
|
-
> `warn` for it (e.g. *"ACME_DB_DSN is unset — baking an empty value into codex
|
|
437
|
-
> config"*) — `export` the variable before installing, or give the ref a
|
|
438
|
-
> `:-default`.
|
|
439
|
-
|
|
440
|
-
> **Native hooks escape hatch.** The normalized `hooks` API covers the 13
|
|
441
|
-
> cross-platform events. For host-only events — Claude Code alone ships 30
|
|
442
|
-
> (`TaskCompleted`, `TeammateIdle`, `WorktreeCreate`, …) — declare
|
|
443
|
-
> `platforms: { "claude-code": { nativeHooks: { TaskCompleted: { handler } } } }`:
|
|
444
|
-
> the handler receives the host's **raw** payload and whatever it returns is the
|
|
445
|
-
> **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Claude
|
|
446
|
-
> Code is not the only nativeHooks host: `amp`, `claude-code`, `continue`,
|
|
447
|
-
> `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
|
|
448
|
-
> `nemoclaw`, `omp`, `openclaw`, `opencode`, and `qwen-code` currently support
|
|
449
|
-
> host-native passthrough. Other hosts skip-warn, never silently.
|
|
450
|
-
|
|
451
|
-
> **Host-config key patches.** For host-exclusive *settings keys* no other
|
|
452
|
-
> surface reaches (e.g. an experimental `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`
|
|
453
|
-
> flag), declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }`.
|
|
454
|
-
> Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
|
|
455
|
-
> overwrite, never deep-merge. Ownership is refcounted in a persisted ledger, so
|
|
456
|
-
> uninstall removes a key only when the last owning connector releases it and the
|
|
457
|
-
> value is untouched; security-relevant keys (`permissions*`, `apiKey*`,
|
|
458
|
-
> `env.ANTHROPIC_*`, token/secret env vars, …) are hard-refused, as are keys
|
|
459
|
-
> agent-connector models as first-class surfaces (`hooks*`, `mcpServers*`,
|
|
460
|
-
> `statusLine` → use the `statusline` surface instead). Claude Code only for now;
|
|
461
|
-
> other hosts skip-warn with the exact manual edit.
|
|
462
|
-
|
|
463
234
|
`agent-connector install` turns that into, e.g.:
|
|
464
235
|
|
|
465
236
|
| Host | What gets written |
|
|
@@ -471,150 +242,80 @@ export default defineConnector({
|
|
|
471
242
|
…each pointing hooks at a **single stable home binary**, so one update propagates
|
|
472
243
|
everywhere.
|
|
473
244
|
|
|
474
|
-
|
|
245
|
+
**Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` (or `"${env:VAR:-default}"`) anywhere in `command` / `args` / `env` / `url` / `headers` to reference an environment variable.
|
|
475
246
|
|
|
476
|
-
|
|
247
|
+
<details>
|
|
248
|
+
<summary>Native interpolation vs. literal-at-install resolution</summary>
|
|
477
249
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
],
|
|
485
|
-
```
|
|
250
|
+
> On hosts with **native** interpolation (Claude Code, Cursor, VS Code Copilot,
|
|
251
|
+
> amp, codebuff) the token is written through to the host config and resolved at
|
|
252
|
+
> runtime. Every other host has **no** native interpolation, so the value is
|
|
253
|
+
> resolved to a **literal at install time**; an unset variable with no default
|
|
254
|
+
> resolves to an **empty string**, and `install` emits a `warn` for it on a
|
|
255
|
+
> literal-resolving host.
|
|
486
256
|
|
|
487
|
-
|
|
488
|
-
[AGENTS.md](https://agents.md) on 29 of the 35 hosts** (the open, Linux
|
|
489
|
-
Foundation-stewarded "README for agents" format): project scope targets
|
|
490
|
-
`<projectDir>/AGENTS.md` — and where a host resolves its rules file
|
|
491
|
-
exclusively, the target is *probed* so the block lands in the file the host
|
|
492
|
-
actually reads (zed's first-match rules list, warp's `WARP.md` priority,
|
|
493
|
-
hermes' `.hermes.md`, opencode's `CLAUDE.md` fallback, codex's
|
|
494
|
-
`AGENTS.override.md`). User scope goes to the host's documented global memory
|
|
495
|
-
file (AGENTS.md where one exists, else the host's own file — `~/.qwen/QWEN.md`,
|
|
496
|
-
goose `.goosehints`, kilo/roo/kiro rules dirs).
|
|
497
|
-
The two hosts that don't read AGENTS.md are wired per their own official docs:
|
|
498
|
-
|
|
499
|
-
- **Claude Code** → the block goes in `CLAUDE.md` (the official memory docs are
|
|
500
|
-
explicit: *"Claude Code reads CLAUDE.md, not AGENTS.md"*). Opt-in
|
|
501
|
-
`platforms: { "claude-code": { memory: { mode: "agents-import" } } }` instead
|
|
502
|
-
writes the canonical AGENTS.md block plus Anthropic's documented `@AGENTS.md`
|
|
503
|
-
import line as a managed bridge in CLAUDE.md — opt-in because the import makes
|
|
504
|
-
Claude read the *entire* AGENTS.md.
|
|
505
|
-
- **Gemini CLI** → `GEMINI.md`, unless the user's `context.fileName` setting
|
|
506
|
-
already opts Gemini into AGENTS.md (probed and respected — never edited).
|
|
507
|
-
|
|
508
|
-
Writes are **surgical managed blocks** — marker-fenced
|
|
509
|
-
(`<!-- agent-connector:begin <id>/memory hash=… -->`), hash-stamped, multiple
|
|
510
|
-
connectors coexist in one file, and bytes outside your own markers are never
|
|
511
|
-
touched. If a user edits inside the block, the hash mismatch is detected and the
|
|
512
|
-
edit is *left intact* (sync warns; `install --force` overwrites after a backup).
|
|
513
|
-
Uninstall excises exactly your blocks and `doctor` verifies them (present /
|
|
514
|
-
hash-intact / user-edited / file missing). Hosts with no writable memory file at
|
|
515
|
-
a scope skip-warn, never silently.
|
|
516
|
-
|
|
517
|
-
### Status line (`statusline`) — live HUD per connector
|
|
518
|
-
|
|
519
|
-
Ship a render function that the host calls on every status refresh:
|
|
257
|
+
</details>
|
|
520
258
|
|
|
521
|
-
|
|
522
|
-
import { defineConnector, defineStatusline } from "@ken-jo/agent-connector";
|
|
259
|
+
**Native hooks escape hatch.** The normalized `hooks` API covers the 13 cross-platform events; for host-only events (Claude Code alone ships 30) declare `platforms: { "claude-code": { nativeHooks: { TaskCompleted: { handler } } } }`.
|
|
523
260
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
// ...
|
|
527
|
-
statusline: defineStatusline({
|
|
528
|
-
render(ctx) {
|
|
529
|
-
const model = ctx.model?.displayName ?? ctx.model?.id ?? "unknown";
|
|
530
|
-
return `acme-db · ${model} · $${(ctx.cost?.totalUsd ?? 0).toFixed(4)}`;
|
|
531
|
-
},
|
|
532
|
-
}),
|
|
533
|
-
});
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
`StatuslineContext` provides (where the host supplies them) `host`,
|
|
537
|
-
`connectorId`, `sessionId`, `cwd`, `model` (`id` / `displayName`),
|
|
538
|
-
`cost` (`totalUsd`), `context` (`usedTokens` / `maxTokens` / `percent`),
|
|
539
|
-
`transcriptPath`, and `raw` (the host's verbatim payload). Fields the host
|
|
540
|
-
does not provide are `undefined`.
|
|
541
|
-
|
|
542
|
-
> **`ctx.context` is reserved** — `context.usedTokens` / `maxTokens` / `percent`
|
|
543
|
-
> are declared in `StatuslineContext` for a future AC-usage integration but are
|
|
544
|
-
> **not populated by any v1 code path**. Rendering `ctx.context?.percent ?? 0`
|
|
545
|
-
> always produces `0%`. Use `ctx.cost?.totalUsd` and `ctx.model?.displayName`
|
|
546
|
-
> (both populated by claude-code) instead.
|
|
547
|
-
|
|
548
|
-
**v1: claude-code and qwen-code.** Install registers Claude Code's
|
|
549
|
-
`settings.json.statusLine` or Qwen Code's nested `settings.json.ui.statusLine`
|
|
550
|
-
via the same ownership ledger — **set-if-absent, never clobbers a status line
|
|
551
|
-
agent-connector doesn't own** (skip-warns and prints the manual edit instead),
|
|
552
|
-
refcounted, reversible. Every other host adapter skip-warns at install time,
|
|
553
|
-
never silently. The runtime is **fail-safe**: any error — a
|
|
554
|
-
throwing `render`, unknown connector, malformed stdin — exits 0 with empty
|
|
555
|
-
stdout so a HUD never wedges the host. `doctor` includes a dedicated
|
|
556
|
-
`statusline wired` check.
|
|
557
|
-
|
|
558
|
-
> `defineStatusline` is a typed identity helper and is optional — you can
|
|
559
|
-
> pass the `{ render }` object directly to `statusline:`. Both
|
|
560
|
-
> `StatuslineDef` and `StatuslineContext` are exported from
|
|
561
|
-
> `@ken-jo/agent-connector`.
|
|
562
|
-
|
|
563
|
-
### Actions (`defineAction`) — user-triggered dispatch
|
|
564
|
-
|
|
565
|
-
Declare named, user-invocable operations on your connector:
|
|
261
|
+
<details>
|
|
262
|
+
<summary>Raw-payload semantics and the ~14 passthrough hosts</summary>
|
|
566
263
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
// ...
|
|
573
|
-
actions: [
|
|
574
|
-
defineAction({
|
|
575
|
-
id: "flush-cache",
|
|
576
|
-
description: "Flush the acme-db query cache",
|
|
577
|
-
async run(ctx) {
|
|
578
|
-
// ctx is HostCtx — same context object as hooks
|
|
579
|
-
await flushCache();
|
|
580
|
-
return { message: "Cache flushed." };
|
|
581
|
-
},
|
|
582
|
-
}),
|
|
583
|
-
],
|
|
584
|
-
});
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
The **universal verb** runs any declared action from the shell (or from a
|
|
588
|
-
script / IDE task):
|
|
589
|
-
|
|
590
|
-
```bash
|
|
591
|
-
agent-connector action <platform> flush-cache --connector acme-db
|
|
592
|
-
```
|
|
264
|
+
> The handler receives the host's **raw** payload and whatever it returns is the
|
|
265
|
+
> **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Hosts
|
|
266
|
+
> supporting host-native passthrough: `amp`, `claude-code`, `continue`,
|
|
267
|
+
> `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
|
|
268
|
+
> `nemoclaw`, `omp`, `openclaw`, `opencode`, `qwen-code`. Others skip-warn.
|
|
593
269
|
|
|
594
|
-
|
|
595
|
-
stdout. **Error semantics are user-triggered**: an unknown action id or a
|
|
596
|
-
throw exits 1 and writes to stderr (unlike hooks and statusline, which are
|
|
597
|
-
fail-safe/silent on error).
|
|
270
|
+
</details>
|
|
598
271
|
|
|
599
|
-
`
|
|
600
|
-
`@ken-jo/agent-connector` and `@ken-jo/agent-connector/sdk`.
|
|
601
|
-
`ActionDef = { id, description?, run, hosts? }` and `ActionResult = { message? }`.
|
|
272
|
+
**Host-config key patches.** For host-exclusive *settings keys* no other surface reaches, declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }` (Claude Code only for now; other hosts skip-warn with the exact manual edit).
|
|
602
273
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
affordances on `droid`, `hermes`, `nemoclaw`, `omp`, `openclaw`, and `warp`; every
|
|
606
|
-
other host skip-warns rather than silently dropping declared actions. `explain()`
|
|
607
|
-
reports those emitter hosts as native and the rest as skip-warn. `simulate()`
|
|
608
|
-
does not cover actions (actions take no host payload and have no host-honor
|
|
609
|
-
verdict — intentional).
|
|
274
|
+
<details>
|
|
275
|
+
<summary>Set-if-absent + refcount + denylist semantics</summary>
|
|
610
276
|
|
|
611
|
-
|
|
277
|
+
> Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
|
|
278
|
+
> overwrite, never deep-merge. Ownership is refcounted in a persisted ledger;
|
|
279
|
+
> security-relevant keys and keys agent-connector models as first-class surfaces
|
|
280
|
+
> are hard-refused.
|
|
281
|
+
|
|
282
|
+
</details>
|
|
283
|
+
|
|
284
|
+
### Memory, statusline, actions, and the SDK
|
|
285
|
+
|
|
286
|
+
- **`memory`** (aligned with the [AGENTS.md](https://agents.md) standard) — ship
|
|
287
|
+
standing guidance that lands in `AGENTS.md` on 33 of the 42 hosts; the two that
|
|
288
|
+
don't read it (Claude Code → `CLAUDE.md`, Gemini CLI → `GEMINI.md`) are wired
|
|
289
|
+
per their own official docs. Writes are surgical marker-fenced, hash-stamped
|
|
290
|
+
managed blocks — multiple connectors coexist, bytes outside your markers are
|
|
291
|
+
never touched, and uninstall excises exactly your blocks.
|
|
292
|
+
- **`statusline`** (`defineStatusline`) — a live HUD render function the host
|
|
293
|
+
calls on every status refresh. v1 registers Claude Code's `settings.json.statusLine`
|
|
294
|
+
or Qwen Code's `settings.json.ui.statusLine` (set-if-absent, refcounted,
|
|
295
|
+
reversible); other hosts skip-warn. The runtime is **fail-safe**: any error
|
|
296
|
+
exits 0 with empty stdout so a HUD never wedges the host.
|
|
297
|
+
- **`actions`** (`defineAction`) — named, user-invocable operations dispatched by
|
|
298
|
+
the universal verb `agent-connector action <platform> <id> --connector <id>`.
|
|
299
|
+
`install` emits host-side affordances on `droid`, `hermes`, `nemoclaw`, `omp`,
|
|
300
|
+
`openclaw`, and `warp`; other hosts skip-warn. Error semantics are
|
|
301
|
+
user-triggered (unknown id or throw exits 1).
|
|
302
|
+
- **The Connector SDK** (`@ken-jo/agent-connector/sdk`, `/sdk/test`) — the
|
|
303
|
+
consolidated authoring surface re-exports `defineConnector`, the full `define*`
|
|
304
|
+
family (`defineHook`, `defineCommand`, `defineSkill`, `defineSubagent`,
|
|
305
|
+
`defineMemory`, `defineStatusline`, `defineAction`, `defineConfigPatch`,
|
|
306
|
+
`defineNativeHook`), introspection helpers (`hostsSupporting`,
|
|
307
|
+
`capabilitiesOf`, `surfaceSupport`), and an **offline harness**
|
|
308
|
+
(`simulate`, `explain`, `explainHooks`) that runs the real adapter
|
|
309
|
+
parse→handler→format chain to answer *"does my handler actually work on host
|
|
310
|
+
X?"* before you touch a real host. See
|
|
311
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
312
|
+
|
|
313
|
+
## How it works
|
|
612
314
|
|
|
613
315
|
- **Home-dir, single binary.** The runtime installs once under
|
|
614
|
-
`~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
auto-update, so one bad release can't break every project at once.
|
|
316
|
+
`~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every host config we
|
|
317
|
+
write is a thin pointer back to that one binary. Updates are
|
|
318
|
+
**explicit/managed** (`agent-connector upgrade`), never silent auto-update.
|
|
618
319
|
- **Per-project data, kept.** Telemetry/state is keyed by a stable project
|
|
619
320
|
identity (git remote or normalized path), partitioned per project, stored under
|
|
620
321
|
the home data-root — surviving `git clean`, shared across hosts opening the same
|
|
@@ -623,45 +324,83 @@ verdict — intentional).
|
|
|
623
324
|
only framework-owned state lives under the data-root.
|
|
624
325
|
- **Windows-first correctness.** No symlinks, no POSIX-only assumptions.
|
|
625
326
|
|
|
327
|
+
**Three hook paradigms**, all install-verified across the 42-platform set
|
|
328
|
+
(see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)):
|
|
329
|
+
|
|
330
|
+
| Paradigm | Platforms |
|
|
331
|
+
|---|---|
|
|
332
|
+
| `json-stdio` (full hook dispatch) | CodeBuddy · Claude Code · Codex CLI · Cursor · VS Code Copilot · JetBrains Copilot · GitHub Copilot CLI · Gemini CLI · Qwen CLI · Kiro · Kimi CLI · Crush · Goose · Hermes · Droid (Factory) · OpenHands · Antigravity · Antigravity CLI · Continue · Amazon Q · Grok CLI · Devin CLI |
|
|
333
|
+
| `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
|
|
334
|
+
| `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
|
|
335
|
+
|
|
336
|
+
Adding a platform = **one registry entry + one adapter**.
|
|
337
|
+
|
|
626
338
|
## CLI
|
|
627
339
|
|
|
628
340
|
| Command | Purpose |
|
|
629
341
|
|---|---|
|
|
630
342
|
| `detect` | List installed platforms, scopes, capabilities, hook paradigm. |
|
|
631
|
-
| `install [--scope
|
|
632
|
-
| `uninstall [--targets …]` | Full inverse — removes everything we wrote. |
|
|
633
|
-
| `upgrade [--channel
|
|
634
|
-
| `doctor [--probe] [--explain]` | Per-platform health checks with fixes; `--probe` runs a live MCP handshake
|
|
343
|
+
| `install [--scope …] [--targets …] [--method …] [--dry-run] [--force]` | Render + write MCP + hooks + content surfaces across targets. |
|
|
344
|
+
| `uninstall [--targets …] [--purge] [--method …]` | Full inverse — removes everything we wrote; `--purge` also clears framework state. |
|
|
345
|
+
| `upgrade [--channel …]` | Re-render host config + heal stale pointers + refresh the home binary (alias: `update`, `sync`); never a silent self-update. |
|
|
346
|
+
| `doctor [--probe] [--explain]` | Per-platform health checks with fixes; `--probe` runs a live MCP handshake, `--explain` prints the per-`(host, event)` hook honor matrix. |
|
|
635
347
|
| `status` | Light install-state: which connectors are present on which hosts (always exits 0). |
|
|
636
|
-
| `package [--format <fmt>\|all]` | Emit a host bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
|
|
637
|
-
| `
|
|
638
|
-
| `telemetry
|
|
639
|
-
| `
|
|
640
|
-
| `leaderboard [--
|
|
348
|
+
| `package [--format <fmt>\|all]` | Emit a host plugin bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
|
|
349
|
+
| `action <platform> <id> [--connector <id>]` | Run a declared action from the shell. |
|
|
350
|
+
| `telemetry report [--by …] [--since …] [--connector <id>]` | Per-tool token footprint of **your connector's own wrapped server**. Stdio servers only. |
|
|
351
|
+
| `telemetry export [--format …] [--connector <id>]` | Raw aggregate records for your wrapped server. |
|
|
352
|
+
| `usage report\|export\|leaderboard [--by …]` | **No connector needed.** Host-native whole-conversation token totals parsed read-only from each agent CLI's own logs. Does NOT break down by individual MCP or tool. |
|
|
353
|
+
| `leaderboard [--since …] [--connector <id>] [--scope …]` | Three origin-labeled boards with **different prerequisites** (🔌 MCP/plugin · 🛰️ host-native turns · 🖥️ host/user); counts are never summed across them. |
|
|
641
354
|
|
|
642
355
|
> `hook` and `serve` also exist — internal entrypoints the written host configs
|
|
643
356
|
> point at; you never run them by hand. Full flag-level reference: the
|
|
644
357
|
> [docs site `/docs/dev/cli`](https://agent-connector.ai/docs/dev/cli) · `llms-full.txt` §3 (canonical, drift-guarded by tests).
|
|
645
358
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
359
|
+
## Token telemetry & usage
|
|
360
|
+
|
|
361
|
+
Two independent, never-summed views of token cost:
|
|
362
|
+
|
|
363
|
+
- **Per-tool telemetry for *your own* server** (the MCP-developer path). No host
|
|
364
|
+
reports per-tool usage back to an MCP server, so agent-connector measures your
|
|
365
|
+
server's *own* bytes (args in, results out, tool schemas) and tokenizes them
|
|
366
|
+
locally — **aggregate counts only, stored locally, zero egress by default.**
|
|
367
|
+
Per-tool telemetry is automatic for **stdio** servers; remote (`http`/`sse`/`ws`)
|
|
368
|
+
servers are registered but not wrapped (the proxy can't intercept remote
|
|
369
|
+
transports). Read it with `agent-connector telemetry report --by tool`.
|
|
370
|
+
- **Connector-free usage** (`agent-connector usage`). Already run Claude Code /
|
|
371
|
+
Codex / Cursor and just want totals? `usage` reads your local agent-CLI session
|
|
372
|
+
logs **read-only** and never writes any host config — no connector, no install:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
npx @ken-jo/agent-connector usage report --by platform # CLI/model/project/session/day
|
|
376
|
+
npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
|
|
377
|
+
npx @ken-jo/agent-connector usage export --format csv --out usage.csv
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
It reports **whole-conversation totals** per agent CLI / model / project /
|
|
381
|
+
session / day. It does **not** itemize cost by individual MCP server or tool —
|
|
382
|
+
agent CLIs don't log per-tool attribution.
|
|
383
|
+
|
|
384
|
+
**Privacy & tokenizer.** Default tokenizer is `gpt-tokenizer` (pure-JS, no native
|
|
385
|
+
build) — `o200k_base` for OpenAI/Codex-family, a documented approximation for
|
|
386
|
+
Anthropic; falls back to a `chars/4` heuristic if it can't load. Every record
|
|
387
|
+
carries a confidence tag. Raw tool arguments and results are never stored or
|
|
388
|
+
transmitted. Off switch: `AGENT_CONNECTOR_TELEMETRY=0`, or
|
|
389
|
+
`telemetry: { enabled: false }`.
|
|
651
390
|
|
|
652
391
|
## Publish to the MCP ecosystem
|
|
653
392
|
|
|
654
|
-
Where the MCP standard already covers your server's functionality,
|
|
655
|
-
**emits the standard exactly** so your already-standard work is
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
- **`package --format mcp-server-json`** → an official **MCP Registry**
|
|
659
|
-
(schema `2025-12-11`). It describes your **real upstream server**
|
|
660
|
-
installer runs), not our telemetry wrapper. Publish it with
|
|
661
|
-
`mcp-publisher` CLI.
|
|
662
|
-
- **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT)
|
|
663
|
-
`manifest.json` (`manifest_version 0.3`) for one-click local install in
|
|
664
|
-
Desktop and any MCPB host, with secrets routed through the host keychain
|
|
393
|
+
Where the MCP standard already covers your server's functionality,
|
|
394
|
+
agent-connector **emits the standard exactly** so your already-standard work is
|
|
395
|
+
portable:
|
|
396
|
+
|
|
397
|
+
- **`package --format mcp-server-json`** → an official **MCP Registry**
|
|
398
|
+
`server.json` (schema `2025-12-11`). It describes your **real upstream server**
|
|
399
|
+
(what a registry installer runs), not our telemetry wrapper. Publish it with
|
|
400
|
+
the official `mcp-publisher` CLI.
|
|
401
|
+
- **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT)
|
|
402
|
+
bundle `manifest.json` (`manifest_version 0.3`) for one-click local install in
|
|
403
|
+
Claude Desktop and any MCPB host, with secrets routed through the host keychain
|
|
665
404
|
(`user_config`).
|
|
666
405
|
|
|
667
406
|
Both read a `publish` block on your connector (the namespace you own + your
|
|
@@ -682,32 +421,34 @@ defineConnector({
|
|
|
682
421
|
|
|
683
422
|
> **Config we write is the standard.** `install` writes each host's native MCP
|
|
684
423
|
> config in the de-facto canonical `mcpServers` shape — `{ command, args, env }`
|
|
685
|
-
> for stdio, `{ url, headers }` for remote
|
|
686
|
-
>
|
|
687
|
-
>
|
|
688
|
-
>
|
|
424
|
+
> for stdio, `{ url, headers }` for remote. The spec transport slug for
|
|
425
|
+
> streamable HTTP is `streamable-http` (registry `server.json`); host configs
|
|
426
|
+
> canonically use `http`. WebSocket (`ws`) is **not** an MCP spec transport and
|
|
427
|
+
> the standard artifacts reject it.
|
|
689
428
|
|
|
690
429
|
> **Forward-compatible by transport.** The `serve` proxy is **byte-transparent**:
|
|
691
430
|
> it forwards every JSON-RPC message verbatim and only tees a copy to count
|
|
692
|
-
> `tools/call` round-trips
|
|
693
|
-
>
|
|
694
|
-
> `io.modelcontextprotocol/ui` extension: `ui://` resource templates, `_meta.ui`
|
|
695
|
-
> tool linkage, the bidirectional `ui/*` + `sampling` traffic) and **any
|
|
431
|
+
> `tools/call` round-trips. So newer MCP features ride through untouched —
|
|
432
|
+
> **MCP Apps** (the official `io.modelcontextprotocol/ui` extension) and **any
|
|
696
433
|
> reverse-DNS extension** negotiated at `initialize`. A connector whose server
|
|
697
434
|
> already speaks these deploys across every host and keeps its telemetry today,
|
|
698
|
-
> no agent-connector change required.
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
435
|
+
> no agent-connector change required.
|
|
436
|
+
|
|
437
|
+
## Verification
|
|
438
|
+
|
|
439
|
+
The full single-API contract is **install-verified across all 42 platforms** by
|
|
440
|
+
a committed registry-driven install-roundtrip harness that, for every adapter,
|
|
441
|
+
drives the real install → uninstall into an isolated HOME and asserts on-disk
|
|
442
|
+
placement + zero residue. A separate committed `scripts/verify-host.mjs` driver
|
|
443
|
+
installs **20 real host CLIs** and verifies install → placement →
|
|
444
|
+
clean-uninstall, and live hook dispatch + telemetry are proven end-to-end on
|
|
445
|
+
several of them. The remaining hosts (IDE extensions / GUI editors with no
|
|
446
|
+
headless CLI) stay covered by the install-roundtrip harness.
|
|
447
|
+
|
|
448
|
+
**Dogfood result:** porting the real multi-host context-mode plugin to
|
|
449
|
+
`defineConnector` collapsed **~20,322 lines of hand-maintained per-host code down
|
|
450
|
+
to ~76 lines** (a 99.63% reduction). See the reports under
|
|
451
|
+
[`docs/research/`](docs/research/) and [`CHANGELOG.md`](CHANGELOG.md).
|
|
711
452
|
|
|
712
453
|
## Development
|
|
713
454
|
|