agent-connector · git:20260624.09226fc · 2026-06-24 · sha256 10220814728d0411
agent-connector git:20260624.09226fcA
Immutable. This exact content is served forever at /api/v1/blob/10220814728d0411.
---
name: agent-connector
description: Two audiences. (A) MCP DEVELOPER — add agent-connector as a framework dependency inside a developer-branded MCP package, write the server/hooks/surfaces ONCE with defineConnector({...}), and ship install/doctor/uninstall through the branded package/bin (for example `npx @acme/acme-db-mcp install`) across every detected AI-agent CLI in the 42 registered deploy adapters, with default local-first per-tool token telemetry for YOUR OWN wrapped stdio server. package.json name/mcpName/bin/version are the default metadata source; explicit id/mcp.hostAlias/version are advanced overrides only. (B) AGENT-CLI END USER — with NO connector at all, run `agent-connector usage` to see per-CLI / per-model token totals scanned read-only from each agent CLI's own session logs. Use this when a developer wants one integration to reach many agent hosts and to see which of their own server's tools cost the most context, OR when any agent-CLI user wants whole-conversation token totals per CLI/model with zero setup.
---
# agent-connector
agent-connector serves two distinct audiences and the work forks between them:
- **(A) MCP developer** — depends on agent-connector as a framework inside their
own branded MCP package, writes an integration once with `defineConnector()`,
and ships their MCP server + lifecycle hooks (+ commands / skills / subagents /
memory) across every detected agent CLI through their own package/bin. It solves two dev problems: (1) each agent host re-invents
MCP registration + lifecycle hooks with incompatible config files, root keys, formats
(JSON/JSONC/TOML/YAML/exported TS), and event names; (2) no host reports per-tool
token usage back to an MCP server. Write the integration once; the branded CLI renders it into
each installed host's native dialect and measures the developer's OWN wrapped stdio
server's per-tool token footprint locally.
- **(B) Agent-CLI user** — has NOT authored a connector and just runs an agent CLI
(Claude Code, Codex, Cursor, …). Their entire supported surface is one connector-free
command, `agent-connector usage`, which reads each agent CLI's own session logs
read-only to show per-CLI / per-model token totals. No `defineConnector`, no install,
no config file.
The one accuracy-critical line between them: if you BUILD an MCP integration,
agent-connector is the framework underneath your branded package/bin, which deploys
it everywhere and measures your own server's per-tool tokens. If you just USE agent CLIs, agent-connector reads their logs to show you per-CLI /
per-model token totals — whole-conversation only, never itemized per MCP or per tool.
## When to reach for it
- **(A) MCP developer** wants to ship ONE MCP server (and/or hooks / slash commands /
Agent Skills / subagents / standing memory guidance) across many agent CLIs without
hand-authoring N config dialects → `defineConnector` + a branded package/bin
command such as `npx @acme/acme-db-mcp install`.
- **(A) MCP developer** asks "which of MY OWN server's tools cost the most context?" →
`telemetry report --by tool` / `telemetry leaderboard --by mcp|tool`. Requires a
declared connector with a wrapped stdio server (per-tool counts exist only for the
server your connector declares and wraps; remote http/sse/ws servers are not wrapped).
- **(B) Agent-CLI user (no connector needed)** wants to compare token spend across the
agent CLIs on their machine → `usage` (alone). This reports WHOLE-CONVERSATION totals
per CLI / model / project / session / day — it does NOT and cannot itemize cost per
individual MCP server or per tool, because agent CLIs do not log per-tool token
attribution. For per-MCP/per-tool numbers, that MCP must be deployed and wrapped via a
connector (the developer track above).
Do NOT use it to author a brand-new MCP server protocol — it deploys + measures an
existing server command/URL and wraps lifecycle hooks; it does not implement tools.
## Write once: defineConnector({...})
Create `agent-connector.config.mjs` (or `.js` / `.json`) at the project root:
```ts
import { defineConnector } from "@ken-jo/agent-connector";
export default defineConnector({
// package.json name/mcpName/bin/version are the default metadata source.
// Set id or mcp.hostAlias only for legacy configs or multi-instance aliases.
// MCP server — declared once, transport-polymorphic. Omit for a hooks-only connector.
server: {
transport: "stdio", // stdio | http | sse | ws
command: "npx", // stdio: command required; remote: url required
args: ["-y", "@acme/acme-db-mcp"],
env: { ACME_DB_DSN: "${env:ACME_DB_DSN}" }, // universal ${env:VAR} / ${env:VAR:-default}
tools: { include: ["*"] },
timeoutMs: 30_000,
// wrapForTelemetry defaults true for stdio when telemetry is on
},
// Lifecycle hooks — 13 canonical events (SessionStart, SessionEnd, UserPromptSubmit,
// PreToolUse, PostToolUse, PreCompact, Stop, Notification, PermissionRequest,
// PostToolUseFailure, SubagentStart, SubagentStop, PostCompact); the framework
// synthesizes the right entrypoint per host paradigm (json-stdio binary /
// ts-plugin module / skip on mcp-only). Hosts without a native analog skip-warn —
// never silently dropped.
hooks: {
PreToolUse: {
matcher: "acme_write", // regex on tool name; empty = all
async handler(evt) {
return evt.toolName === "acme_write"
? { decision: "ask", reason: "Confirm Acme DB write" } // allow|deny|modify|context|ask
: { decision: "allow" };
},
},
SessionStart: {
async handler() {
return { decision: "context", additionalContext: "Acme DB schema v12 loaded." };
},
},
},
// Content surfaces (all optional, content-only files; written where supported).
commands: [
{ name: "db-report", description: "Summarize the schema", prompt: "Report on {{schema}}.", argumentHint: "[schema]" },
],
skills: [
{ name: "db-helper", description: "Guides DB queries; use when the user asks about the schema.",
body: "# DB helper\nUse acme_query first...", resources: { "references/api.md": "..." } },
],
// subagents: [{ name: "db-auditor", description: "...", prompt: "..." }],
// Standing guidance (memory) — written ONCE as a marker-fenced, hash-stamped
// managed block into the memory file each host actually reads: the standard
// AGENTS.md on most supporting hosts, CLAUDE.md on Claude Code (opt-in
// `platforms["claude-code"].memory.mode: "agents-import"` manages an @AGENTS.md
// bridge instead), GEMINI.md on Gemini CLI. User edits inside the block are
// hash-detected and never clobbered (`install --force` overrides after a backup);
// uninstall excises exactly your block. 16 KiB hard cap / 4 KiB soft warn.
memory: [
{ content: "Use the acme-db MCP tools for schema questions; never hand-edit migrations." },
],
telemetry: { enabled: true, modelFamilyHint: "auto", measureToolDefs: true }, // ON by default
// Per-platform escape hatches: disable a surface, force scope, merge `extra`
// verbatim; `nativeHooks` wires ANY host hook event outside the 13 normalized
// ones by its verbatim name on adapters with supportsNativeHooks; `configPatch`
// patches claude-code host-exclusive settings keys (set-if-absent + skip-warn,
// refcounted ownership, sensitive-key denylist, reversible uninstall).
platforms: {
warp: { hooks: false },
"claude-code": {
nativeHooks: {
TaskCompleted: { async handler(evt) { /* evt.raw = host JSON, verbatim */ } },
},
configPatch: [{
key: "statusLine", // dotted LEAF path into settings.json
value: { type: "command", command: "acme-db statusline" },
reason: "Render the Acme meter in Claude Code's status line",
}],
// memory: { mode: "agents-import" }, // or memory: { path: "docs/AGENTS.md" }
},
},
targets: "auto", // "auto" = all detected, or e.g. ["claude-code","codex"]
});
```
A connector must declare at least one of `server`, `hooks`, `commands`, `skills`,
`subagents`, or `memory` (or a per-platform `nativeHooks` / `configPatch`
declaration). `defineConnector` validates eagerly and throws `ConnectorConfigError`
on bad ids or missing derivable package identity, non-function handlers, duplicate surface names, oversized skill
descriptions (>1024 chars), unsafe skill `resources` paths, memory content over the
16 KiB hard cap (or containing the literal managed-block marker tokens), a
`nativeHooks` key that names one of the 13 normalized events (use `hooks` for
those), or a `configPatch` key in the agent-connector namespace (`hooks*`,
`mcpServers*` — the sensitive-key denylist is enforced at install).
## CLI workflow
```bash
npm install @ken-jo/agent-connector # framework dependency of your MCP package
cd my-mcp-project
npx @acme/acme-db-mcp detect # user-facing path: your branded package/bin
npx @acme/acme-db-mcp install --dry-run # preview every change, everywhere (nothing written)
npx @acme/acme-db-mcp install # deploy across detected hosts
npx @acme/acme-db-mcp doctor [--probe] # health checks; --probe spawns the real stdio server: initialize → ping → tools/list
npx @acme/acme-db-mcp uninstall # full inverse — removes everything install wrote
npx @ken-jo/agent-connector install --dry-run --connector ./agent-connector.config.mjs
# development fallback / CI-debug path; not the foreground install brand for users
```
`--scope` is `user` (default) or `project`. `--targets` is a comma-separated
PlatformId list. `--dry-run` works on install/upgrade/uninstall. `--connector <path>`
points at a config explicitly; otherwise it's found by walking up from the project.
`install --force` additionally overwrites USER-EDITED memory managed blocks (hash
drift) after a timestamped backup — the default is warn-and-leave. Canonical
flag-level reference: `llms-full.txt` §3 / the docs site `/docs/dev/cli`.
## Telemetry, leaderboards, usage
There are two completely separate token-measurement axes, split by audience. They
measure DIFFERENT things and are NEVER summed.
**Axis 1 — `telemetry` / 🔌 (MCP-developer track, the developer's OWN wrapped server).**
Telemetry is ON by default: stdio servers are wrapped with `agent-connector serve` so
every `tools/call` is measured (args in, results out, plus the one-time `tools/list`
schema cost) and tokenized locally. This is the ONLY source of per-MCP and per-tool
numbers, and it exists only for a server a registered connector declares and wraps —
`serve` loads the connector by id and every record requires a connector id, so an
arbitrary third-party MCP the user didn't author produces nothing here. Wrapping is
stdio-only; remote (http/sse/ws) servers are registered but never wrapped. Every record
carries a confidence tag (`tokenizer-exact | tokenizer-calibrated | tokenizer-approx |
heuristic | host-native`).
```bash
agent-connector telemetry report --by tool --since 7d # ranked per-tool footprint (also session|project)
agent-connector telemetry export --format csv --out tel.csv
agent-connector telemetry leaderboard --by mcp # which of YOUR servers costs most (also --by tool | --by surface)
```
**Axis 2 — `usage` / 🖥️ (agent-CLI-user track, host-log scan, NO connector needed).**
Reads each agent CLI's OWN session logs/DBs read-only and aggregates WHOLE-CONVERSATION
totals. It groups ONLY by `platform | project | session | model | day` — there is NO
per-MCP or per-tool dimension, because agent CLIs do not log per-tool token attribution.
Use this for "which agent CLI / model is burning the most tokens?"; never read it as
"which MCP/tool costs the most." Local readers report host-logged counts; a few are
host-estimated (shown in the CONFIDENCE column); 5 "synced" platforms (cursor,
antigravity, antigravity-cli, trae, warp) are skipped as "requires sync" unless a local
cache already exists.
```bash
npm i -g @ken-jo/agent-connector # optional: connector-free token telemetry utility
agent-connector usage report --by platform --since 7d # whole-conversation totals from CLI logs (also project|session|model|day)
agent-connector usage leaderboard --by platform # which CLI/host spent the most (also --by model)
agent-connector usage export --format csv --out usage.csv
```
The unified `agent-connector leaderboard` shows three origin-labeled boards with
DIFFERENT prerequisites — never summed: 🔌 per-MCP (needs a connector + serve traffic),
🛰️ live host-native turns (needs the opt-in usage hook, installed only by the Gemini CLI
and Antigravity adapters, and a connector at runtime), and 🖥️ host usage (the only board
that works with no setup — same whole-conversation, per-CLI/per-model scan as `usage`).
For a plain agent-CLI user with no connector, 🔌 and 🛰️ are empty; `usage` is the
primary end-user entry point precisely because only its data source is connector-free.
## Operating model
- **Home-dir single binary.** Runtime installs once under `~/.agent-connector`
(override `AGENT_CONNECTOR_DATA_DIR`). Every host config we write is a thin
pointer to that one stable binary, so one managed `agent-connector upgrade`
propagates everywhere — never silent auto-update.
- **Per-project data.** Telemetry/state is keyed by project identity (git remote or
normalized path), stored under the home data-root — survives `git clean`, shared
across hosts opening the same project. Native host config files are never relocated.
- **Windows-first.** No symlinks, no POSIX-only assumptions.
## Privacy / opt-out
Aggregate counts only — raw tool arguments and results are never stored or
transmitted. Local-first, zero network egress by default. Opt out via
`AGENT_CONNECTOR_TELEMETRY=0` or `telemetry: { enabled: false }`. Network
calibration (Anthropic `count_tokens`) and host-native turn capture are opt-in only.