Telemetry
Overview#
The only data identical across hosts is the server's own bytes. The agent-connector serve proxy intercepts every tools/call at the server boundary and tokenizes input and output locally.
Input = params.arguments, output = result.content[] + structuredContent. With measureToolDefs (default on) it also tokenizes the tools/list schemas once → the fixed "cost of merely defining my tools" per-turn overhead. This measures the server your connector declares and wraps; to see per-CLI token totals without authoring a connector, use the connector-free usage track instead.
# a wrapped MCP entry runs the real server behind the telemetry proxy:
agent-connector serve --connector acme-db -- npx -y @acme/acme-db-mcpTelemetryConfig#
| Field | Type | Default | Notes |
|---|---|---|---|
enabled | boolean | true | AGENT_CONNECTOR_TELEMETRY=0 also kills it. |
modelFamilyHint | "auto" | "openai" | "anthropic" | "generic" | "auto" | Tokenizer family selection; auto infers from client/host. |
measureToolDefs | boolean | true | Tokenize tools/list once → fixed per-turn tool-definition overhead. |
calibration | { anthropicCountTokens?: boolean } | false | Opt-in network calibration (sends content off-box). |
hostNativeUsage | boolean | false | Opt-in host-native turn capture. Also forced via AGENT_CONNECTOR_HOST_NATIVE=1. |
store | "ndjson" | "sqlite" | "ndjson" | NDJSON needs no native deps; sqlite is a drop-in upgrade. |
telemetry: {
enabled: true, // AGENT_CONNECTOR_TELEMETRY=0 kills it
modelFamilyHint: "auto", // auto | openai | anthropic | generic
measureToolDefs: true, // tokenize tools/list once → per-turn overhead
hostNativeUsage: false, // opt-in; AGENT_CONNECTOR_HOST_NATIVE=1
store: "ndjson", // or "sqlite"
}Tokenizer#
Default gpt-tokenizer (pure-JS, no native build → Windows/single-binary safe): o200k_base for every family — exact for OpenAI/Codex-family, and a documented approximation for Anthropic-family (no offline Claude tokenizer ships). Family is auto-selected from initialize.clientInfo or modelFamilyHint. Fallback is a plain chars/4 heuristic — explicitly labeled so it's never mistaken for exact. Separately, binary content blocks (image/audio/resource) are never base64-tokenized — each gets a flat per-modality token estimate (~85 each).
Confidence sources#
Every telemetry row carries one confidence source:
| Source | Meaning |
|---|---|
tokenizer-exact | Local gpt-tokenizer match for the host's family (o200k_base). |
tokenizer-approx | o200k_base used as a documented approximation for non-OpenAI families — Anthropic/Claude and the generic family (Gemini and any unrecognized host); no offline Claude tokenizer ships. |
heuristic | chars/4 fallback (no content-type awareness — when an encoder loads, binary content blocks get a flat per-modality estimate that is labeled tokenizer-approx, not heuristic, and base64 is never tokenized); explicitly labeled. |
tokenizer-calibrated | Opt-in Anthropic count_tokens sampler (sends content off-box) refines a row. |
host-native | Real host usage (e.g. Gemini usageMetadata.totalTokenCount) via the opt-in AfterModel hook. |
Store#
Local, under the data-root, aggregate counts only — never raw args/results. MVP is an append-atomic NDJSON event log + derived rollups behind a TelemetryStore interface (store: "sqlite" is a drop-in upgrade). Rows are keyed roughly by connectorId, toolName, scope (call|tool_defs|model_turn|hook), hostPlatform, sessionId, projectKey, projectDir, inputTokens, outputTokens, confidenceSource, isError, ts.
Host usage layer#
A separate read-only subsystem (src/usage/) parses each agent CLI's native logs/DBs (JSONL / JSON / SQLite via pure-WASM sql.js / synced-cache artifacts) to report per-platform/project/session/model/day usage. Confidence is host-reported (real numbers) vs host-estimated (e.g. Kiro char/4, Crush cost-only). It never writes host config and never collides with the serve-proxy store. Some hosts (cursor / antigravity / antigravity-cli / trae / warp) need an external sync agent-connector does not perform → those rows are "requires sync, skipped" unless a local cache already exists.