@ken-jo/agent-connector 0.4.91 → 0.4.93
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 +326 -563
- package/dist/{action-L44DXFHT.js → action-DOWHWEDZ.js} +14 -14
- package/dist/{amazon-q-B52EY2SV.js → amazon-q-ETMAGY3D.js} +5 -5
- package/dist/{amp-UXABVUKC.js → amp-67BZONGF.js} +5 -5
- package/dist/{antigravity-RZHN53VB.js → antigravity-VXLDLTO7.js} +6 -6
- package/dist/{antigravity-cli-JO6GUTV7.js → antigravity-cli-OM6SC3PE.js} +47 -16
- package/dist/antigravity-cli-OM6SC3PE.js.map +1 -0
- package/dist/{chunk-R6LML2YS.js → chunk-2RIFORQS.js} +2 -2
- package/dist/{chunk-QKLJU4JX.js → chunk-2Y2MZRLP.js} +56 -2
- package/dist/chunk-2Y2MZRLP.js.map +1 -0
- package/dist/{chunk-HORHRHNG.js → chunk-4NHXLXSD.js} +2 -2
- package/dist/{chunk-AY3RGRTT.js → chunk-6TF7MHG5.js} +2 -2
- package/dist/{chunk-NBUEL74R.js → chunk-6WZODR3Z.js} +3 -3
- package/dist/{chunk-LF76VPGQ.js → chunk-B5W3RHTI.js} +72 -22
- package/dist/chunk-B5W3RHTI.js.map +1 -0
- package/dist/{chunk-BLTVZACS.js → chunk-EHP7WISI.js} +9 -9
- package/dist/{chunk-4NSU3KWX.js → chunk-FJCUKXGX.js} +2 -2
- package/dist/{chunk-IXOQDZWC.js → chunk-GZGLCCEE.js} +5 -1
- package/dist/chunk-GZGLCCEE.js.map +1 -0
- package/dist/{chunk-LAIITCMW.js → chunk-I5TO42QC.js} +5 -5
- package/dist/{chunk-4FWETID5.js → chunk-IVAWP6HH.js} +2 -2
- package/dist/{chunk-UBB7T54N.js → chunk-JKKU2WKG.js} +3 -3
- package/dist/{chunk-G4CEELKO.js → chunk-KJLFGQQM.js} +180 -10
- package/dist/chunk-KJLFGQQM.js.map +1 -0
- package/dist/{chunk-NWLRJNXM.js → chunk-KSPMSRVU.js} +27 -15
- package/dist/chunk-KSPMSRVU.js.map +1 -0
- package/dist/{chunk-VVFDU4IX.js → chunk-MGTDQLJJ.js} +12 -5
- package/dist/{chunk-VVFDU4IX.js.map → chunk-MGTDQLJJ.js.map} +1 -1
- package/dist/{chunk-56R2ER7K.js → chunk-NBYKLUF6.js} +2 -2
- package/dist/chunk-OEADFFKO.js +590 -0
- package/dist/chunk-OEADFFKO.js.map +1 -0
- package/dist/{chunk-QARPXSIV.js → chunk-P23RVIUY.js} +4 -4
- package/dist/{chunk-25CPWJA7.js → chunk-SILKSP2Y.js} +43 -43
- package/dist/{chunk-KIRCPLM4.js → chunk-TTKSYJRY.js} +538 -226
- package/dist/chunk-TTKSYJRY.js.map +1 -0
- package/dist/{chunk-YYNXIUR2.js → chunk-UMQ6NBQR.js} +3 -3
- package/dist/chunk-UMQ6NBQR.js.map +1 -0
- package/dist/{chunk-4HVQ7IUM.js → chunk-XC5SJ35F.js} +17 -4
- package/dist/chunk-XC5SJ35F.js.map +1 -0
- package/dist/{chunk-LN76OGNR.js → chunk-Z2MRSS2I.js} +2 -2
- package/dist/{chunk-ZMLVR4J7.js → chunk-ZMAJ2XFD.js} +2 -2
- package/dist/{claude-code-WS4NAGZT.js → claude-code-DUZNOAS2.js} +9 -9
- package/dist/cli/sdk.js +7 -7
- package/dist/cli.js +1 -1
- package/dist/{cline-NNMVCECA.js → cline-25KW25IN.js} +5 -5
- package/dist/{codebuddy-RBEZGXBG.js → codebuddy-ZNYQACMF.js} +5 -5
- package/dist/{codebuff-RJIDSEU3.js → codebuff-VR6JUDIY.js} +5 -5
- package/dist/{codex-ZZ434GYR.js → codex-CPNKTXG3.js} +11 -5
- package/dist/{codex-ZZ434GYR.js.map → codex-CPNKTXG3.js.map} +1 -1
- package/dist/{continue-MNM7YVJY.js → continue-WU2IB5KS.js} +6 -6
- package/dist/{copilot-cli-SMTX5F65.js → copilot-cli-PAP377OM.js} +5 -5
- package/dist/{crush-NYDBHIJE.js → crush-3AVQA4YU.js} +5 -5
- package/dist/{cursor-AOELDNZU.js → cursor-GSLUET3V.js} +6 -6
- package/dist/define-connector-LQFJL_at.d.ts +89 -0
- package/dist/{detect-3S46RUMK.js → detect-DYQNUMXL.js} +4 -4
- package/dist/{devin-PRJY2TTD.js → devin-QMEM3OFA.js} +5 -5
- package/dist/{doctor-3CUBPQKU.js → doctor-H6XXAR63.js} +25 -21
- package/dist/doctor-H6XXAR63.js.map +1 -0
- package/dist/{droid-PTCH2K7Y.js → droid-MOKV53J4.js} +5 -5
- package/dist/{gemini-cli-QGLN2UMS.js → gemini-cli-47ZHCOZR.js} +5 -5
- package/dist/{goose-DQ6GSZ5O.js → goose-4EI5MYTI.js} +6 -6
- package/dist/{grok-cli-5QD235UB.js → grok-cli-QYQPDSVB.js} +5 -5
- package/dist/{hermes-E47IG63A.js → hermes-F75OSK3Y.js} +6 -6
- package/dist/{hook-P6EKDINW.js → hook-GIQTUDMN.js} +14 -14
- package/dist/index.d.ts +15 -88
- package/dist/index.js +15 -7
- package/dist/install-T27662FW.js +382 -0
- package/dist/install-T27662FW.js.map +1 -0
- package/dist/{introspect-DYOIX8Ov.d.ts → introspect-D4fEGuhN.d.ts} +1 -1
- package/dist/{jetbrains-copilot-T2EPKROP.js → jetbrains-copilot-ZGIWI6YV.js} +23 -7
- package/dist/jetbrains-copilot-ZGIWI6YV.js.map +1 -0
- package/dist/{junie-SQ4SDLGK.js → junie-DIFN2P22.js} +5 -5
- package/dist/{kilo-OU2ZLZKB.js → kilo-EMZJBEBB.js} +5 -5
- package/dist/{kilo-cli-NMWGYF4F.js → kilo-cli-S3GXBPAE.js} +5 -5
- package/dist/{kimi-Z7L2LEEI.js → kimi-IQJOIY6B.js} +5 -5
- package/dist/{kiro-4IN5IH46.js → kiro-BYX4HEAJ.js} +5 -5
- package/dist/{leaderboard-LF5SP6X2.js → leaderboard-CIMQBOUS.js} +5 -5
- package/dist/{mimo-code-G2CBZ4M6.js → mimo-code-7R53QDHB.js} +5 -5
- package/dist/{mistral-vibe-TRQDHAWV.js → mistral-vibe-LHJ55FSB.js} +5 -5
- package/dist/{mux-JNM3F2NW.js → mux-NYCNGL43.js} +5 -5
- package/dist/{nemoclaw-SHA4IUML.js → nemoclaw-WSIPSE7U.js} +6 -6
- package/dist/{omp-OOVUNXME.js → omp-562NK5BJ.js} +5 -5
- package/dist/{open-interpreter-4PKL56AA.js → open-interpreter-I2CNOEXY.js} +5 -5
- package/dist/openclaw-7EYBQS4R.js +17 -0
- package/dist/{opencode-W2RK4M7G.js → opencode-YS4WX2E2.js} +5 -5
- package/dist/{openhands-5LNH3BKB.js → openhands-QMYIKNOS.js} +5 -5
- package/dist/{package-2EAIYSJ4.js → package-LIPZKHAQ.js} +12 -12
- package/dist/{pi-BUADR5MJ.js → pi-644FIN3A.js} +5 -5
- package/dist/{qwen-code-TUJNHKNI.js → qwen-code-STDMX7EM.js} +6 -6
- package/dist/{roo-code-L5F7S6QH.js → roo-code-DLPIHHQ6.js} +5 -5
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +12 -12
- package/dist/sdk/index.d.ts +4 -4
- 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-ABTO2NA2.js} +14 -14
- package/dist/{status-E5MCFZM6.js → status-J7SOUH7O.js} +10 -10
- package/dist/{statusline-LIPF2KVP.js → statusline-QF4G724E.js} +13 -13
- package/dist/{telemetry-4OC56NTM.js → telemetry-EICCFEIF.js} +10 -10
- package/dist/{trae-Z7CQ2A2Q.js → trae-UOYD6JZZ.js} +5 -5
- package/dist/{types-C4qMgbJn.d.ts → types-BhcUEIJJ.d.ts} +82 -3
- package/dist/{uninstall-2YYKN5DX.js → uninstall-NJNNZZZY.js} +35 -25
- package/dist/uninstall-NJNNZZZY.js.map +1 -0
- package/dist/{upgrade-55AFPJEF.js → upgrade-TIBUOQNM.js} +23 -17
- package/dist/upgrade-TIBUOQNM.js.map +1 -0
- package/dist/{usage-3PB3WZSL.js → usage-VEVBWPLS.js} +2 -2
- package/dist/{usage-event-KD5FW6W4.js → usage-event-GRQE7XWT.js} +13 -13
- package/dist/{vscode-copilot-LU5NC4ZS.js → vscode-copilot-NIMH2DGU.js} +20 -5
- package/dist/vscode-copilot-NIMH2DGU.js.map +1 -0
- package/dist/{warp-4PPG5LOM.js → warp-QYJGKURM.js} +5 -5
- package/dist/{windsurf-3T3RVXKM.js → windsurf-75LLZ37C.js} +5 -5
- package/dist/{zed-ZF2OQ75O.js → zed-HKAZXEJW.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-G4CEELKO.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-NWLRJNXM.js.map +0 -1
- package/dist/chunk-QKLJU4JX.js.map +0 -1
- package/dist/chunk-YYNXIUR2.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-DOWHWEDZ.js.map} +0 -0
- /package/dist/{amazon-q-B52EY2SV.js.map → amazon-q-ETMAGY3D.js.map} +0 -0
- /package/dist/{amp-UXABVUKC.js.map → amp-67BZONGF.js.map} +0 -0
- /package/dist/{antigravity-RZHN53VB.js.map → antigravity-VXLDLTO7.js.map} +0 -0
- /package/dist/{chunk-R6LML2YS.js.map → chunk-2RIFORQS.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-NBUEL74R.js.map → chunk-6WZODR3Z.js.map} +0 -0
- /package/dist/{chunk-BLTVZACS.js.map → chunk-EHP7WISI.js.map} +0 -0
- /package/dist/{chunk-4NSU3KWX.js.map → chunk-FJCUKXGX.js.map} +0 -0
- /package/dist/{chunk-LAIITCMW.js.map → chunk-I5TO42QC.js.map} +0 -0
- /package/dist/{chunk-4FWETID5.js.map → chunk-IVAWP6HH.js.map} +0 -0
- /package/dist/{chunk-UBB7T54N.js.map → chunk-JKKU2WKG.js.map} +0 -0
- /package/dist/{chunk-56R2ER7K.js.map → chunk-NBYKLUF6.js.map} +0 -0
- /package/dist/{chunk-QARPXSIV.js.map → chunk-P23RVIUY.js.map} +0 -0
- /package/dist/{chunk-25CPWJA7.js.map → chunk-SILKSP2Y.js.map} +0 -0
- /package/dist/{chunk-LN76OGNR.js.map → chunk-Z2MRSS2I.js.map} +0 -0
- /package/dist/{chunk-ZMLVR4J7.js.map → chunk-ZMAJ2XFD.js.map} +0 -0
- /package/dist/{claude-code-WS4NAGZT.js.map → claude-code-DUZNOAS2.js.map} +0 -0
- /package/dist/{cline-NNMVCECA.js.map → cline-25KW25IN.js.map} +0 -0
- /package/dist/{codebuddy-RBEZGXBG.js.map → codebuddy-ZNYQACMF.js.map} +0 -0
- /package/dist/{codebuff-RJIDSEU3.js.map → codebuff-VR6JUDIY.js.map} +0 -0
- /package/dist/{continue-MNM7YVJY.js.map → continue-WU2IB5KS.js.map} +0 -0
- /package/dist/{copilot-cli-SMTX5F65.js.map → copilot-cli-PAP377OM.js.map} +0 -0
- /package/dist/{crush-NYDBHIJE.js.map → crush-3AVQA4YU.js.map} +0 -0
- /package/dist/{cursor-AOELDNZU.js.map → cursor-GSLUET3V.js.map} +0 -0
- /package/dist/{detect-3S46RUMK.js.map → detect-DYQNUMXL.js.map} +0 -0
- /package/dist/{devin-PRJY2TTD.js.map → devin-QMEM3OFA.js.map} +0 -0
- /package/dist/{droid-PTCH2K7Y.js.map → droid-MOKV53J4.js.map} +0 -0
- /package/dist/{gemini-cli-QGLN2UMS.js.map → gemini-cli-47ZHCOZR.js.map} +0 -0
- /package/dist/{goose-DQ6GSZ5O.js.map → goose-4EI5MYTI.js.map} +0 -0
- /package/dist/{grok-cli-5QD235UB.js.map → grok-cli-QYQPDSVB.js.map} +0 -0
- /package/dist/{hermes-E47IG63A.js.map → hermes-F75OSK3Y.js.map} +0 -0
- /package/dist/{hook-P6EKDINW.js.map → hook-GIQTUDMN.js.map} +0 -0
- /package/dist/{junie-SQ4SDLGK.js.map → junie-DIFN2P22.js.map} +0 -0
- /package/dist/{kilo-OU2ZLZKB.js.map → kilo-EMZJBEBB.js.map} +0 -0
- /package/dist/{kilo-cli-NMWGYF4F.js.map → kilo-cli-S3GXBPAE.js.map} +0 -0
- /package/dist/{kimi-Z7L2LEEI.js.map → kimi-IQJOIY6B.js.map} +0 -0
- /package/dist/{kiro-4IN5IH46.js.map → kiro-BYX4HEAJ.js.map} +0 -0
- /package/dist/{leaderboard-LF5SP6X2.js.map → leaderboard-CIMQBOUS.js.map} +0 -0
- /package/dist/{mimo-code-G2CBZ4M6.js.map → mimo-code-7R53QDHB.js.map} +0 -0
- /package/dist/{mistral-vibe-TRQDHAWV.js.map → mistral-vibe-LHJ55FSB.js.map} +0 -0
- /package/dist/{mux-JNM3F2NW.js.map → mux-NYCNGL43.js.map} +0 -0
- /package/dist/{nemoclaw-SHA4IUML.js.map → nemoclaw-WSIPSE7U.js.map} +0 -0
- /package/dist/{omp-OOVUNXME.js.map → omp-562NK5BJ.js.map} +0 -0
- /package/dist/{open-interpreter-4PKL56AA.js.map → open-interpreter-I2CNOEXY.js.map} +0 -0
- /package/dist/{openclaw-BD56E5MV.js.map → openclaw-7EYBQS4R.js.map} +0 -0
- /package/dist/{opencode-W2RK4M7G.js.map → opencode-YS4WX2E2.js.map} +0 -0
- /package/dist/{openhands-5LNH3BKB.js.map → openhands-QMYIKNOS.js.map} +0 -0
- /package/dist/{package-2EAIYSJ4.js.map → package-LIPZKHAQ.js.map} +0 -0
- /package/dist/{pi-BUADR5MJ.js.map → pi-644FIN3A.js.map} +0 -0
- /package/dist/{qwen-code-TUJNHKNI.js.map → qwen-code-STDMX7EM.js.map} +0 -0
- /package/dist/{roo-code-L5F7S6QH.js.map → roo-code-DLPIHHQ6.js.map} +0 -0
- /package/dist/{serve-K62FW3V7.js.map → serve-ABTO2NA2.js.map} +0 -0
- /package/dist/{status-E5MCFZM6.js.map → status-J7SOUH7O.js.map} +0 -0
- /package/dist/{statusline-LIPF2KVP.js.map → statusline-QF4G724E.js.map} +0 -0
- /package/dist/{telemetry-4OC56NTM.js.map → telemetry-EICCFEIF.js.map} +0 -0
- /package/dist/{trae-Z7CQ2A2Q.js.map → trae-UOYD6JZZ.js.map} +0 -0
- /package/dist/{usage-3PB3WZSL.js.map → usage-VEVBWPLS.js.map} +0 -0
- /package/dist/{usage-event-KD5FW6W4.js.map → usage-event-GRQE7XWT.js.map} +0 -0
- /package/dist/{warp-4PPG5LOM.js.map → warp-QYJGKURM.js.map} +0 -0
- /package/dist/{windsurf-3T3RVXKM.js.map → windsurf-75LLZ37C.js.map} +0 -0
- /package/dist/{zed-ZF2OQ75O.js.map → zed-HKAZXEJW.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,248 +1,201 @@
|
|
|
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).
|
|
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>
|
|
72
47
|
|
|
73
|
-
##
|
|
48
|
+
## Quick start
|
|
74
49
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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/).
|
|
50
|
+
agent-connector is an **SDK connector developers depend on**. Add it to the
|
|
51
|
+
package that holds your connector, declare the connector once, then ship a
|
|
52
|
+
branded MCP package/bin such as `npx @acme/acme-db-mcp install` — it deploys to
|
|
53
|
+
every detected agent CLI in that host's own native config. Installing
|
|
54
|
+
`@ken-jo/agent-connector` globally is only an optional path for connector-free
|
|
55
|
+
token usage reports. The linear path is:
|
|
56
|
+
**get a server → declare it → install through your branded package**.
|
|
57
|
+
|
|
58
|
+
**0. You need an MCP server file first.** The config below points at
|
|
59
|
+
`./my-mcp-server.mjs`, so that file must exist before you install. Don't have an
|
|
60
|
+
MCP server yet? Copy
|
|
61
|
+
[`examples/acme-db/acme-db-mcp-server.mjs`](examples/acme-db/acme-db-mcp-server.mjs)
|
|
62
|
+
(a self-contained ~35-line stub) as `./my-mcp-server.mjs`, or follow the
|
|
63
|
+
[official MCP SDK quickstart](https://modelcontextprotocol.io/quickstart/server).
|
|
133
64
|
|
|
134
|
-
|
|
65
|
+
```bash
|
|
66
|
+
# 1. add agent-connector as a DEPENDENCY of your connector package
|
|
67
|
+
npm install @ken-jo/agent-connector
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```jsonc
|
|
71
|
+
// 2. package.json — this is the user-facing package identity
|
|
72
|
+
{
|
|
73
|
+
"name": "@acme/acme-db-mcp",
|
|
74
|
+
"mcpName": "io.github.acme/acme-db",
|
|
75
|
+
"bin": { "acme-db": "./bin.mjs" },
|
|
76
|
+
"dependencies": { "@ken-jo/agent-connector": "^0.4.92" }
|
|
77
|
+
}
|
|
78
|
+
```
|
|
135
79
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
80
|
+
```js
|
|
81
|
+
// 3. agent-connector.config.mjs — declare your server + hooks once
|
|
82
|
+
import { fileURLToPath } from "node:url";
|
|
83
|
+
import { defineConnector } from "@ken-jo/agent-connector";
|
|
140
84
|
|
|
141
|
-
|
|
85
|
+
const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
|
|
142
86
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
87
|
+
export default defineConnector({
|
|
88
|
+
// package.json / npm metadata is the source of truth. The host alias/runtime
|
|
89
|
+
// id and connector version are derived from name/mcpName/bin/version unless
|
|
90
|
+
// you need a multi-instance alias.
|
|
91
|
+
server: {
|
|
92
|
+
transport: "stdio",
|
|
93
|
+
command: "node",
|
|
94
|
+
args: [serverPath],
|
|
95
|
+
},
|
|
96
|
+
// hooks, telemetry, and more surfaces — see "What you define once" below
|
|
97
|
+
});
|
|
98
|
+
```
|
|
146
99
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
100
|
+
> While developing, `server.command` can be `node` + a local file path (as
|
|
101
|
+
> above); once your server is a published package, switch to `npx` + the package
|
|
102
|
+
> name (`command: "npx", args: ["-y", "@acme/acme-db-mcp"]`) — the form the
|
|
103
|
+
> [site quick-start](https://agent-connector.ai) teaches.
|
|
150
104
|
|
|
151
105
|
```bash
|
|
152
|
-
#
|
|
153
|
-
npx @
|
|
106
|
+
# 4. deploy under your branded MCP package/bin
|
|
107
|
+
npx @acme/acme-db-mcp detect # which platforms are installed here?
|
|
108
|
+
npx @acme/acme-db-mcp install --dry-run # preview every change first
|
|
109
|
+
npx @acme/acme-db-mcp install # write native config in each host
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> `install` targets only the hosts actually **detected** on this machine (or an
|
|
113
|
+
> explicit `--targets` / `connector.targets` list), intersected with the
|
|
114
|
+
> 42-adapter registry — there is no "install to all 42 unconditionally" path.
|
|
115
|
+
> `@ken-jo/agent-connector` is the framework dependency underneath; use it
|
|
116
|
+
> directly for development fallback or connector-free token telemetry, not as
|
|
117
|
+
> the foreground install brand for your users.
|
|
154
118
|
|
|
155
|
-
|
|
156
|
-
npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
|
|
119
|
+
## Ship it: direct install or a marketplace plugin
|
|
157
120
|
|
|
158
|
-
|
|
159
|
-
npx @ken-jo/agent-connector usage export --format csv --out usage.csv
|
|
160
|
-
```
|
|
121
|
+
Same one definition, your choice of distribution.
|
|
161
122
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
> To get **per-MCP / per-tool** numbers for an MCP, that MCP must be deployed and
|
|
167
|
-
> wrapped via a connector (the MCP-developer track and its `telemetry` command).
|
|
168
|
-
|
|
169
|
-
> **Coverage caveats.** Local readers (claude-code, codex, gemini-cli, …) report
|
|
170
|
-
> host-logged exact counts; a few readers are host-estimated (labeled in the
|
|
171
|
-
> `CONFIDENCE` column). Five "synced" platforms — **cursor, antigravity,
|
|
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.
|
|
123
|
+
**Direct install** — your branded command (`acme-db install`,
|
|
124
|
+
`npx @acme/acme-db-mcp install`) writes each host's native MCP + hook +
|
|
125
|
+
content-surface config in place, with no per-platform marketplace submission or
|
|
126
|
+
review. This is the Quick start path above.
|
|
191
127
|
|
|
192
|
-
agent-connector
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
128
|
+
**Marketplace plugin** — `agent-connector package` turns the connector into a
|
|
129
|
+
real plugin/extension bundle (manifest + bundled commands, agents, skills,
|
|
130
|
+
hooks, MCP) from one definition. Hooks + MCP keep the telemetry serve-wrapper,
|
|
131
|
+
so a marketplace-installed connector still reports per-tool tokens for its stdio
|
|
132
|
+
server. `--format all` emits **10 host formats**:
|
|
133
|
+
|
|
134
|
+
| Format | Hosts |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `claude-plugin` | Claude Code · Codex · VS Code Copilot · OpenClaw · OMP |
|
|
137
|
+
| `codex-plugin` | Codex (`.codex-plugin/` manifest variant) |
|
|
138
|
+
| `copilot-plugin` | GitHub Copilot CLI |
|
|
139
|
+
| `factory-plugin` | Droid |
|
|
140
|
+
| `gemini-extension` | Gemini CLI |
|
|
141
|
+
| `qwen-extension` | Qwen Code |
|
|
142
|
+
| `agy-plugin` | Antigravity (CLI + IDE) |
|
|
143
|
+
| `cursor-plugin` | Cursor |
|
|
144
|
+
| `kimi-plugin` | Kimi CLI |
|
|
145
|
+
| `npm-plugin` | OpenCode · Kilo CLI · Pi |
|
|
146
|
+
|
|
147
|
+
Two official **MCP standard artifacts** are opt-in (they need a `publish` block,
|
|
148
|
+
so they're excluded from `--format all`) — `mcp-server-json` (an MCP Registry
|
|
149
|
+
`server.json`) and `mcpb` (a one-click MCPB bundle); see
|
|
150
|
+
[Publish to the MCP ecosystem](#publish-to-the-mcp-ecosystem).
|
|
196
151
|
|
|
197
152
|
```bash
|
|
198
|
-
#
|
|
199
|
-
|
|
153
|
+
# emit every host format (mcp-server-json + mcpb are opt-in by name)
|
|
154
|
+
agent-connector package --format all --out ./dist-plugin
|
|
155
|
+
agent-connector package --format gemini-extension --out ./ext # or just one
|
|
200
156
|
|
|
201
|
-
#
|
|
202
|
-
|
|
203
|
-
#
|
|
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
|
|
157
|
+
# e.g. Claude Code: /plugin marketplace add ./dist-plugin/claude-plugin
|
|
158
|
+
# /plugin install <connector-id>@agent-connector
|
|
159
|
+
# e.g. Gemini CLI: gemini extensions install ./dist-plugin/gemini-extension/<id>
|
|
216
160
|
```
|
|
217
161
|
|
|
218
|
-
>
|
|
219
|
-
>
|
|
220
|
-
>
|
|
221
|
-
|
|
222
|
-
> **Optional convenience.** A global `npm i -g @ken-jo/agent-connector` is **not**
|
|
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.
|
|
162
|
+
> **Embedded-path caveat.** Most host bundles bake in the absolute home-bin
|
|
163
|
+
> launcher path of the machine that ran `package`, so they're valid for a
|
|
164
|
+
> **local install on that same machine/home**. For shared distribution use
|
|
165
|
+
> `npm-plugin` or the MCP standard artifacts, or re-run `package` per machine.
|
|
226
166
|
|
|
227
|
-
|
|
167
|
+
**Let your branded MCP package drive the host's own install flow** with
|
|
168
|
+
`install --method marketplace`:
|
|
228
169
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
`agent-connector/cli` export) exposes **every** agent-connector subcommand under
|
|
232
|
-
your brand, fully delegated and **auto-scoped** to your connector — so your
|
|
233
|
-
users never install agent-connector globally or type `--connector`. See
|
|
234
|
-
[`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
|
|
170
|
+
```bash
|
|
171
|
+
acme-db install --method marketplace
|
|
235
172
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
{
|
|
239
|
-
"name": "acme-db-tools",
|
|
240
|
-
"type": "module",
|
|
241
|
-
"bin": { "acme-db": "./bin.mjs" },
|
|
242
|
-
"dependencies": { "@ken-jo/agent-connector": "^0.4.0" }
|
|
243
|
-
}
|
|
173
|
+
# framework fallback for local framework development/debugging only
|
|
174
|
+
npx @ken-jo/agent-connector install --method marketplace --connector ./agent-connector.config.mjs
|
|
244
175
|
```
|
|
245
176
|
|
|
177
|
+
- **What it does** — stages the bundle, registers a local marketplace where the
|
|
178
|
+
host has one, then runs the host's plugin-install verb (or, for npm-plugin
|
|
179
|
+
hosts, writes a local `file://` entry); headless and idempotent. Other
|
|
180
|
+
marketplace-format hosts print the exact manual commands.
|
|
181
|
+
- **Host coverage** — live-verified for Claude Code, Codex, OpenCode, Kilo
|
|
182
|
+
(CLI + ext), and Antigravity (CLI + IDE) on Linux, Windows, and macOS; Droid
|
|
183
|
+
and Qwen Code have the driver shipped but pending a live host; Gemini CLI is
|
|
184
|
+
legacy (sunsetting toward Antigravity — driver kept for existing installs).
|
|
185
|
+
- **Safety + reversal** — a guard refuses installing the same connector by BOTH
|
|
186
|
+
methods, `uninstall --method auto` reverses whichever method is installed, and
|
|
187
|
+
`doctor` checks registration drift.
|
|
188
|
+
|
|
189
|
+
### Ship a branded CLI
|
|
190
|
+
|
|
191
|
+
A connector developer can ship their **own** bin instead of having users type
|
|
192
|
+
`agent-connector`. `createConnectorCli({ name, connector })` (from the
|
|
193
|
+
`@ken-jo/agent-connector/cli` export) exposes **every** subcommand under your
|
|
194
|
+
brand, fully delegated and **auto-scoped** to your connector — so your users
|
|
195
|
+
do not need a framework global install or `--connector` for branded MCP
|
|
196
|
+
install/doctor/uninstall. See
|
|
197
|
+
[`examples/branded-cli`](examples/branded-cli) for the full, runnable package.
|
|
198
|
+
|
|
246
199
|
```js
|
|
247
200
|
#!/usr/bin/env node
|
|
248
201
|
// bin.mjs — every agent-connector subcommand, branded as `acme-db`
|
|
@@ -258,142 +211,21 @@ process.exitCode = await createConnectorCli({
|
|
|
258
211
|
}).run();
|
|
259
212
|
```
|
|
260
213
|
|
|
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).
|
|
381
|
-
|
|
382
|
-
```bash
|
|
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
|
-
```
|
|
214
|
+
After a consumer installs **your** package, the `acme-db` bin is on their PATH
|
|
215
|
+
and every command is scoped to your connector (`acme-db install` ≈
|
|
216
|
+
`agent-connector install --connector ./agent-connector.config.mjs`). Auto-scoping
|
|
217
|
+
is pure argument injection over the SAME single home binary; `serve` and `hook`
|
|
218
|
+
still route through the one `~/.agent-connector` home binary every host config
|
|
219
|
+
points back to. An explicit `--connector` / `--connector-id` always overrides
|
|
220
|
+
the injected default.
|
|
390
221
|
|
|
391
|
-
|
|
392
|
-
> home-bin launcher path of the machine that ran `package`, so they're valid
|
|
393
|
-
> for a **local install on that same machine/home**. For shared distribution use
|
|
394
|
-
> `npm-plugin` or the 2 MCP standard artifacts, or re-run `package` per machine.
|
|
222
|
+
## What you define once
|
|
395
223
|
|
|
396
|
-
|
|
224
|
+
A single `defineConnector({...})` declares your MCP **server** + lifecycle
|
|
225
|
+
**hooks**, and optionally the additional surfaces — **commands**, **skills**,
|
|
226
|
+
**subagents**, **memory**, **statusline**, **actions**, plus host-native escape
|
|
227
|
+
hatches. agent-connector renders each surface into every detected host's native
|
|
228
|
+
format, or *skip-warns* (never silently drops) where a host can't support it.
|
|
397
229
|
|
|
398
230
|
```ts
|
|
399
231
|
import { fileURLToPath } from "node:url";
|
|
@@ -403,7 +235,6 @@ import { defineConnector } from "@ken-jo/agent-connector";
|
|
|
403
235
|
const serverPath = fileURLToPath(new URL("./my-mcp-server.mjs", import.meta.url));
|
|
404
236
|
|
|
405
237
|
export default defineConnector({
|
|
406
|
-
id: "acme-db",
|
|
407
238
|
server: {
|
|
408
239
|
transport: "stdio",
|
|
409
240
|
command: "node", // or "npx", "python", etc. — whatever starts your server
|
|
@@ -424,43 +255,7 @@ export default defineConnector({
|
|
|
424
255
|
});
|
|
425
256
|
```
|
|
426
257
|
|
|
427
|
-
|
|
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
|
-
`agent-connector install` turns that into, e.g.:
|
|
258
|
+
`npx @acme/acme-db-mcp install` turns that into, e.g.:
|
|
464
259
|
|
|
465
260
|
| Host | What gets written |
|
|
466
261
|
|---|---|
|
|
@@ -471,150 +266,80 @@ export default defineConnector({
|
|
|
471
266
|
…each pointing hooks at a **single stable home binary**, so one update propagates
|
|
472
267
|
everywhere.
|
|
473
268
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
Ship the rules every agent should follow when your MCP is installed:
|
|
477
|
-
|
|
478
|
-
```ts
|
|
479
|
-
memory: [
|
|
480
|
-
{
|
|
481
|
-
content:
|
|
482
|
-
"Use the acme-db MCP tools for schema questions; never hand-edit migrations.",
|
|
483
|
-
},
|
|
484
|
-
],
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
**Write the guidance once — it lands in the standard
|
|
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:
|
|
520
|
-
|
|
521
|
-
```ts
|
|
522
|
-
import { defineConnector, defineStatusline } from "@ken-jo/agent-connector";
|
|
269
|
+
**Secret env-refs (`${env:VAR}`).** Write `"${env:VAR}"` (or `"${env:VAR:-default}"`) anywhere in `command` / `args` / `env` / `url` / `headers` to reference an environment variable.
|
|
523
270
|
|
|
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
|
-
```
|
|
271
|
+
<details>
|
|
272
|
+
<summary>Native interpolation vs. literal-at-install resolution</summary>
|
|
535
273
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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:
|
|
274
|
+
> On hosts with **native** interpolation (Claude Code, Cursor, VS Code Copilot,
|
|
275
|
+
> amp, codebuff) the token is written through to the host config and resolved at
|
|
276
|
+
> runtime. Every other host has **no** native interpolation, so the value is
|
|
277
|
+
> resolved to a **literal at install time**; an unset variable with no default
|
|
278
|
+
> resolves to an **empty string**, and `install` emits a `warn` for it on a
|
|
279
|
+
> literal-resolving host.
|
|
566
280
|
|
|
567
|
-
|
|
568
|
-
import { defineConnector, defineAction } from "@ken-jo/agent-connector";
|
|
281
|
+
</details>
|
|
569
282
|
|
|
570
|
-
|
|
571
|
-
id: "acme-db",
|
|
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
|
-
```
|
|
283
|
+
**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 } } } }`.
|
|
586
284
|
|
|
587
|
-
|
|
588
|
-
|
|
285
|
+
<details>
|
|
286
|
+
<summary>Raw-payload semantics and the ~14 passthrough hosts</summary>
|
|
589
287
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
288
|
+
> The handler receives the host's **raw** payload and whatever it returns is the
|
|
289
|
+
> **verbatim** JSON reply (exit 0 only — exit-2 blocking isn't modeled). Hosts
|
|
290
|
+
> supporting host-native passthrough: `amp`, `claude-code`, `continue`,
|
|
291
|
+
> `copilot-cli`, `cursor`, `gemini-cli`, `hermes`, `jetbrains-copilot`, `kimi`,
|
|
292
|
+
> `nemoclaw`, `omp`, `openclaw`, `opencode`, `qwen-code`. Others skip-warn.
|
|
593
293
|
|
|
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).
|
|
294
|
+
</details>
|
|
598
295
|
|
|
599
|
-
`
|
|
600
|
-
`@ken-jo/agent-connector` and `@ken-jo/agent-connector/sdk`.
|
|
601
|
-
`ActionDef = { id, description?, run, hosts? }` and `ActionResult = { message? }`.
|
|
296
|
+
**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
297
|
|
|
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).
|
|
298
|
+
<details>
|
|
299
|
+
<summary>Set-if-absent + refcount + denylist semantics</summary>
|
|
610
300
|
|
|
611
|
-
|
|
301
|
+
> Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
|
|
302
|
+
> overwrite, never deep-merge. Ownership is refcounted in a persisted ledger;
|
|
303
|
+
> security-relevant keys and keys agent-connector models as first-class surfaces
|
|
304
|
+
> are hard-refused.
|
|
305
|
+
|
|
306
|
+
</details>
|
|
307
|
+
|
|
308
|
+
### Memory, statusline, actions, and the SDK
|
|
309
|
+
|
|
310
|
+
- **`memory`** (aligned with the [AGENTS.md](https://agents.md) standard) — ship
|
|
311
|
+
standing guidance that lands in `AGENTS.md` on 33 of the 42 hosts; the two that
|
|
312
|
+
don't read it (Claude Code → `CLAUDE.md`, Gemini CLI → `GEMINI.md`) are wired
|
|
313
|
+
per their own official docs. Writes are surgical marker-fenced, hash-stamped
|
|
314
|
+
managed blocks — multiple connectors coexist, bytes outside your markers are
|
|
315
|
+
never touched, and uninstall excises exactly your blocks.
|
|
316
|
+
- **`statusline`** (`defineStatusline`) — a live HUD render function the host
|
|
317
|
+
calls on every status refresh. v1 registers Claude Code's `settings.json.statusLine`
|
|
318
|
+
or Qwen Code's `settings.json.ui.statusLine` (set-if-absent, refcounted,
|
|
319
|
+
reversible); other hosts skip-warn. The runtime is **fail-safe**: any error
|
|
320
|
+
exits 0 with empty stdout so a HUD never wedges the host.
|
|
321
|
+
- **`actions`** (`defineAction`) — named, user-invocable operations dispatched by
|
|
322
|
+
the universal verb `agent-connector action <platform> <id> --connector <id>`.
|
|
323
|
+
`install` emits host-side affordances on `droid`, `hermes`, `nemoclaw`, `omp`,
|
|
324
|
+
`openclaw`, and `warp`; other hosts skip-warn. Error semantics are
|
|
325
|
+
user-triggered (unknown id or throw exits 1).
|
|
326
|
+
- **The Connector SDK** (`@ken-jo/agent-connector/sdk`, `/sdk/test`) — the
|
|
327
|
+
consolidated authoring surface re-exports `defineConnector`, the full `define*`
|
|
328
|
+
family (`defineHook`, `defineCommand`, `defineSkill`, `defineSubagent`,
|
|
329
|
+
`defineMemory`, `defineStatusline`, `defineAction`, `defineConfigPatch`,
|
|
330
|
+
`defineNativeHook`), introspection helpers (`hostsSupporting`,
|
|
331
|
+
`capabilitiesOf`, `surfaceSupport`), and an **offline harness**
|
|
332
|
+
(`simulate`, `explain`, `explainHooks`) that runs the real adapter
|
|
333
|
+
parse→handler→format chain to answer *"does my handler actually work on host
|
|
334
|
+
X?"* before you touch a real host. See
|
|
335
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
336
|
+
|
|
337
|
+
## How it works
|
|
612
338
|
|
|
613
339
|
- **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.
|
|
340
|
+
`~/.agent-connector` (override `AGENT_CONNECTOR_DATA_DIR`). Every host config we
|
|
341
|
+
write is a thin pointer back to that one binary. Updates are
|
|
342
|
+
**explicit/managed** (`agent-connector upgrade`), never silent auto-update.
|
|
618
343
|
- **Per-project data, kept.** Telemetry/state is keyed by a stable project
|
|
619
344
|
identity (git remote or normalized path), partitioned per project, stored under
|
|
620
345
|
the home data-root — surviving `git clean`, shared across hosts opening the same
|
|
@@ -623,45 +348,83 @@ verdict — intentional).
|
|
|
623
348
|
only framework-owned state lives under the data-root.
|
|
624
349
|
- **Windows-first correctness.** No symlinks, no POSIX-only assumptions.
|
|
625
350
|
|
|
351
|
+
**Three hook paradigms**, all install-verified across the 42-platform set
|
|
352
|
+
(see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)):
|
|
353
|
+
|
|
354
|
+
| Paradigm | Platforms |
|
|
355
|
+
|---|---|
|
|
356
|
+
| `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 |
|
|
357
|
+
| `mcp-only` (MCP registration only) | Warp · Roo Code · Cline · Trae · Zed · Codebuff · Mux · Pi · Windsurf · Open Interpreter · Junie · Mistral Vibe |
|
|
358
|
+
| `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw · Amp |
|
|
359
|
+
|
|
360
|
+
Adding a platform = **one registry entry + one adapter**.
|
|
361
|
+
|
|
626
362
|
## CLI
|
|
627
363
|
|
|
628
364
|
| Command | Purpose |
|
|
629
365
|
|---|---|
|
|
630
366
|
| `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
|
|
367
|
+
| `install [--scope …] [--targets …] [--method …] [--dry-run] [--force]` | Render + write MCP + hooks + content surfaces across targets. |
|
|
368
|
+
| `uninstall [--targets …] [--purge] [--method …]` | Full inverse — removes everything we wrote; `--purge` also clears framework state. |
|
|
369
|
+
| `upgrade [--channel …]` | Re-render host config + heal stale pointers + refresh the home binary (alias: `update`, `sync`); never a silent self-update. |
|
|
370
|
+
| `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
371
|
| `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 [--
|
|
372
|
+
| `package [--format <fmt>\|all]` | Emit a host plugin bundle, or an OFFICIAL standard artifact: `mcp-server-json` (registry) · `mcpb` (one-click bundle). |
|
|
373
|
+
| `action <platform> <id> [--connector <id>]` | Run a declared action from the shell. |
|
|
374
|
+
| `telemetry report [--by …] [--since …] [--connector <id>]` | Per-tool token footprint of **your connector's own wrapped server**. Stdio servers only. |
|
|
375
|
+
| `telemetry export [--format …] [--connector <id>]` | Raw aggregate records for your wrapped server. |
|
|
376
|
+
| `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. |
|
|
377
|
+
| `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
378
|
|
|
642
379
|
> `hook` and `serve` also exist — internal entrypoints the written host configs
|
|
643
380
|
> point at; you never run them by hand. Full flag-level reference: the
|
|
644
381
|
> [docs site `/docs/dev/cli`](https://agent-connector.ai/docs/dev/cli) · `llms-full.txt` §3 (canonical, drift-guarded by tests).
|
|
645
382
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
383
|
+
## Token telemetry & usage
|
|
384
|
+
|
|
385
|
+
Two independent, never-summed views of token cost:
|
|
386
|
+
|
|
387
|
+
- **Per-tool telemetry for *your own* server** (the MCP-developer path). No host
|
|
388
|
+
reports per-tool usage back to an MCP server, so agent-connector measures your
|
|
389
|
+
server's *own* bytes (args in, results out, tool schemas) and tokenizes them
|
|
390
|
+
locally — **aggregate counts only, stored locally, zero egress by default.**
|
|
391
|
+
Per-tool telemetry is automatic for **stdio** servers; remote (`http`/`sse`/`ws`)
|
|
392
|
+
servers are registered but not wrapped (the proxy can't intercept remote
|
|
393
|
+
transports). Read it with `agent-connector telemetry report --by tool`.
|
|
394
|
+
- **Connector-free usage** (`agent-connector usage`). Already run Claude Code /
|
|
395
|
+
Codex / Cursor and just want totals? `usage` reads your local agent-CLI session
|
|
396
|
+
logs **read-only** and never writes any host config — no connector, no install:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
npx @ken-jo/agent-connector usage report --by platform # CLI/model/project/session/day
|
|
400
|
+
npx @ken-jo/agent-connector usage leaderboard --by platform # or --by model
|
|
401
|
+
npx @ken-jo/agent-connector usage export --format csv --out usage.csv
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
It reports **whole-conversation totals** per agent CLI / model / project /
|
|
405
|
+
session / day. It does **not** itemize cost by individual MCP server or tool —
|
|
406
|
+
agent CLIs don't log per-tool attribution.
|
|
407
|
+
|
|
408
|
+
**Privacy & tokenizer.** Default tokenizer is `gpt-tokenizer` (pure-JS, no native
|
|
409
|
+
build) — `o200k_base` for OpenAI/Codex-family, a documented approximation for
|
|
410
|
+
Anthropic; falls back to a `chars/4` heuristic if it can't load. Every record
|
|
411
|
+
carries a confidence tag. Raw tool arguments and results are never stored or
|
|
412
|
+
transmitted. Off switch: `AGENT_CONNECTOR_TELEMETRY=0`, or
|
|
413
|
+
`telemetry: { enabled: false }`.
|
|
651
414
|
|
|
652
415
|
## Publish to the MCP ecosystem
|
|
653
416
|
|
|
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
|
|
417
|
+
Where the MCP standard already covers your server's functionality,
|
|
418
|
+
agent-connector **emits the standard exactly** so your already-standard work is
|
|
419
|
+
portable:
|
|
420
|
+
|
|
421
|
+
- **`package --format mcp-server-json`** → an official **MCP Registry**
|
|
422
|
+
`server.json` (schema `2025-12-11`). It describes your **real upstream server**
|
|
423
|
+
(what a registry installer runs), not our telemetry wrapper. Publish it with
|
|
424
|
+
the official `mcp-publisher` CLI.
|
|
425
|
+
- **`package --format mcpb`** → an official **MCPB** (`.mcpb`, formerly DXT)
|
|
426
|
+
bundle `manifest.json` (`manifest_version 0.3`) for one-click local install in
|
|
427
|
+
Claude Desktop and any MCPB host, with secrets routed through the host keychain
|
|
665
428
|
(`user_config`).
|
|
666
429
|
|
|
667
430
|
Both read a `publish` block on your connector (the namespace you own + your
|
|
@@ -669,8 +432,6 @@ published package + author):
|
|
|
669
432
|
|
|
670
433
|
```ts
|
|
671
434
|
defineConnector({
|
|
672
|
-
id: "acme-db",
|
|
673
|
-
version: "1.2.0",
|
|
674
435
|
server: { transport: "stdio", command: "npx", args: ["-y", "@acme/acme-db-mcp"] },
|
|
675
436
|
publish: {
|
|
676
437
|
registryNamespace: "io.github.acme", // a namespace YOU proved ownership of
|
|
@@ -682,32 +443,34 @@ defineConnector({
|
|
|
682
443
|
|
|
683
444
|
> **Config we write is the standard.** `install` writes each host's native MCP
|
|
684
445
|
> config in the de-facto canonical `mcpServers` shape — `{ command, args, env }`
|
|
685
|
-
> for stdio, `{ url, headers }` for remote
|
|
686
|
-
>
|
|
687
|
-
>
|
|
688
|
-
>
|
|
446
|
+
> for stdio, `{ url, headers }` for remote. The spec transport slug for
|
|
447
|
+
> streamable HTTP is `streamable-http` (registry `server.json`); host configs
|
|
448
|
+
> canonically use `http`. WebSocket (`ws`) is **not** an MCP spec transport and
|
|
449
|
+
> the standard artifacts reject it.
|
|
689
450
|
|
|
690
451
|
> **Forward-compatible by transport.** The `serve` proxy is **byte-transparent**:
|
|
691
452
|
> 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
|
|
453
|
+
> `tools/call` round-trips. So newer MCP features ride through untouched —
|
|
454
|
+
> **MCP Apps** (the official `io.modelcontextprotocol/ui` extension) and **any
|
|
696
455
|
> reverse-DNS extension** negotiated at `initialize`. A connector whose server
|
|
697
456
|
> 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
|
-
|
|
457
|
+
> no agent-connector change required.
|
|
458
|
+
|
|
459
|
+
## Verification
|
|
460
|
+
|
|
461
|
+
The full single-API contract is **install-verified across all 42 platforms** by
|
|
462
|
+
a committed registry-driven install-roundtrip harness that, for every adapter,
|
|
463
|
+
drives the real install → uninstall into an isolated HOME and asserts on-disk
|
|
464
|
+
placement + zero residue. A separate committed `scripts/verify-host.mjs` driver
|
|
465
|
+
installs **20 real host CLIs** and verifies install → placement →
|
|
466
|
+
clean-uninstall, and live hook dispatch + telemetry are proven end-to-end on
|
|
467
|
+
several of them. The remaining hosts (IDE extensions / GUI editors with no
|
|
468
|
+
headless CLI) stay covered by the install-roundtrip harness.
|
|
469
|
+
|
|
470
|
+
**Dogfood result:** porting the real multi-host context-mode plugin to
|
|
471
|
+
`defineConnector` collapsed **~20,322 lines of hand-maintained per-host code down
|
|
472
|
+
to ~76 lines** (a 99.63% reduction). See the reports under
|
|
473
|
+
[`docs/research/`](docs/research/) and [`CHANGELOG.md`](CHANGELOG.md).
|
|
711
474
|
|
|
712
475
|
## Development
|
|
713
476
|
|