trackmcp
SDKs

TypeScript SDK

@trackmcp/sdk wraps the official MCP server so every call, result, and client is captured automatically. Works with Node 18+ and any transport.

Install

npm i @trackmcp/sdk
# Create a key at https://app.trackmcp.com/dashboard
# or: pnpm add @trackmcp/sdk / yarn add @trackmcp/sdk

Optional Node MCP client adapter

The separate @trackmcp/sdk/client-adapter entry point is Node.js-only and requires @modelcontextprotocol/sdk exactly1.30.0. It rejects browser and Edge runtimes and must not be imported by frontend bundles. The caller is responsible for protecting the API key. It supports only StdioClientTransport andStreamableHTTPClientTransport.

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { TrackMCPClientAdapter } from "@trackmcp/sdk/client-adapter";

const adapter = new TrackMCPClientAdapter({
  apiKey: process.env.TRACKMCP_KEY!,
  service: "my-mcp-client",
  transport: "stdio", // or "streamable_http"
});
const transport = new StdioClientTransport({ command: "my-mcp-server" });
const client = new Client({ name: "my-host", version: "1.0.0" });
await client.connect(adapter.wrapTransport(transport));

Capture is metadata-only. It records client-observed issued calls, matched transport responses, observable next calls, repeats, and lifecycle boundaries; it does not record tool arguments/results, prompts, completions, private reasoning, token costs, promise outcomes, timeouts, aborts, or hidden HTTP reconnect/authentication behavior. Client events are labeled withobservation_source: "client" and do not inflate the server-only aggregate or Tool Quality metrics. Malformed, notification, unmatched, and duplicate messages produce diagnostics only, and capture stays fail-open.

Wrap your server

Pass your existing server into withTrackMCP with your API key. Nothing else in your code changes.

import { withTrackMCP } from "@trackmcp/sdk";
import { server } from "./mcp";

export default withTrackMCP(server, {
  apiKey: process.env.TRACKMCP_KEY!,
  service: "acme-mcp-server",
  environment: process.env.NODE_ENV,
});

Options

Every option except apiKey is optional. See the full configuration reference for defaults.

withTrackMCP(server, {
  apiKey: process.env.TRACKMCP_KEY!,
  service: "acme-mcp-server",   // shows up as the server name
  environment: "production",     // production | staging | ...
  sampleRate: 1.0,               // 0-1, fraction of calls captured
  payloadMode: "redacted",      // metadata | redacted | full (all are bounded)
  redact: ["args.password", "args.token"], // never leaves your process
  redactKeys: ["customer_id"],  // optional additional case-insensitive keys
  maxPayloadBytes: 32768,        // final serialized payload budget
  endpoint: "https://trackmcp.com/api/v1/ingest", // compatible ingest endpoint override
  intentFallback: ({ toolName }) => toolName ? "Complete the " + toolName + " operation" : undefined,
});

Redacting sensitive fields

Redaction runs in your process before anything is sent. The default redacted mode recursively removes common sensitive keys, scrubs binary/base64 resources, and bounds depth, breadth, strings, and bytes. Use metadata when arguments and results must not be captured;full is opt-in but remains bounded.

redact: ["args.email", "args.apiKey", "result.rawResponse"]
redactKeys: ["customer_id"]
redactEvent: (event) => event // return null to drop this event

// Truncations use a marker such as:
// { __trackmcp_truncated: true, reason: "max_payload_bytes", original_type: "object" }

Failure and queue behavior

A hook exception drops only that event. Delivery failures are retried from a bounded queue of 500 events or 2 MiB; oldest queued events are dropped when those limits are reached. Telemetry is fail-open and never blocks tool execution.

Optional correlation

Correlation is off by default and does not mutate MCP schemas. External mode accepts a synchronous resolver for bounded request metadata and stores only a validated anonymized opaque handle. Issued mode is opt-in and works only at the TypeScript transport boundary for compatible object-shaped tool schemas; clients may ignore the field, in which case provenance remains missing.

correlation: {
  mode: "external",
  resolve: ({ toolName, sessionId }) => toolName ? anonymizedJobHandle(toolName, sessionId) : undefined,
}

// Never return emails, tokens, URLs, raw user IDs, prompts,
// completions, or private reasoning.

Explicit workflow outcomes

A workflow event is an application-emitted signal, not an inference about whether an answer was correct. Emit it only where your application knows the user task started, completed, or failed.

server.trackmcp.workflow("issue_resolution", "completed", {
  issue_type: "bug",
});

Open the authenticated dashboard trace explorer to inspect ordered server-boundary events. See the API reference for the bounded trace response.

Intent and missing capabilities

Intent is opt-in context, not an inference. Compatible object-shapedtools/list schemas receive an optional contextfield with a one-sentence description. TrackMCP strips that known field before the customer handler and labels it context_parameter. Clients that omit or ignore it can use intentFallback, whose value is labeled fallback. Values supplied by an external application can be submitted with intent_source set toexternal_callback. Unsafe or absent values aremissing; no private reasoning is inspected.

withTrackMCP(server, {
  apiKey: process.env.TRACKMCP_KEY!,
  intentFallback: ({ toolName }) => toolName ? "Find the requested record" : undefined,
});

server.trackmcp.reportMissing("bulk_export", "Export all matching records");

Custom events

Want to track something beyond tool calls? Emit a named event from anywhere.

import { track } from "@trackmcp/sdk";

track("checkout_completed", { amount: 4900, plan: "pro" });