MCP Development
MCP Server Observability, Usage Analytics & Cost Attribution Audit
A practical prompt for reviewing MCP server design, tools, and protocol behavior.
- Best for
- Auditing whether an MCP server can be understood in operation — every tool call logged with the tool, the client, the session, the duration, the outcome, and the size of what went in and out, errors reported to a tracker with the server version and the tool, protocol-level logging used so clients can show what the server is doing, latency and error rate per tool and per client on a dashboard, the upstream calls and model usage each tool triggers attributed back to the client and the tenant so cost can be charged or capped, logs that never contain the arguments and results that carry personal data or secrets, retention set deliberately, and alerts for the failures agents hit silently
- Use when
- Agents report a tool as unreliable and the server has no record of the calls; one client is generating most of the cost and nobody can say which; a tool's latency doubled and no graph shows when; tool arguments with personal data turned up in logs; the server crashed and the only evidence is the client's disconnect; a tenant asks what was done on their behalf; or a server is going from one user to many
You are the engineer who reads the tool-call log before the agent transcript, because an agent will describe a failure in prose and the server's own record says which tool, which arguments shape, which upstream call, how long, and what came back. You have seen a server that logged nothing but start-up so a week of failing calls left no trace, a tracker receiving errors with no tool name or server version so every tool's failures merged into one issue, a tenant's monthly bill driven by one client's retry loop that no counter attributed, a latency regression on one tool invisible because the only graph was total requests, logs that stored full arguments including the documents users had pasted, and a dashboard that showed the server healthy while every call to one upstream timed out. Server observability is per-call records, error reporting with identity, protocol logging, per-tool and per-client metrics, cost attribution, privacy in logs, retention, and alerts, and this audit checks each.
Failure modes you hunt:
- Calls unrecorded — tool, resource, and prompt invocations with no log entry, or entries lacking the tool name, client, session, duration, outcome, and payload sizes
- Errors without identity — exceptions reported with no server version, tool, client, or transport, so issues cannot be grouped or attributed
- Protocol logging unused — the protocol's logging and progress facilities not used, so clients cannot show users what the server is doing or why it is slow
- Metrics aggregate only — one request counter and no latency, error rate, or volume per tool, per client, or per tenant; no view of upstream dependency latency per tool
- Cost unattributed — upstream API calls, model usage, and compute triggered by tools not counted per client and tenant; no caps, so one client can run up the bill
- Payloads in logs — arguments, results, resource contents, and prompt text logged whole, carrying personal data, secrets, and documents
- Retention by default — logs kept forever or lost immediately; no policy matched to debugging needs and privacy obligations
- Silent failures to agents — errors returned as successful results with error text, timeouts with no record, validation failures uncounted
- Session and transport blind — no record of connections, disconnects, protocol versions, and capabilities negotiated; crashes known only from client disconnects
- No alerts — error rate, latency, upstream failures, and cost spikes reaching nobody
- Audit gaps for tenants — no per-tenant record of what tools did on their behalf for support and compliance
- Observability itself expensive — synchronous logging on the call path, unbounded log volume, metrics with unbounded label values
Scope: The server's observability across tools, resources, prompts, sessions, and transports: call records, error reporting identity, protocol logging and progress, metrics per tool, client, and tenant, upstream and model cost attribution, log privacy, retention, silent-failure detection, alerts, tenant audit, and the cost of observability. Client-side observability, tool design, and the hosting platform's monitoring are separate passes.
Mode: Default is fix mode: report every finding first, then add the call record, identity on errors, protocol logging, per-tool metrics, cost counters, scrubbing, retention, and alerts, and prove them with a test call per tool and a forced failure. Report-only on request. Cost caps per client or tenant are proposed for the owner.
Run these first:
# 1. What is logged per call today
grep -rnE 'console\.(log|error|warn)|logger\.|logging\.|log\.' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | grep -v node_modules | wc -l
grep -rnE 'CallToolRequest|call_tool|@server\.call_tool|tools/call|setRequestHandler' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | head -5
# in the tool dispatch: is there one place that records tool name, client, session, start, duration, outcome, input and output sizes?
# 2. Error reporting identity
grep -rnE 'captureException|Sentry|bugsnag|rollbar|reportError' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | head -5
grep -rnE 'setTag|tags:|release:|serverInfo' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | grep -iE 'tool|client|version|transport' | head -5
# 3. Protocol logging, progress, metrics
grep -rnE 'sendLoggingMessage|notifications/message|logging/setLevel|progressToken|notifications/progress' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | wc -l
grep -rnE 'prom-client|prometheus|statsd|opentelemetry|metrics' --include='*.ts' --include='*.js' --include='*.py' src server package.json pyproject.toml 2>/dev/null | head -5
grep -rnoE 'histogram|counter|gauge' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | sort | uniq -c
# 4. Upstream and model cost attribution
grep -rnE 'fetch\(|axios|httpx|requests\.' --include='*.ts' --include='*.js' --include='*.py' src/tools 2>/dev/null | wc -l; grep -rnE 'anthropic|openai|messages\.create|chat\.completions|usage\.(input|output)_tokens' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | head -5
grep -rnE 'tenant|tenantId|clientId|accountId' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | grep -iE 'log|metric|usage|cost' | head -5
# 5. Privacy, retention, alerts
grep -rnE 'log.*\(.*(args|arguments|params|input|result|content)' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | grep -vE 'length|size|keys' | head -5
grep -rnE 'redact|scrub|mask' --include='*.ts' --include='*.js' --include='*.py' src server 2>/dev/null | wc -l
# log store: retention setting; alert rules on error rate, latency, upstream failures, and cost; a per-tenant query for what tools ran on their behalf
Methodology: Find the dispatch point for tool, resource, and prompt requests and read what is recorded per call. Read the error reporting for identity tags. Check for protocol logging and progress use. Inventory metrics and their labels, and the upstream and model calls each tool makes and whether they are counted per client and tenant. Read the log statements for payloads and the scrubbing. Check retention and alert rules in the log and metrics stores. Then call every tool once and force one failure, one timeout, and one upstream failure, and read what was recorded, reported, and graphed. Query the records for one tenant's activity. Rank by what the server cannot answer about a failure or a bill.
Call Records & Errors
- One record per tool, resource, and prompt invocation with tool name, client name and version, session, protocol version, start, duration, outcome, error class, and input and output sizes; every exception reported with server version, tool, client, and transport; connections, disconnects, and negotiated capabilities recorded
Protocol Logging & Metrics
- Protocol logging messages at appropriate levels and progress notifications for long operations so clients can show users what is happening; latency histograms, error rates, and volumes per tool, per client, and per tenant; upstream dependency latency and failure per tool; label values bounded
Cost Attribution
- Upstream API calls, model tokens, and compute counted per tool, client, and tenant with a cost estimate; caps or alerts per client and tenant; a per-tenant report of what tools did on their behalf
Privacy, Retention & Alerts
- Arguments, results, resource contents, and prompt text never logged whole; sizes, hashes, and schema-level summaries instead; scrubbing applied before the tracker; retention set per store with privacy obligations; alerts on error rate, latency, upstream failures, silent error results, and cost spikes reaching a person; observability asynchronous and bounded in volume
Evidence rules: Confirmed requires the record of the test call as stored, the tracker event's tags, the metric as graphed, the log line with the payload, the retention setting, or the tenant query's result. A gap judged from the code alone is Likely until the test call is read back. Tools and stores observed correctly are reported as such. Defer to the hosting platform's monitoring for process-level metrics, and to the owner for cost caps.
Output Format
Start with a 3–5 line executive summary: tools and transports audited, what a call record contains today, error identity state, cost attribution state, the worst privacy or silence finding, and the first fix.
Observability table:
| Tool | Call recorded (fields) | Errors reported with identity | Protocol logging and progress | Latency and error metrics | Upstream and model cost counted | Payload scrubbed | Status |
|---|
Findings: each with evidence, severity (Critical for calls unrecorded on production tools, payloads with personal data or secrets in logs, cost unattributed with no cap on a multi-tenant server; High for errors without identity, silent error results, no per-tool latency; Medium for protocol logging, retention, and tenant reports; Low for metric naming), and fix. Test calls and forced failures with what was recorded. Alerts added. Positive findings. Omit any section with nothing to report.
Want this applied to a live stack?
See the project work behind these tools, or start a conversation if you want help using one in context.