ProductMapper
MCP SERVER GET / POST /api/mcp

MCP (AI Agent Access)

A hand-rolled Model Context Protocol server exposing this app's mapping API as tools an AI coding agent can call directly - the same lookup, batch, and history endpoints documented elsewhere, wrapped for tool-calling instead of plain REST.

Same auth, credits, and rate limits as the REST API
Every tool call is authorized and billed identically to calling /api/map directly. There is no separate MCP-specific quota. A personal API key (generate one at /dashboard/api-keys) is required - browser sessions are not accepted here.

Transport: SSE + JSON-RPC 2.0

Two channels, per the classic MCP SSE transport spec: a long-lived GET connection that streams every response, and a POST per request that only acknowledges receipt. Most MCP client libraries (Claude Desktop, Cursor, etc.) handle this transport automatically - point them at the URL below and they manage both channels for you.

1. OPEN THE STREAM
GET /api/mcp?key=pm_live_xxxxxxxxxxxxxxxxxxxxxxxx
Accept: text/event-stream

# Opens an SSE stream and registers a session. The very first event tells
# you where to POST JSON-RPC requests for this session:

event: endpoint
data: /api/mcp?client_id=3f9e2b40-1c2a-4a3e-9c5e-7b8f2a1d9e33&key=pm_live_xxxxxxxxxxxxxxxxxxxxxxxx

# The API key can also go on x-api-key or Authorization: Bearer instead of ?key=.
# A ":\n\n" comment ping is sent every 15s to keep the connection alive.
2. INITIALIZE
POST /api/mcp?client_id=3f9e2b40-1c2a-4a3e-9c5e-7b8f2a1d9e33
Content-Type: application/json

{ "jsonrpc": "2.0", "method": "initialize", "id": 1 }

# The POST itself just acks receipt (HTTP 200, {"status":"accepted"}) - the
# actual JSON-RPC response streams back over the still-open GET connection
# as an "event: message" event:

event: message
data: {"jsonrpc":"2.0","result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"product-mapper-mcp","version":"1.0.0"}},"id":1}

List Available Tools

tools/list
{ "jsonrpc": "2.0", "method": "tools/list", "id": 2 }

# Streamed result: { "tools": [ ...four tool definitions, see below ] }

Call a Tool

tools/call
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "lookup",
    "arguments": { "value": "079361039905", "type": "auto" }
  },
  "id": 3
}

# Streamed result:
event: message
data: {"jsonrpc":"2.0","result":{"content":[{"type":"text","text":"{ ...full /api/map response, JSON-stringified... }"}]},"id":3}

A tool's result text is the JSON-stringified body of the underlying REST response - the exact same shape documented on that endpoint's own page. A 404/error from the underlying call is surfaced as a JSON-RPC error object, not a thrown exception.

Tool Reference

TOOLS
lookup
  value*: string        - identifier or title to resolve
  type: string           - "auto" (default) | UPC | EAN | GTIN | ASIN | Title
  marketplace: string    - default "amazon"
  region: string         - optional marketplace country filter, e.g. "CA"
  → calls POST /api/map with your API key; same credits/rate-limit/auth as a direct REST call.

batch_lookup
  items*: string[]       - up to 500 identifiers or titles
  marketplace: string    - default "amazon"
  → calls POST /api/map/batch; returns the batch job id immediately, still processing in the background.

batch_lookup_status
  jobId*: string         - the id returned by batch_lookup
  → calls GET /api/jobs/batch/{jobId}.

history_search
  search: string         - optional search term; omit to list everything
  page: integer          - default 1
  → calls GET /api/history.

* required
Sessions are in-memory and idle-limited
A session is tied to one running server process - it does not survive a deploy or restart, and disconnects after 90 seconds of inactivity (6× the 15s keep-alive ping interval). Reconnect via GET /api/mcp to get a fresh client_id if your client reports the session as expired.