MCP server
Native Model Context Protocol server at
https://mcp.turtleqr.com/mcp.
12 tools. JSON-RPC 2.0 over HTTP POST. Bearer token authentication.
Back to Docs hub or jump to REST API reference.
What it does
The MCP server lets AI agents operate TurtleQR as a native capability. Your agent can create codes, read scan counts, change destinations, and export analytics without leaving the conversation. The tools proxy directly to the REST API: anything you can do in the dashboard you can do from a chat.
Supported clients: Claude Desktop, Claude.ai (via extension), Cursor, ChatGPT (via custom GPT), and any MCP-compatible client that can make HTTP POST requests.
Get an API key
The MCP server authenticates with a TurtleQR API key. Generate one in the dashboard:
- Sign in at app.turtleqr.com.
- Go to API keys.
- Click Create API key. Give it a label (e.g., "Claude desktop"). Copy the token when it appears; it is shown once.
The token starts with qr_live_ (production) or qr_test_
(test workspaces).
Connect Claude Desktop
Add this block to
~/Library/Application Support/Claude/claude_desktop_config.json
on macOS, or
%APPDATA%Claudeclaude_desktop_config.json on Windows:
{
"mcpServers": {
"turtleqr": {
"command": "npx",
"args": [
"mcp-remote",
"https://mcp.turtleqr.com/mcp",
"--header",
"Authorization:Bearer qr_live_YOUR_KEY_HERE"
]
}
}
}
Restart Claude Desktop. Try: "Create a TurtleQR code pointing to https://example.com."
The mcp-remote package bridges Claude's local stdio transport to the
remote HTTP endpoint. It does not require installation; npx fetches and
caches it on first run.
Connect Cursor
Add to your Cursor MCP config at ~/.cursor/mcp.json (create the file
if it does not exist):
{
"mcpServers": {
"turtleqr": {
"url": "https://mcp.turtleqr.com/mcp",
"headers": {
"Authorization": "Bearer qr_live_YOUR_KEY_HERE"
}
}
}
}
Cursor supports direct HTTP transports without mcp-remote. Reload
the Cursor window after saving. You should see TurtleQR listed under
Settings > MCP.
Connect ChatGPT (custom GPT)
ChatGPT does not yet support the MCP transport natively, but you can expose the same tools via a custom GPT action that calls the MCP endpoint directly.
- In ChatGPT, open Explore GPTs > Create.
- Go to Configure > Actions > Add action.
- Set the server URL to
https://mcp.turtleqr.com/mcp. - Set the authentication type to API Key, key in header, header
name
Authorization, valueBearer qr_live_YOUR_KEY_HERE. - Import the OpenAPI schema from mcp.turtleqr.com/openapi.json.
The custom GPT can then call any of the 12 tools directly from the chat.
Generic MCP client (JSON-RPC curl)
The protocol is JSON-RPC 2.0 over HTTP POST to
https://mcp.turtleqr.com/mcp. No special client is required for testing.
# List available tools (no auth required for tools/list)
curl -s -X POST https://mcp.turtleqr.com/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq
# Confirm authentication and workspace scope
curl -s -X POST https://mcp.turtleqr.com/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer qr_live_YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": { "name": "whoami", "arguments": {} }
}' | jq
# Create a QR code
curl -s -X POST https://mcp.turtleqr.com/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer qr_live_YOUR_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "create_qr",
"arguments": {
"targetUrl": "https://example.com/autumn-menu",
"slug": "autumn-menu"
}
}
}' | jq
Tool results are returned in the standard MCP content envelope:
{"content":[{"type":"text","text":"..."}]}. Error results
also include "isError": true.
Tool reference
12 tools are available. All tool calls require a valid Bearer token in the
Authorization header except as noted.
create_qr
Create a new dynamic QR code. Returns the slug, short URL, and code id.
The short URL resolves immediately at qr.turtleqr.com/{slug}.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
targetUrl | string (URI) | Yes | The URL the QR redirects to. Must be http(s). |
slug | string | No | Custom slug ([a-zA-Z0-9_-], max 100). Auto-generated if omitted. |
fallbackUrl | string (URI) | No | Where scanners go after expiry or scan cap. |
expiresAt | ISO 8601 datetime | No | Expiration timestamp. Pro+ only. |
scanCap | integer | No | Maximum scan count. Pro+ only. |
type | enum | No (default: url) | url | menu | event | coupon | social | business-page |
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_qr",
"arguments": {
"targetUrl": "https://myshop.com/summer-sale",
"slug": "summer-sale",
"fallbackUrl": "https://myshop.com/"
}
}
}
list_qr_codes
List QR codes in the active workspace. Returns up to 100 codes, newest first. Each item includes slug, target URL, status, and timestamps.
Input schema
No input fields required.
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "list_qr_codes", "arguments": {} }
}
get_qr_code
Read a single code by id. Returns full details including expiration and scan cap.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The code id, e.g. code_abc123. |
update_qr_target
Change a code's destination without reprinting. The KV redirect cache is invalidated; new scans see the new value within 60 seconds globally.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Code id. |
targetUrl | string (URI) | No | New destination URL. |
fallbackUrl | string or null | No | New fallback URL. Pass null to clear. |
expiresAt | datetime or null | No | New expiration. Pass null to clear. Pro+ only. |
scanCap | integer or null | No | New scan cap. Pass null to clear. Pro+ only. |
status | string enum | No | active | expired | suspended |
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "update_qr_target",
"arguments": {
"id": "code_abc123",
"targetUrl": "https://myshop.com/new-page"
}
}
}
delete_qr_code
Soft-delete a code. Status is set to deleted; scanners hit the
workspace fallback. Recoverable by an admin.
Input schema
| Field | Type | Required |
|---|---|---|
id | string | Yes |
get_qr_image
Render a QR code as an image. Returns base64-encoded PNG or SVG text. Useful for the agent to display, attach, or save the QR image without requiring a separate download step. The QR encodes the short URL so the underlying target can change without reprinting.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Code id, e.g. code_abc123. |
format | string enum | No (default: png) | png | svg |
size | integer | No (default: 1024) | Pixel size. Range: 128 to 2048. |
get_qr_scans
List recent scans for a code. Returns up to limit scans, newest first.
Each scan includes country, region, city, device, OS, and browser.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Code id. |
limit | integer | No (default: 50) | Min 1, max 500. |
get_qr_analytics
Aggregated scan analytics: totals, time series, breakdowns by country, device, OS, browser, hour-of-day, and day-of-week. Use this for dashboard views or to answer questions like "how is my conference QR performing?"
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
codeId | string | Yes | Code id. |
range | string enum | No (default: 30d) | 7d | 30d | 90d | all |
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_qr_analytics",
"arguments": { "codeId": "code_abc123", "range": "7d" }
}
}
list_recent_scans
Paginated individual scan events, newest first. Use for activity feeds or
browsing scan history. Each scan includes: scannedAt, country, region, city,
device, os, browser, referer. Pass cursor (the previous response's
nextCursor) to fetch the next page.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
codeId | string | Yes | Code id. |
limit | integer | No (default: 50) | Min 1, max 200. |
cursor | string | No | Opaque cursor from a previous response's nextCursor. Omit for the first page. |
bulk_create_qr_codes
Create up to 50 QR codes in one call. Returns both successfully-created codes
and individual failures, so the agent can report partial success. For a single code,
prefer create_qr.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
codes | array | Yes | 1 to 50 items. Each item: {targetUrl, slug?, label?}. |
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "bulk_create_qr_codes",
"arguments": {
"codes": [
{ "targetUrl": "https://example.com/page-1", "label": "Page 1" },
{ "targetUrl": "https://example.com/page-2", "label": "Page 2" }
]
}
}
}
export_qr_scans_csv
Export scan history as CSV for one QR code. Returns the CSV text inline in the
csv field, plus a suggested filename. The agent should
write the csv field to a .csv file. Capped at 100,000 rows.
Pro+ only.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
codeId | string | Yes | Code id. |
range | string enum | No (default: 30d) | 7d | 30d | 90d | all |
whoami
Returns { workspaceId, authenticated, codeCount, server } for the authenticated API key.
The server sub-object includes { name, version }.
Useful as a connectivity probe and for confirming the active workspace.
Input schema
No input fields required.
Example invocation
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "whoami", "arguments": {} }
}
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
Error 401 |
Missing or invalid Bearer token. | Check that your API key starts with qr_live_ or qr_test_ and is included as Authorization: Bearer .... |
Error 403 |
Key does not have access to the requested resource. | The code or workspace may belong to a different key. Call whoami to confirm the scoped workspace id. |
Error 402 plan_limit_exceeded |
Requested action requires Pro+. | Features like expiration dates, scan caps, password gates, and CSV export require a Pro plan. See pricing. |
Error 409 slug_taken |
Custom slug is already in use. | Omit the slug field to auto-generate one, or choose a different value. |
| Tool not listed in Claude | Config file not saved or Claude not restarted. | Verify the config path, confirm the JSON is valid, and restart Claude Desktop fully. |
npx mcp-remote hangs |
Outbound HTTPS blocked by a firewall or proxy. | Confirm that mcp.turtleqr.com is reachable on port 443 from the machine running Claude Desktop. |
What is next for MCP
OAuth 2.1 (PKCE) is live for Claude.ai web. Use the /oauth/authorize
flow at auth.turtleqr.com to grant access without sharing an API key.
Self-hosted MCP clients (e.g. Cursor) can use a workspace API key via the
Authorization: Bearer qr_live_* header.
Additional planned tools: visual customization (logo, color, frame), folder management, routing rule creation, and webhook management.