Guides

Observability

What you can see about your traffic in the dashboard, and how to follow one call from a gateway log row into your own tracing backend.

Every call that reaches your agent is recorded, and the dashboard turns those records into pages you can use to answer four questions: is my agent healthy, who is calling what, why did that call fail, and where did the time go. This page walks through each page, says what it needs from you, and ends with how to follow one call from a row in Logs into Datadog, New Relic, Grafana or any other tracing backend you already use.

Where to look

QuestionPageNeeds
Is my agent healthy right now? Memory, CPU, event loopDashboard (Process tiles, Per project table)Telemetry in your agent
How much traffic, how fast, how reliable? What stands out?Dashboard (Traffic & reliability)Nothing
What is each connected agent doing?AgentsNothing (telemetry adds process figures)
How many calls per day, per tool, per project, per client?UsageNothing
Did this call happen, who made it, did it fail and why?LogsNothing
Where did this call's time go?TracesNothing
What did someone do to my account (keys, sign-ins, settings)?ActivityNothing
What did my handler do inside, query by query?Your own backendOpenTelemetry in your agent. See OpenTelemetry

All times on these pages are UTC.

Dashboard

/dashboard is the first page after you sign in. It refreshes itself every few seconds. If you have more than one project, filter chips at the top narrow every number to one project.

Headline cards

CardShows
AgentsConnected agents, across your projects
ToolsTools exposed to clients
Peak concurrentThe most calls running at once in the latest report window (about 10 seconds), with a sparkline
CallsCalls reported by your agents' recent samples, shown in red if any failed

Process tiles

Heap used, RSS (resident memory), CPU (a share of one core) and Event loop (mean delay, with how busy the loop was). The event loop delay is the number that predicts tool latency: a handler can be fast while the process is saturated, and then every call queues.

These tiles and the heap, CPU and loop columns of the Per project table need telemetry in your agent (see Telemetry from your agent). Until an agent reports, the page says Nothing reporting yet.

Traffic flow

A live diagram of calls moving from clients, through your agents, to the tools, resources and prompts they run. It draws one movement per real call and nothing else moves.

You seeIt means
A card labelled Agent / Client on the leftWhere calls come from, with how many agents are connected
One card per project in the middle, with the number of agents, and heap and cpu when telemetry is onYour agents. Replicas are drawn as a stack. A dashed, dim card means no agent is connected
Tools, Resources and Prompts cards on the rightWhat your agents registered
A filled dot travelling left to rightA call started
A card staying litThe agent is working on a call. Even a call that finishes instantly lights its card for a moment
A hollow ring travelling backThe call finished
GreenA call that succeeded
RedA call that failed. A project card whose recent calls are failing also gets a red outline

The eye button hides the moving traffic, and your choice is remembered. On a narrow screen the diagram scrolls sideways inside its card.

The lock button next to it holds the diagram in place. Unlock it to drag the diagram around, scroll to zoom, and double-click (or press reset) to put it back. The lock is remembered; the position is not.

The diagram is a short-lived picture, not a record: it keeps about a minute of events and empties when the gateway restarts. Logs is the record.

Per project

One row per project: Status, Agents, Tools, Heap, CPU, Loop, Uptime. Status is one of:

StatusMeaning
HealthyAt least one agent is connected and no recent calls failed
ErrorsAn agent is connected and calls in roughly the last minute failed. It clears on its own as they age out
DisabledAgents are connected, but every one has been switched off on the Agents page, so clients get an error
OfflineNo agent is connected

Traffic & reliability

Switch between 24h (hourly buckets) and 7d (daily buckets). It shows four figures with the change against the previous period (Calls, Success rate, Median latency and the 95th percentile latency), a chart of calls with the failed share in red, the busiest tools, and What stands out, a short list of things worth acting on.

This is computed from your call log, so it works without telemetry, and it only reaches back as far as your plan keeps logs: on a plan with 3 days of history the week toggle reads 3d. The notes appear after about 20 calls:

NoteAppears when
A tool is failingA tool with at least 5 calls has an error rate of 5% or more (red at 20% or more)
A tool is slowA tool with at least 5 calls has a 95th percentile of at least 1 second and at least 3 times the overall median
Traffic is up or downCalls changed by 25% or more against the previous period
Busiest hour or dayOnce there are 20 calls
No calls in the last 3 hours or daysTraffic stopped after earlier activity
Nothing unusualNone of the warnings fired

Telemetry from your agent

Process health is optional. It comes from a separate package that you attach to the agent. Reports ride the connection the agent already has, over the same key, so there is nothing else to configure.

bash
npm install @spacefix/telemetry

Then attach it to the agent before it connects:

agent.ts
import { telemetry } from '@spacefix/telemetry';

agent.use(telemetry());   // reports every 10 seconds
void agent.connect();

Metrics appear within one interval. A failing report is swallowed, so a telemetry problem never takes a tool down.

Each sample covers one window and reports:

FieldMeaning
rss, heapUsed, heapTotalMemory, in bytes
cpuShare of one core since the last sample, 0 to 1
eventLoopDelayMean event loop delay in milliseconds
eventLoopUtilizationFraction of the window the loop was busy, 0 to 1
uptimeSeconds the process has been up
toolsTools the agent exposes
calls, errorsCalls handled in the window, and how many failed
inFlightCalls running at the instant of sampling, usually 0
peakInFlightMost simultaneous calls in the window. Read this one for concurrency
avgMsMean handler duration in milliseconds

A Go agent has no event loop, so it reports the closest equivalents: the mean time goroutines wait to be scheduled, and how busy the runtime was. They rise when the process is overloaded, like event loop delay does in Node.js.

The gateway keeps the most recent samples in memory only and drops them when a project's last agent disconnects, so the process tiles are a live view, not history. For history of every number, send it to your own backend with OpenTelemetry.

Agents

/agents lists the processes holding a connection to the gateway right now: a project with three replicas has three agents. Each row shows the project, how long it has been connected, how many tools, resources and prompts it registered, and its calls and errors since it connected. A green dot means connected and healthy, a red dot means at least 5% of its calls have failed, and an amber dot means it is Disabled.

Open one to see everything it registered, its process figures from telemetry, and its last 30 calls. A Disable button takes an agent out of rotation without disconnecting it: it keeps its connection but gets no new calls, and calls already running finish. Disabling lasts until the agent disconnects, so a restarted agent comes back enabled.

An agent's page is live, not history. Its id exists only while it is connected, and its counters start at zero each time it connects. For history use Usage, Logs and Traces.

Usage

/usage shows calls across all your projects (filter to one with the chips). It covers the last 30 days.

  • This month is your monthly allowance as a bar: calls used of the limit, resetting on the 1st (UTC). Playground runs are not counted. See Plans and limits.
  • Tiles: Calls, Errors, Success rate and Mean latency.
  • Calls per day for the last 14 days, with failed calls in red.
  • The table: one row per day, project and tool, with calls, errors, error rate and average time. Resource reads are listed under their uri and prompts under their name.
  • Busiest tools and, when you have more than one project, By project.
  • Where time goes, Why calls fail and Clients. These three come from the call log, so they cover your plan's log window rather than 30 days:

    • Where time goes splits the mean call time between your handler and everything else (the gateway and the network), for calls where your agent reported its handler time.
    • Why calls fail counts failures by type (see Logs). Each links to the Logs page filtered to that type.
    • Clients counts calls and errors by the MCP client's reported name (claude-code), or by the User-Agent of a caller that reported none.

Export CSV downloads the table with the columns day, project, tool, calls, errors, avg_ms. By default it covers the last 30 days. Cells that start with =, +, - or @ are prefixed with an apostrophe so a spreadsheet does not run them as formulas. You can run 6 exports a minute.

Logs

/logs lists every call, newest first, updating while you are on the first page. A call is a tool call, a resource read or a prompt that reached your agent, whether it succeeded, failed or timed out.

Columns and details

The table shows Time (UTC), Name (the tool name, or the resource uri or prompt name with a resource or prompt tag), Project, Status (ok or error), Duration, Size in to out, and Error. Click a row for details:

DetailWhat it is
Request idThe gateway's id for this call. It is also on your agent's OpenTelemetry span as spacefix.request_id
Trace id32 hex characters. It links to the call's waterfall
Handler timeTime inside your handler, as your agent measured it, with its share of the call
Gateway & networkEverything else in the call's duration
Gateway → agentHow long the call took to reach your agent, as the agent measured it
Trace started by"the MCP client" or "the gateway"
Agent span idYour agent's span id
CredentialThe label of the key used, revoked key if it no longer exists, or dashboard session for Playground runs. A dash for OAuth callers, which use no key
PlatformThe runtime your agent runs on, exactly as the SDK reported it when it connected: Node.js 22.14.0, Go 1.23.4
EnvironmentWhat the call was made from: the User-Agent the caller sent, such as node or Go-http-client/2.0
ClientThe MCP client that made the call, by the name and version it reported when it connected, for example claude-code 2.1.4, codex-mcp-client 0.98.0 or inspector-client 0.17.0. Shown when the client reported one; it is self-reported
Client capabilities, MCP protocolWhat the client said it supports (sampling, elicitation, roots...) and the MCP protocol revision it speaks
Arguments passedThe names of the arguments, never their values (first 20 names)
Size in → outBytes of the arguments and of the result
FailureThe failure type and message, for failed calls
AgentThe id of the agent that ran the call, as the Agents page shows it. An agent gets a new id each time it connects, and only connected agents are kept, so this id is for matching a row to an agent that is still connected
Agent SDKThe SDK your agent reported, such as spacefix-sdk-node/1.0.0. Blank if it did not report one
Agent User-AgentThe whole User-Agent your agent had when the call ran: the SDK, the runtime and, if you set appInfo (Node) or AppInfo (Go), your application's own name and version. It shows which build of your service answered

Filters

Project, Status (Any status, Succeeded, Failed), Type (Tools, Resources, Prompts), Source (Clients or Playground) and a tool name box. When you filter to failures, a failure type filter appears. Page sizes are 10, 20, 50 and 100. The tiles above the table follow the filters: calls, success rate, 50th and 95th percentile latency, and data moved.

Failure types

LabelMeaning
Timed outYour agent did not answer within the call timeout (Request for tool "<name>" timed out after <ms>ms.)
Agent errorYour handler threw or reported an error, or your agent disconnected mid-call. The message is yours
No agent connectedThe call got past the gateway's checks, but no connected agent served that tool, resource or prompt when it was sent (for example during a rolling deploy). It is logged but not counted against your allowance

A request refused before it reaches an agent is not logged and not counted: a bad key, a rate limit, a suspended project, an allowance already spent, arguments that fail the tool's schema, or no agent connected at all. It never ran your code, so look for it on the client side. See Troubleshooting and Errors.

Retention and export

Rows are kept for your plan's history: 3 days on Free. Longer plans keep more; see Plans and limits. A row's expiry is fixed when it is written, so moving to a bigger plan keeps new rows longer but does not extend old ones.

Export CSV writes time_utc, project, tool, kind, ok, ms, arg_bytes, result_bytes, error, request_id, trace_id, source, client, handler_ms, agent_inbound_ms, error_kind. It is limited to your retention and to 100,000 rows, and shares the 6-a-minute export limit.

Traces

A trace is the path of a call, or of several calls that share a trace id, between the MCP client, the gateway and your agent. /traces lists them, newest first: Started (UTC), Trace id, First call, Project, Calls, Status, Duration and Started by. Filters are Project, Status, Source and tool name.

Client traces and gateway traces. If the MCP client sent a traceparent header, the call joins the client's trace and is labelled a client trace. One client trace can hold many calls. If it sent none, the gateway starts a trace and the call is labelled a gateway trace. Either way every call that reaches an agent has a trace id. Playground runs get a trace of their own, so they appear here too.

Open a trace for the timeline. Select any row to expand it for where it ran, when it started, how long it took, its share of the trace, its span id and notes.

  • A marker for the client's own span, when there was one. The gateway cannot know how long the client's span ran. Only the client's tracing backend does.
  • A gateway bar for each call: the time the gateway spent on it end to end (red if it failed, with the reason beside the name). With several calls, each is numbered (#1, #2, ...) and parallel calls overlap.
  • Three legs inside it for your agent: gateway → agent (the call travelling to you), handler (your code, with the agent that ran it) and agent → gateway (the result coming back).
  • Each bar carries its duration, and the longest single step is tagged slowest.

Around the timeline the page adds:

  • What stands out: plain-language findings, such as why a call failed (timed out, agent error, or no agent connected), whether the time is mostly in your handler or outside it, and whether calls ran in parallel.
  • Where the time went: one bar splitting the total into your handlers, gateway and transit, time the agent gave no breakdown for, and calls that failed before an answer.
  • Trace details: trace id, start and finish, who started it, project, the agents that ran the calls and the SDK versions they reported, credential, client and the data moved.
  • A Spans table (where, start, duration, share, span id, notes) and the calls in the trace with size in and out, the agent, request id, credential, client and, for a failed call, the error.

Why some bars say "estimated". Two things are measured exactly: the gateway's time for the whole call, and how long your handler ran (measured by your agent on its own clock). Where the handler sits inside the call is inferred from the gateway-to-agent latency your agent observed, and that figure compares two different computers' clocks. So the legs on either side of the handler are drawn lighter and tagged estimated. If your agent did not report that latency, the transit time is split evenly between the two legs. If it reported no timing at all, you see only the gateway bar.

The queries and HTTP requests your handler makes are not on this page. They are spans in your backend, under the same trace id.

Activity

/activity is the audit trail of your account: sign-ins, key and project changes, tool setting changes, two-factor changes, webhooks and more. It is kept for at least 30 days. See Security.

Following a call into your own backend

The gateway exports no telemetry and never holds credentials for your backend. Instead your agent emits spans, metrics and logs through your own OpenTelemetry setup, and the gateway hands each call's trace context to the agent so the two line up. Setup is in OpenTelemetry. In short:

  • If your MCP client sends traceparent, your agent's span is a child of the client's span, in the same trace.
  • If it sends none, the gateway starts the trace and your agent's span carries that trace id.
  • Your handler runs inside that span, so queries and HTTP calls made by instrumented libraries nest under it.

To go from a gateway log row to a trace in Datadog, New Relic or similar:

  1. Open the call's row on Logs (or the trace under Traces) and copy the Trace id: 32 hexadecimal characters, for example 4bf92f3577b34da6a3ce929d0e0e4736. On a trace's page, the Copy trace id button does it.
  2. In your tracing backend, search for that trace id. The field name and query syntax depend on the vendor, so check its documentation for searching by OTLP trace id.
  3. You see the whole request: the client's span (if the client traces), your agent's tools/call <name> span, and everything your handler did.

In the other direction, a span's spacefix.request_id attribute is the Request id in the Logs row details, so from a slow span you can find the gateway's row.

Only calls that reach your agent produce a span. A call the gateway refuses, or one that times out before your agent answers, appears in Logs only. And when the client sent no traceparent, the span's parent is a span the gateway invented, which no backend has, so some backends mark your span as having a missing parent. Instrumenting the client removes that.

What is stored, and what is not

StoredNever stored
Time, project, tool, resource or prompt name, outcome, durationArgument values
Argument names (up to 20, each trimmed to 64 characters)Results
Size in bytes of the arguments and of the resultIP addresses of callers
The error message of a failed call (up to 300 characters)Key values
The label of the key used, the caller's User-Agent (160 characters), the MCP client's reported name, version and capabilities, and your agent's runtime
Request id, trace id, and the timings your agent reported

Error messages are stored, and they are whatever your handler threw, so do not put secrets or personal data in them. For the full picture see Security.

Things worth knowing

  • Writes are buffered for about two seconds. Calls are written in batches, so a call can take a moment to show up. The pages flush before they read, so your own just-made calls are there when you load a page.
  • Cache hits are invisible. If you set a cache time on a tool, a call answered from the cache never reaches your agent and is not logged, traced or counted.
  • Per-tool figures on an agent's page are per project. The call log does not record which replica ran a call, so with several replicas the per-tool numbers cover all of them.
  • The week toggle is bounded by your plan. The dashboard can only show what your log retention keeps.
  • Playground runs are logged (marked playground, credential dashboard session) but never counted toward your allowance, and have no trace.

Next steps