Sobald er eingerichtet ist, kannst du Fragen stellen wie „Welche Kanäle hatten letzten Monat den besten ROAS unter Data-Driven-Attribution?" — und Claude fragt deine Klar-Daten ab und antwortet direkt, ohne Dashboards, Exporte oder Copy-Paste.
Du musst den Server nicht von Hand schreiben. Wir stellen unten eine fertige CLAUDE.md-Spezifikation bereit: Leg sie in einen leeren Projektordner, richte Claude Code (oder einen beliebigen Coding-Agenten) darauf aus und bitte ihn, den Server zu bauen. Die Datei enthält alles, was der Agent braucht — die API-Referenz, die Constraints und die bereitzustellenden Tools.
Was ist MCP?
MCP ist ein offener Standard, der es KI-Assistenten ermöglicht, externe Tools und Datenquellen über eine einzige, konsistente Schnittstelle aufzurufen. Ein MCP-Server ist ein kleines Programm, das „Tools" bereitstellt, die der Assistent nutzen kann. Baue einen, der die Klar-Attribution-API umschließt, und jeder MCP-fähige Client — Claude Desktop, Claude Code und andere — kann deine Attributionsdaten auf Abruf ziehen.
Bevor du beginnst
Du brauchst:
Deinen Klar-Refresh-Token. Gehe in Klar zu Store-Konfigurator → Store Settings und kopiere den Refresh Token. Ein Refresh Token ist an einen Store und einen User gebunden — behandle ihn also wie ein Passwort.
Node.js 20 oder neuer installiert.
Claude Code (
npm install -g @anthropic-ai/claude-code) oder einen anderen Coding-Agenten, um den Server zu bauen, plus Claude Desktop, falls du den fertigen Server dort nutzen möchtest.
Schritt 1 — Projektordner erstellen und CLAUDE.md hinzufügen
Erstelle einen leeren Ordner für das Projekt und speichere die untenstehende Datei darin als CLAUDE.md. Das ist die Build-Spezifikation — sie sagt dem Coding-Agenten genau, was zu bauen ist und wie sich die Klar-API verhält.
Claude.md:
# CLAUDE.md — Klar Attribution API MCP Server
## Project goal
Build a Model Context Protocol (MCP) server that wraps the Klar Attribution API
so that any MCP-capable client (Claude Desktop, Claude Code, etc.) can query a
Klar store's attribution data in natural language. The server exposes the
attribution report as typed tools, handles authentication, and absorbs Klar's
API constraints (short-lived tokens, the 31-day window limit, and the rate
limit) so the user never has to think about them.
## Tech stack
- TypeScript + Node.js (Node 20+).
- @modelcontextprotocol/sdk (latest) — use McpServer and StdioServerTransport.
- zod for input validation.
- stdio transport (local), so the server plugs straight into Claude Desktop and
Claude Code.
- Native fetch (built into Node 20+) — no extra HTTP client needed.
Python is a fine alternative (official mcp / FastMCP SDK). If you go that route,
keep the same tool surface and the same constraint handling.
## Build steps
1. Scaffold the project: "type": "module" in package.json, a tsconfig.json
targeting NodeNext, output to ./build, and a build script (tsc).
2. Implement a Klar API client module (auth + report) honouring the constraints
in the API reference below.
3. Implement the MCP server with the tools described under "Tool surface".
4. Compile (npm run build) and confirm it builds cleanly.
5. Write a README that includes the exact claude_desktop_config.json entry.
Do not call the live API during the build. The user supplies a real refresh
token at runtime via an environment variable.
## Klar Attribution API reference
Base URL: https://api.getklar.com
### Authentication — exchange the refresh token for an access token
- Endpoint: POST /public/auth/token
- Request header: token: <KLAR_REFRESH_TOKEN> (the store's static refresh token)
- Success: 201 Created
- Response body: { "accessToken": "eyJ...", "expiresIn": 300000 }
The accessToken is a JWT valid for 5 minutes (300,000 ms). Cache it and reuse it
across calls; only request a new one when the current token is within ~30
seconds of expiry.
The refresh token is one per store/user and is a secret. Read it from the
KLAR_REFRESH_TOKEN environment variable. Never hardcode it and never write it to
logs.
### Report — fetch attribution data
- Endpoint: GET /public/attribution
- Header: Authorization: Bearer <accessToken>
Query parameters:
- startDate (string, required): format yyyy-mm-dd.
- endDate (string, required): format yyyy-mm-dd. EXCLUSIVE — results cover
[startDate, endDate). Must be within 31 days of startDate.
- metric (string, optional): one of first_touch, last_touch, data_driven,
linear, any_click, any_click_unique, u_shape, time_decay, marketing_mix.
- window (string, optional): one of unlimited, 1_day, 7_day, 28_day.
- date_breakdown (string, optional): one of order, touch.
A 200 OK returns a JSON array of row objects (schema below).
### Constraints the server MUST enforce
1. Rate limit: 2 requests per 30 seconds. This applies to the API as a whole, so
budget the auth call into it too. Implement a small token-bucket or queue so
chunked or back-to-back calls never exceed the limit.
2. 31-day window maximum. For longer ranges, split into consecutive windows of
<= 31 days (use 30 to leave a safety margin), call each window, and
concatenate the rows. Because endDate is exclusive, chunk as [d0, d0+30),
[d0+30, d0+60), ... with no overlap and no gap. Warn the user in the tool
description that wide ranges take longer because of the rate limit.
3. Token caching as described under Authentication.
4. Logging: on stdio transport, never write to stdout — it corrupts the JSON-RPC
stream. Use console.error (stderr) only.
5. Errors: catch failures and return
{ isError: true, content: [{ type: "text", text: "..." }] } instead of
throwing, so a single bad call doesn't kill the client session.
### Response row schema
Dimensions: channelName, date, campaignName, campaignId, adGroupName,
adGroupId, adName, adId.
Metrics: orders, nc, rc, netRevenue, grossRevenue, cost, clicks, impressions,
cm1, cm2, clv_30, clv_60, clv_90, acm2, ncGrossRevenue, rcGrossRevenue,
ncNetRevenue, rcNetRevenue.
## Metric glossary
These are working definitions for the tool descriptions. For authoritative
formulas, see Klar's margin-metrics documentation in the help center.
- orders — attributed orders. Fractional values are expected: attribution
models distribute partial credit for an order across the touchpoints that led
to it.
- nc / rc — attributed New-Customer and Returning-Customer orders (also
fractional).
- grossRevenue / netRevenue — attributed gross and net revenue.
- cost — ad spend for the row. ROAS is netRevenue / cost.
- clicks / impressions — ad engagement.
- cm1 / cm2 — contribution-margin tiers (CM1 after product/variable costs, CM2
after marketing cost).
- clv_30 / clv_60 / clv_90 — projected customer lifetime value at 30 / 60 / 90
days.
- acm2 — adjusted CM2.
- ncGrossRevenue / rcGrossRevenue / ncNetRevenue / rcNetRevenue — gross and net
revenue split by new vs. returning customers.
## Tool surface
Core — build this first:
- get_attribution_report
- Params: startDate (required, yyyy-mm-dd), endDate (required, yyyy-mm-dd),
metric (optional enum), window (optional enum), date_breakdown (optional
enum). Validate with zod and surface the exact accepted values in the schema.
- Behaviour: auto-chunks any range longer than 31 days, respects the rate
limit, returns the combined rows.
Optional extensions (add if useful to the user):
- summarize_by_channel — same params; aggregates rows by channelName (sum
orders, cost, netRevenue, grossRevenue; derive ROAS = netRevenue / cost).
- compare_periods — two date ranges; returns per-channel deltas.
Bake the key interpretation rules — fractional orders, exclusive endDate, ROAS =
netRevenue / cost — into the tool descriptions so the model reads the results
correctly.
## Run & test
- npm run build
- npx @modelcontextprotocol/inspector node ./build/index.js
## README must include
A one-line description; the exact claude_desktop_config.json snippet; the tool
list with one-line descriptions; the required env var (KLAR_REFRESH_TOKEN); and
a short troubleshooting section covering token expiry, rate-limit pauses on wide
date ranges, and the no-stdout-logging rule.
Schritt 2 — Den Agenten bauen lassen
Öffne den Ordner in Claude Code (oder deinem bevorzugten Agenten) und gib ihm einen kurzen Prompt:
Read CLAUDE.md and build the MCP server it describes. Use TypeScript with
the official MCP SDK and stdio transport. When you're done, run the build
and show me the claude_desktop_config.json entry I need.
Der Agent scaffoldet das Projekt, implementiert den Klar-API-Client (mit Token-Caching, Rate-Limiting und Datumsbereichs-Chunking), definiert die Tools und kompiliert den Server. Prüfe den generierten Code und baue ihn dann.
Schritt 3 — Mit Claude Desktop verbinden
Öffne deine Claude-Desktop-Config-Datei und füge den Server unter mcpServers hinzu. Auf macOS liegt sie unter ~/Library/Application Support/Claude/claude_desktop_config.json; auf Windows unter %APPDATA%\Claude\claude_desktop_config.json.
{
"mcpServers": {
"klar-attribution": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/build/index.js"],
"env": {
"KLAR_REFRESH_TOKEN": "your-store-refresh-token"
}
}
}
}
Verwende den absoluten Pfad zur kompilierten build/index.js, füge den Refresh Token deines Stores ein, speichere die Datei und starte Claude Desktop neu. Die Klar-Tools erscheinen, sobald der Server sauber startet.
Wenn du stattdessen Claude Code nutzt, kannst du denselben Server über die Kommandozeile mit claude mcp add registrieren.
Schritt 4 — Losfragen
Sobald verbunden, probiere Prompts wie:
„Zeig mir die Attribution der letzten Woche nach Kanal unter Last-Touch."
„Vergleiche den Neukunden-Nettoumsatz im März vs. Februar."
„Welche Kampagnen hatten im Q1 mit Data-Driven-Attribution einen ROAS über 3?"
Claude ruft deinen Server auf, holt die Daten aus Klar und antwortet.
Gut zu wissen
Access Tokens laufen nach 5 Minuten ab. Der Server erneuert sie automatisch — du stellst immer nur den langlebigen Refresh Token bereit.
Weite Datumsbereiche dauern etwas länger. Klar begrenzt Anfragen auf 2 alle 30 Sekunden und 31 Tage pro Anfrage, sodass ein ganzes Jahr in gedrosselten Monats-Chunks geholt wird. Das ist so vorgesehen.
Attribuierte Bestellungen sind oft Bruchzahlen. Attributionsmodelle verteilen den Erfolg einer Bestellung über die Touchpoints, die zu ihr geführt haben — ein Kanal kann daher z.B. 2,13 Bestellungen zeigen.
Halte deinen Refresh Token privat. Er ist an deinen Store gebunden — committe ihn niemals in ein Repository und teile ihn nicht.
