Instrument a Node/TypeScript MCP server with Amplitude's @amplitude/mcp-analytics SDK so tool calls, sessions, and rationale are tracked as Amplitude events. Use this skill whenever the user wants to add Amplitude analytics to their MCP server, mentions "MCP Analytics", "@amplitude/mcp-analytics", "instrument my MCP server", "track MCP tool calls", "add rationale to my MCP tools", or wants agent traffic (Claude, Cursor, ChatGPT) attributed back to Amplitude. Also use for adding UTM tagging to MCP-returned links, or for troubleshooting identity/user_id mismatches between MCP events and web/mobile Amplitude data.
72
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Instruments an MCP server so every tool call becomes an Amplitude event, joinable with the rest of the product's Amplitude data (retention, revenue, web/mobile usage).
The authoritative SDK reference is the package README:
https://github.com/amplitude/Amplitude-MCP-Analytics-Node (npm: @amplitude/mcp-analytics).
The SDK is in preview and evolves quickly — always fetch the latest README and follow it for
installation, API shapes, configuration, and default events. Do not rely on memorized snippets or
this skill's summaries for SDK API details; the README wins on any conflict.
There are four steps. Steps 1–2 are required and are documented in the README — this skill tells you which sections to follow and which invariants to verify. Steps 3–4 are strongly recommended and are documented in full here, because they require changes outside the SDK (the server's tool schemas and the product's web app) that the SDK README intentionally does not cover.
Do them in order: Step 1 (tool calls) → Step 2 (identity) → Step 3 (rationale) → Step 4 (UTM, only if the server returns links). Get identity right before calling anything "done" — everything downstream depends on it.
Confirm:
@modelcontextprotocol/sdk. This SDK doesn't support other languages/runtimes.Fetch the README and follow its Install and Quick start sections. Always install the latest
published version (e.g. pnpm add @amplitude/mcp-analytics@latest) — never pin a version from
memory, and don't reproduce install commands from this skill.
Invariants to verify once wired up (the README explains each):
analytics.instrumentServer(server, ...) runs before server.connect() — order matters.analytics.instrumentTool(...). Unwrapped tools aren't
tracked. The wrapper has the identical shape to the handler and is a no-op passthrough if the
server was never bound, so it's safe to wrap defensively.[MCP] prefix, so they never collide with the product's existing
Amplitude events. See the README's Default events table (and docs/events.md in the repo) for
the current event set and properties.Optional: attach stable custom dimensions (plan tier, team, feature flags) via extra on
instrumentTool/instrumentServer — see the README's Custom event properties section.
MCP events must carry the same user_id the product already sends to Amplitude from web/mobile.
Skip this and MCP usage shows up as a disconnected population that can't be joined to product data —
this defeats most of the point of the integration.
Follow the README's Identity section for the current API: it offers server-level binding,
per-request setIdentity() inside a handler, and an opt-in resolveIdentity mapping from the
request's authInfo claims. Pick whichever fits the server's auth model.
One behavior to surface to the user: fully anonymous, anchor-less events are dropped by default
(not counted as users) unless explicitly opted in via emitAnonymousEvent: true for aggregate-only
tracking — ask before turning this on, since it changes what gets counted.
Unlike a human clicking a button, an agent can tell you why it called a tool. Capturing this turns the data from "what happened" into "what the user was trying to do."
The SDK side is one call (analytics.setRationale(...) — see the README's Rationale section),
but the SDK never reads rationale out of tool inputs itself: how the rationale reaches the server
is a server-side convention this skill implements. The battle-tested pattern is schema injection —
add an optional rationale field to every tool's input schema. Because the parameter is described
in the schema agents already read, they fill it in unprompted, across all clients, with zero
client-side changes:
// Add to every tool's input schema (zod example):
rationale: z
.string()
.optional()
.describe(
'Brief explanation of why you are calling this tool and what ' +
'you expect to learn from the result.',
),Then read it inside the instrumented handler and hand it to the SDK:
analytics.instrumentTool(async (args, extra) => {
if (typeof args.rationale === 'string') {
analytics.setRationale(args.rationale);
}
return doWork(args);
}, { name: 'search' });Making the field optional means nothing breaks when an agent omits it. It is emitted as the reserved
[MCP] Rationale property (truncated to 1,000 chars; last write wins). Worth doing on every tool,
not just a sample.
This step is entirely outside the SDK — it changes how the server builds URLs and depends on the product's web-side analytics. It is not covered in the SDK README.
If any tool response includes a link (dashboard, doc, product page), tag it before it leaves the server so click-throughs are attributable to MCP/agent traffic instead of showing up as direct:
function addUtmParams(url: string, clientName?: string): string {
const u = new URL(url);
u.searchParams.append('utm_source', 'mcp');
u.searchParams.append('utm_medium', 'referral');
// The connected client (e.g. "Claude", "Cursor"), if you know it:
u.searchParams.append('utm_content', clientName ?? 'unknown');
return u.toString();
}Route every URL-building path in tool responses through one central function like this — a single untagged link breaks the attribution story for that flow.
Prerequisite (tell the user this explicitly): this only works if their web analytics captures UTM params on page-view events (or whatever event their site fires on landing). Amplitude's Browser SDK 2 does this by default — see Track marketing attribution (UTM, referrer, and click ID parameters are captured out of the box). If they use a custom page-view tracker, they need to confirm UTM values land on those events too, or there's nothing to join the MCP-tagged clicks against.
Relevant Amplitude documentation:
Once events are flowing, point a coding agent at Amplitude's published analyze-mcp-server skill to run
intent clustering and surface tool-call error patterns by intent. (If this project has the
mcp-intent-error-analysis skill installed, that's the one — use it once the user has data flowing and
wants to analyze it, rather than duplicating that analysis here.)
instrumentServer() after server.connect() — must be before.instrumentTool.user_id that doesn't match the one used on web/mobile — breaks joinability, the whole point of the integration.emitAnonymousEvent: true without the user understanding it inflates aggregate counts with anchor-less traffic.amplitude/builder-skills
51838c2
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.