MCP usage telemetry
repowise mcp-log controls RepoWise's pseudonymous MCP usage
telemetry — a lightweight, per-hour "heartbeat" the listener sends so
we can see whether the MCP server is being used, how much, and whether
it is healthy.
The heartbeat is on by default and carries counts only — no
source code, no file paths, no query content, no arguments. It is
pseudonymous, not anonymous: it is tied to your authenticated
session and is attributable to your account via a server-derived
identifier (see What is never sent
below). Because it is personal data, it is included in your GDPR data
export and is erased when you delete your account. You can opt out of
future heartbeats at any time with repowise mcp-log off.
Verbs
repowise mcp-log on # opt back in to the usage heartbeat
repowise mcp-log off # opt out — disables the heartbeat
repowise mcp-log status # show current opt-in state + endpoint
What the heartbeat contains
Once per hour, for each active tenant, the listener POSTs a small JSON document of aggregate counters (no per-call detail):
{
"listenerVersion": "0.1.0",
"windowStartsAt": "2026-06-29T10:00:00.000Z",
"toolCounts": { "find_symbol": 42, "get_impact": 7 },
"statusCounts": { "ok": 46, "error": 2, "timeout": 1, "rejected": 0 },
"missCounts": { "find_symbol": 3 },
"healthCounters": { "graphNotLoaded": 0, "unknownRepo": 0,
"lspDisabled": 0, "lspUnavailable": 1,
"connectFail": 0, "preAuthFail": 0 }
}
toolCounts— how many times each MCP tool was invoked.statusCounts— outcome tallies:ok/error/timeout/rejected.missCounts— per-tool "coverage miss" tallies (a query that returned an empty result, e.g. a symbol we couldn't find). These drive graph + documentation coverage improvements.healthCounters— "broken MCP" signals: graph not loaded, unknown repo, LSP disabled, LSP unavailable (language server not installed/unsupported), connect failures, pre-auth failures.listenerVersion— the listener CLI version, for fleet version-spread telemetry.
What is never sent: file contents, file paths, symbol names, query
strings, arguments, response bodies, or any AI-generated text. The
payload is counts and version only. No identity fields ride the
wire. Instead, both your tenantId and — when the per-user dimension
is enabled — an opaque per-seat identifier (your Cognito sub) are
derived server-side from your authenticated session and stamped onto
the stored counts. That server-derived sub is a pseudonym: it maps
back to your account (which is why these counts are treated as
pseudonymous personal data, exportable and erasable), but your email and
name are never stored on the heartbeat row itself.
Legal basis & retention
The heartbeat rides RepoWise's Service Telemetry basis
(Terms of Service §V.0(b) / Privacy Policy §I.3) — the same basis used
by our other operational metrics. The pseudonymous, server-derived
tenantId (and, when enabled, per-seat sub) is retained for
approximately 24 months (Privacy Policy §XI), then aged out
automatically.
Because the heartbeat is pseudonymous personal data rather than anonymous data, it is:
- Included in your GDPR Art. 15 data export — the ops compliance
export emits an
mcpUsageHeartbeatsection covering the full 24-month retention window for your tenant. - Erased on account deletion (GDPR Art. 17) — when you request
deletion, every heartbeat row scoped to your tenant is deleted on a
best-effort basis alongside the S3 context purge. The immortal consent
audit row (
MCP_LOG_CONSENT#) is deliberately not touched — it is the Art. 7(1) proof-of-consent trail and is retained regardless.
Opting out
repowise mcp-log off # stop sending the heartbeat
repowise mcp-log on # start again
off writes enabled: false to a local flag at
~/.repowise/mcp-log.flag. The listener re-reads this flag on every
tick, so opting out takes effect at the next heartbeat without
restarting the listener — no further heartbeats are sent. Opting out is
a local control; it does not delete previously collected aggregate
counters, and the server-side consent audit row is preserved (GDPR
Art. 7(1)).
Operators can additionally disable the heartbeat fleet-wide with the
REPOWISE_MCP_HEARTBEAT_DISABLED (listener) and
REPOWISE_MCP_HEARTBEAT_TELEMETRY_DISABLED (server) kill-switches.
Raw per-call logging is disabled
RepoWise previously shipped an experimental raw per-call query log (one encrypted JSONL line per MCP call, including the query arguments). That pipeline is currently disabled — the listener no longer collects it by default and it is never uploaded. It required redaction and consent work that has not landed, so it is inert pending that effort. The pseudonymous heartbeat above is the only active MCP telemetry.
The typed-resolution sidecar (separate upload)
Distinct from telemetry: to power typed code intelligence (accurate
go-to-definition, call hierarchies, type-aware impact), the listener
runs language servers locally and uploads a structural sidecar for
the repositories you analyze. This sidecar contains structural code
metadata — file paths, symbol and method names, and call-site
coordinates (line/column) — so the server can resolve references
precisely. It is not MCP usage telemetry and is not controlled
by repowise mcp-log; it is part of analyzing your repository. It does
not include file contents. See your plan's data-handling terms for
details.