Koskamo

qart.uk MCP

An MCP server for qart.uk that allows agents to resolve scanned QR codes, browse the free pool of pre-generated codes, and access the paid Studio for generating custom QR artwork. It supports anonymous resolution and browsing, while authenticated users can claim, shuffle, retarget codes, and run Studio generation tasks using OAuth scopes.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

qart.uk MCP logo, by qart.ukVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-07Operated by qart.uk
MCP endpoint (Streamable HTTP)
https://qart.uk/api/mcp
Vendor documentation

What its tools do

8 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

8 of 8 have a description · 0 of 8 declare behavior hints · 5 of 5 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Passed Official MCP Registry namespace is tied to qart.uk ·
  • Passed Endpoint is on the registry namespace domain ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Resolve scanned QR codes to their destinations
  • Browse the free pool of pre-generated QR codes
  • Generate custom QR artwork via the Studio
  • Retarget existing QR codes to new destinations

Source and maintenance

Vendor evidenceRegistry 1.0.0

Protocol and capabilities

Server
qart-uk 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
8 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {}
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

qart.uk makes QR codes where the artwork IS the code — every image is decoded by a real QR detector before it is offered, so what you get is artwork that already scanned. Three ways to get one: a free pool of finished codes anyone with an account can claim and point at their URL, a paid Studio that generates custom ones from prepaid credits, and a single finished QR bought outright over x402 with no account at all (buy_qr_outright). THE ONE THING TO GET RIGHT WHEN CHOOSING A RAIL: whether the finished code can be RE-POINTED after it is printed. That is a property of the payload, not of the product, and only two paths give it to you. A claimed pool code (claim_pool_code) and a Studio run started with payloadKind 'qart_code' both encode a short qart.uk/_ link, so the owner retargets it for free and every copy already printed follows. EVERYTHING ELSE encodes the payload verbatim into the pixels and can never be re-pointed: a Studio run on any other payloadKind — including the default 'url' — and buy_qr_outright. Verbatim is not a defect (such a code keeps working with no dependency on us staying up) but it is permanent, so say which kind you are making before anything goes to print. Without credentials you can resolve a scanned code, browse the free pool, work out how a payload will encode, get the raw QR module matrix, read the credit price list, and buy a single finished QR outright. Signed in through OAuth you additionally get the tools your granted scopes allow — call tools/list to see what you actually have, and whoami if you are unsure who you are acting for. Claiming pool codes, shuffling the storefront, and running the Studio are all on this server, gated by scope. A Studio run is a long job: starting one reserves credits, images stream in one at a time, and the poll that imports them is also the GPU heartbeat — keep calling poll_studio_run until the run is terminal or it soft-stops and refunds. Retargeting an existing code takes effect instantly on anything already printed, so confirm the destination with the user first. Two things not to do. Do not ask the user for their session cookie: it is an unscoped 30-day credential and this server will not accept it anyway. And if a claim fails with "not in your gallery", the code came from the anonymous free-pool shelf (browse_free_pool) — claims are gated to your own storefront, which browse_my_pool shows.

Tools

8 advertised

browse_free_pool
Advertised by the server during the last successful anonymous check.

List the QR artwork currently claimable for free on qart.uk, one per style, with a preview image URL for each. This is the ANONYMOUS shelf — the same selection every signed-out visitor sees, and these codes are what a guest can claim. Use it to show someone what is available or to describe the styles on offer. If you are acting for a signed-in account and want codes THAT account can actually claim, use browse_my_pool instead — the two storefronts differ, and a code from here may 403 on a claim.

browse_free_pool input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
buy_qr_outright
Advertised by the server during the last successful anonymous check.

How to buy ONE finished QR artwork with no account at all, paying from your own wallet over x402. Returns the live price and the exact request to make. This is the right tool when you have a wallet but no qart.uk account: get_credit_packs buys CREDITS, which still need an account to spend, and the Studio tools all require an OAuth token. This path requires neither — you GET https://qart.uk/api/v1/qr?url=..., it answers 402, you retry with a PAYMENT-SIGNATURE header, and the PNG comes back in the response body. You are charged ONLY if a real QR detector decodes the image: settlement runs after the scan verdict, so a request that produces nothing scannable is never settled and costs you nothing. Pay in USDC on Base — you do not need ETH, because the facilitator submits the transaction. Cannot be performed through MCP itself: a payment rides in an HTTP header and there is nowhere to put one here. This tool tells you the call; you make it.

buy_qr_outright input schema
{
  "type": "object",
  "properties": {
    "url": {
      "type": "string",
      "description": "The https destination you want the QR to encode. Optional — without it you get the price and the call shape."
    },
    "size": {
      "enum": [
        768,
        1024
      ],
      "type": "integer",
      "description": "Pixel size. 1024 costs more. Defaults to 768."
    }
  },
  "additionalProperties": false
}
explain_qart
Advertised by the server during the last successful anonymous check.

Explain how qart.uk works: scan verification, retargeting a printed code, the free claim pool and its daily allowances, Studio pricing, and what happens to credits when a run is stopped or fails. Use this before guessing at product details — pricing and allowances change and this returns the current text.

explain_qart input schema
{
  "type": "object",
  "properties": {
    "topic": {
      "enum": [
        "overview",
        "free-pool",
        "studio",
        "pricing",
        "retargeting"
      ],
      "type": "string",
      "description": "Which aspect to explain. Defaults to overview."
    }
  },
  "additionalProperties": false
}
get_credit_packs
Advertised by the server during the last successful anonymous check.

What Studio credits cost: the packs on sale, their price in USD, and roughly how many images each buys. Anonymous — this is a price list. Read it rather than quoting a price from memory; packs change. An agent that runs out mid-task can top up WITHOUT a human, paying from its OWN wallet: POST /api/qart/x402/credits?pack=... with a qart:purchase bearer token. The money comes from the application's wallet, never the user's card. Stripe checkout (POST /api/qart/checkout) remains human-only; hand the user the purchase URL for that.

get_credit_packs input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
get_dither_qr_parameters
Advertised by the server during the last successful anonymous check.

The complete parameter contract for qart.uk's dithered photo QR recipe — an error-diffused technique (after andrew-t) that dithers a photograph into the space around each QR module, so the finished 1-bit image reads as a picture and still scans. THIS TOOL GENERATES NOTHING. There is no API for the technique and no endpoint that will run it for you: it is a browser-side generator, and this tool returns the parameters, ranges, defaults and algorithm order so that YOU can implement it or instruct someone who will. Pair it with get_qr_matrix, which supplies the module grid and the function-pattern map the algorithm needs. It also returns the honest limits, which matter before anyone prints anything: no scan verdict is computed anywhere in this path, error correction wants to stay at H, and stricter detectors (zbar) reject output that phone-grade detectors accept. Treat a dithered code as untested until someone scans the actual printed sheet.

get_dither_qr_parameters input schema
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
get_qr_matrix
Advertised by the server during the last successful anonymous check.

Return the actual QR MODULE GRID for a payload — the black/white matrix, plus a per-module map of which modules are function patterns (finder, separator, timing, alignment, format info, version info, dark module) and which carry data. Both come back as one row string per row. Costs nothing, mints nothing, stores nothing. Use this when you are going to RENDER or transform a QR yourself: dithering a photo into it, drawing it as an SVG, laying it out for print, or reasoning about which modules are safe to alter. The function-pattern map is the point — any technique that paints over a QR has to know which modules a scanner uses to FIND the code (finder, timing, alignment) versus which merely carry bits. Do NOT use it to check whether a payload fits — preview_qr_encoding is smaller and answers that. Do NOT use it to get a qart.uk product: this is a plain standards QR, with no artwork, no scan verdict and no alias behind it. The matrix is canonical and untransformed: invert, rotation, mirror and any subpixel scaling are yours to apply afterwards.

get_qr_matrix input schema
{
  "type": "object",
  "properties": {
    "ecc": {
      "enum": [
        "L",
        "M",
        "Q",
        "H"
      ],
      "type": "string",
      "description": "Error correction level. Defaults to H, which is what any paint-over-the-code technique needs."
    },
    "end": {
      "type": "string",
      "description": "For 'event': end datetime."
    },
    "lat": {
      "type": "number",
      "description": "For 'geo': latitude."
    },
    "lng": {
      "type": "number",
      "description": "For 'geo': longitude."
    },
    "org": {
      "type": "string",
      "description": "For 'vcard': organization."
    },
    "url": {
      "type": "string",
      "description": "For 'url': the destination. For 'vcard'/'mecard': the website."
    },
    "auth": {
      "enum": [
        "WPA",
        "WEP",
        "nopass"
      ],
      "type": "string",
      "description": "For 'wifi': security type. Defaults to WPA."
    },
    "body": {
      "type": "string",
      "description": "For 'mailto': message body."
    },
    "mask": {
      "enum": [
        "auto",
        "0",
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7"
      ],
      "type": "string",
      "description": "Which of the 8 standard mask patterns to apply. 'auto' (default) picks the lowest-penalty one, exactly as the encoder in the browser does. All 8 are legal and scan identically; they differ only in how the light and dark modules are laid out, which is worth pinning when you are fitting a picture to the grid."
    },
    "name": {
      "type": "string",
      "description": "For 'vcard'/'mecard': full name."
    },
    "ssid": {
      "type": "string",
      "description": "For 'wifi': network name."
    },
    "text": {
      "type": "string",
      "description": "For 'text': the literal text."
    },
    "email": {
      "type": "string",
      "description": "Email address, for 'vcard'/'mecard'/'mailto'."
    },
    "phone": {
      "type": "string",
      "description": "Phone number, for 'vcard'/'mecard'/'tel'/'sms'/'whatsapp'."
    },
    "start": {
      "type": "string",
      "description": "For 'event': start datetime (YYYY-MM-DDTHH:MM)."
    },
    "title": {
      "type": "string",
      "description": "For 'vcard': job title. For 'event': event title."
    },
    "allDay": {
      "type": "boolean",
      "description": "For 'event': all-day (DATE values)."
    },
    "amount": {
      "type": "string",
      "description": "For 'paypal': optional amount."
    },
    "handle": {
      "type": "string",
      "description": "For social kinds (instagram, twitter, youtube, facebook, tiktok, linkedin, paypal): handle or profile URL."
    },
    "hidden": {
      "type": "boolean",
      "description": "For 'wifi': hidden network."
    },
    "address": {
      "type": "string",
      "description": "For 'vcard': postal address."
    },
    "message": {
      "type": "string",
      "description": "For 'sms'/'whatsapp': message text."
    },
    "subject": {
      "type": "string",
      "description": "For 'mailto': subject line."
    },
    "version": {
      "type": "integer",
      "maximum": 40,
      "minimum": 1,
      "description": "Force a QR version (1-40, size 21-177 modules). Omit for the smallest that fits. Pinning BELOW the fit is impossible and is raised to the fit, matching the Studio."
    },
    "location": {
      "type": "string",
      "description": "For 'event': location."
    },
    "password": {
      "type": "string",
      "description": "For 'wifi': network password."
    },
    "username": {
      "type": "string",
      "description": "For 'telegram': username or t.me URL."
    },
    "description": {
      "type": "string",
      "description": "For 'event': description."
    },
    "payloadKind": {
      "enum": [
        "url",
        "qart_code",
        "text",
        "wifi",
        "vcard",
        "mecard",
        "mailto",
        "tel",
        "sms",
        "geo",
        "whatsapp",
        "telegram",
        "event",
        "instagram",
        "twitter",
        "youtube",
        "facebook",
        "tiktok",
        "linkedin",
        "paypal"
      ],
      "type": "string",
      "description": "What the code should contain. Defaults to url."
    }
  },
  "additionalProperties": false
}
preview_qr_encoding
Advertised by the server during the last successful anonymous check.

Work out how a payload will encode as a QR code, without creating anything. Returns the exact string the pixels would carry, its byte length, the QR version and module count required, the capacity remaining at that version, and any warnings. Costs nothing and mints nothing. Use this to answer questions like "will this URL fit at error correction level H" or "how much does a long Wi-Fi password cost me in QR density". Higher ECC survives damage better but needs more modules for the same data; more modules print smaller and get harder to scan. payloadKind 'qart_code' sizes the RETARGETABLE variant instead: the pixels carry a 16-byte qart.uk/_ link rather than your data, which is usually several versions smaller. Compare the two before committing to a print. This returns metadata only, never the module grid. For the actual black/white matrix, call get_qr_matrix.

preview_qr_encoding input schema
{
  "type": "object",
  "required": [
    "payloadKind"
  ],
  "properties": {
    "ecc": {
      "enum": [
        "L",
        "M",
        "Q",
        "H"
      ],
      "type": "string",
      "description": "Error correction level, lowest to highest. Defaults to the Studio default if omitted."
    },
    "end": {
      "type": "string",
      "description": "For 'event': end datetime."
    },
    "url": {
      "type": "string",
      "description": "For payloadKind 'url': the destination."
    },
    "name": {
      "type": "string",
      "description": "For payloadKind 'vcard': full name."
    },
    "ssid": {
      "type": "string",
      "description": "For payloadKind 'wifi': network name."
    },
    "text": {
      "type": "string",
      "description": "For payloadKind 'text': the literal text."
    },
    "email": {
      "type": "string",
      "description": "For payloadKind 'vcard': email address."
    },
    "phone": {
      "type": "string",
      "description": "Phone, for vcard/mecard/tel/sms/whatsapp."
    },
    "start": {
      "type": "string",
      "description": "For 'event': start datetime (YYYY-MM-DDTHH:MM)."
    },
    "title": {
      "type": "string",
      "description": "For 'event': title. For 'vcard': job title."
    },
    "allDay": {
      "type": "boolean",
      "description": "For 'event': all-day (DATE values)."
    },
    "amount": {
      "type": "string",
      "description": "For 'paypal': optional amount."
    },
    "fields": {
      "type": "object",
      "description": "Payload fields for the kind. Flat sibling properties (url, phone, handle, …) are also accepted, matching get_qr_matrix."
    },
    "handle": {
      "type": "string",
      "description": "For social kinds: handle or profile URL."
    },
    "message": {
      "type": "string",
      "description": "For 'sms'/'whatsapp': message text."
    },
    "version": {
      "type": "integer",
      "maximum": 40,
      "minimum": 1,
      "description": "Force a QR version (size). Omit to use the smallest that fits."
    },
    "location": {
      "type": "string",
      "description": "For 'event': location."
    },
    "password": {
      "type": "string",
      "description": "For payloadKind 'wifi': network password."
    },
    "username": {
      "type": "string",
      "description": "For 'telegram': username or t.me URL."
    },
    "description": {
      "type": "string",
      "description": "For 'event': description."
    },
    "payloadKind": {
      "enum": [
        "url",
        "qart_code",
        "text",
        "wifi",
        "vcard",
        "mecard",
        "mailto",
        "tel",
        "sms",
        "geo",
        "whatsapp",
        "telegram",
        "event",
        "instagram",
        "twitter",
        "youtube",
        "facebook",
        "tiktok",
        "linkedin",
        "paypal"
      ],
      "type": "string",
      "description": "What the code should contain. 'qart_code' sizes the retargetable variant — a 16-byte qart.uk/_ link instead of your data. whatsapp/telegram/event/social kinds assemble a standard URL or VCALENDAR; they are verbatim, not retargetable."
    }
  },
  "additionalProperties": false
}
resolve_qart_code
Advertised by the server during the last successful anonymous check.

Resolve a scanned qart.uk code to the URL it currently points at. Accepts the alias ('_ab12cde'), or a full qart.uk URL to pull it out of. Returns targetUrl, or disabledReason if the owner retired it. This does not count as a scan and will not affect the owner's statistics. Only the '_' code class resolves here; older qart.uk links of other shapes are not in this pool.

resolve_qart_code input schema
{
  "type": "object",
  "required": [
    "code"
  ],
  "properties": {
    "code": {
      "type": "string",
      "description": "The code to resolve — '_ab12cde', '/_ab12cde', or 'https://qart.uk/_ab12cde'."
    }
  },
  "additionalProperties": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
687 ms
95th percentile latency
687 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 687 ms · metadata changed · 8 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http qart-uk-mcp https://qart.uk/api/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add qart-uk-mcp --url https://qart.uk/api/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable qart-uk-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "qart-uk-mcp": {
      "url": "https://qart.uk/api/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "qart-uk-mcp": {
      "type": "streamableHttp",
      "url": "https://qart.uk/api/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start qart-uk-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "qart-uk-mcp": {
      "type": "http",
      "url": "https://qart.uk/api/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http qart-uk-mcp https://qart.uk/api/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://qart.uk/api/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "qart-uk-mcp": {
      "serverUrl": "https://qart.uk/api/mcp"
    }
  }
}

Let your agent find its tools

Find servers like qart.uk MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run qart.uk MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing