What you can do
- list_products — Read available products, current USD totals, artwork requirements, and the active x402 payment configuration.
- get_product_configuration — Read one product’s exact canvas dimensions, safe area, bleed, required front count, price breakdown, terms, and privacy links. Optionally pass couponCode to preview a server-validated discount without reserving usage.
- create_asset_uploads — Allocate temporary upload slots. This writes records but does not purchase a product.
- create_order_intent — Claim uploaded artwork and record confirmed delivery details and customer consent. Before create_order_intent or payment, collect the actual recipient's first and last name in customer.name, separated by a space. Do not use a single first name, wallet label, or agent nickname. Ask the customer for missing name details; never invent a surname. If the recipient has only one name, stop and contact support before ordering. Returns a payment URL, amount, digest, expiry, and private status capability; it does not sign a payment.
- get_order_status — Read one intent’s payment and fulfillment state using its status capability. It does not expose the delivery address or contact details.
Current scope: one physical deck per order, direct delivery to U.S. addresses, and only products returned by the live catalog. Coupons are supported through the optional couponCode on get_product_configuration and create_order_intent. Digital downloads, store pickup, multi-deck quantities, cancellations, and refunds are not MCP tools. Artwork must already be rendered; the server does not turn source photos into finished card fronts. A separate trusted wallet/client must support the returned x402 v2 payment rail. Configured payments do not guarantee that a particular wallet client can sign them.
Endpoint and authentication
https://photomatchfun.com/api/mcpTransport: remote Streamable HTTP, stateless, with JSON responses. No PhotoMatchFun login, API key, OAuth flow, or global Authorization header is required to connect or discover products. Use an MCP client rather than opening the endpoint as a web page. Clients limited to local stdio or the older HTTP+SSE transport need their own compatible bridge; no bridge is supplied here.
Authorization is scoped to individual operations: binary uploads require the slot’s Authorization: Bearer uploadToken; order creation requires each assetId and separate claimToken; status requires intentId and statusToken. HTTP status requests use Authorization: Bearer statusToken. Keep these values private. Never send wallet private keys, seed phrases, card numbers, or CVCs.
Desktop and server clients can connect without an Origin header. Browser-origin requests must come from a server-approved origin; arbitrary cross-origin browser clients are not supported. A 403 Origin is not allowed response requires an approved integration origin, not a PhotoMatchFun password.
Connect with VS Code
VS Code supports this remote HTTP configuration. Use Install in VS Code above, or merge the following entry into .vscode/mcp.json in your workspace. Preserve any existing servers. The installation shortcut opens VS Code’s installation flow; review the endpoint and its trust prompts before enabling tools.
{
"servers": {
"photomatchfun": {
"type": "http",
"url": "https://photomatchfun.com/api/mcp"
}
}
}- Run MCP: List Servers from the Command Palette, select photomatchfun, and start it.
- Open chat and enable the PhotoMatchFun tools in the tool picker. Ask it to list available products without creating an order.
- Expect five tools, including list_products and get_order_status. If tools are missing, inspect the server output and verify your organization permits remote MCP servers.
Alternatively, with the code command installed, run this command in a POSIX shell to add the server to your user profile:
code --add-mcp '{"name":"photomatchfun","type":"http","url":"https://photomatchfun.com/api/mcp"}'Other clients that implement Streamable HTTP can use the same endpoint in their remote-server settings. Configuration key names are client-specific; the VS Code servers/type format is not a universal MCP configuration file.
Test the connection without placing an order
With Node.js 20 or later, install the SDK in a project directory, save the JavaScript below as smoke.mjs, and run it. It only discovers tools and reads the catalog; it creates no upload slots, orders, or payments.
npm install @modelcontextprotocol/sdk
node smoke.mjsimport { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const client = new Client({ name: "photomatchfun-quickstart", version: "1.0.0" });
try {
await client.connect(new StreamableHTTPClientTransport(
new URL("https://photomatchfun.com/api/mcp")
));
console.log("Tools:", (await client.listTools()).tools.map(tool => tool.name));
const result = await client.callTool({ name: "list_products", arguments: {} });
if (result.isError) throw new Error(JSON.stringify(result.content));
console.log(JSON.stringify(result.structuredContent ?? result.content, null, 2));
} finally {
await client.close();
}Verification on September 9, 2026: the official JavaScript SDK 1.30.0 connected to the public endpoint without credentials and read the five tools, two resources, workflow prompt, and live catalog. VS Code configuration and installation-link syntax were checked against Microsoft’s documentation; the VS Code graphical installation flow was not exercised. This connection check does not certify wallet signing or a paid fulfillment run.
Sample excerpt from list_products structuredContent on that date (not a current quote; re-read the catalog and product configuration for every order):
{
"products": [
{
"productId": "photomatchfun-custom-photo-card-deck-delivery",
"total": "24.98",
"currency": "USD",
"renderedPhotoFrontsRequired": 8,
"available": true
}
],
"next": "Call get_product_configuration before rendering or uploading artwork."
}Successful tools return structuredContent and readable JSON text in content. Tool failures can return isError: true even when the HTTP transport succeeded. Treat an empty catalog or configured: false payment rail as unavailable; do not invent a purchasable product.
Example customer prompts
- Show me the available PhotoMatchFun decks, their current total prices, and the artwork requirements. Do not create an order yet.
- Check the current product configuration and help me prepare the required card fronts. Show me the artwork, delivery details, total, terms, and privacy notice for confirmation before creating an order intent.
- Check the status of my existing order using the intent ID and status capability I supplied privately. Do not create a new order or payment.
MCP also exposes the purchase_photo_matching_game prompt and the resources photomatchfun://commerce/guide and photomatchfun://commerce/x402. The latter reports the current public payment configuration.
Border options and who renders the cards
Border rendering belongs to the agent. get_product_configuration returns artwork.borders with renderer: agent, serverAppliesBorder: false, and available options. artwork.composition exposes the website's resolved Classic corner-thumbnail and logo switches, sizes, rotations, public asset URLs, and whiteBorderLayout. Use the default white border to match the website, a configured classic overlay, a customer-approved custom border, or no decorative border. Obey the per-corner switches and scaled layout, fit rotated graphics inside the safe bounds, and composite all graphics before upload: serverAppliesGraphics is false. Do not add a second border to an already rendered front. Website theme choices are not MCP order parameters; do not send borderId, themeId, or rendering instructions to create_order_intent.
Re-read widthPx, heightPx, dpi, safeArea, trim, acceptedContentTypes, maxBytesPerAsset, and renderedPhotoFrontsRequired from the live product configuration. Upload exactly that many unique complete photo fronts, one file per slot. The server supplies configured static cards, duplicates the photo fronts according to the deck configuration, and supplies the card back; do not upload those extra cards. Extend backgrounds through bleed, keep faces and text inside the safe area, and omit crop marks. An accepted upload checks the file contract, not visual print quality; review every rendered front with the customer.
- Classic: use the product-specific overlay only when the live artwork.borders.options includes classic with an assetUrl. Check its aspect ratio and transparent opening against the product canvas before composing; do not stretch a pickup-format border onto a delivery card.
- Custom: render a border approved by the customer into the final image. There is no server-side border selection or rendering tool.
- None: submit a complete photo-front canvas without a decorative frame. Bleed and safe-area requirements still apply.
- Themed designs on the consumer website are a separate creation flow. MCP does not expose a themeId or generate illustrations; do not infer compatibility from a theme name.
Fulfillment status and failed-order handoff
requires_payment means no confirmed payment yet; payment_processing means payment outcome is still being resolved; paid means payment is recorded; fulfillment_processing means print submission is in progress; fulfilled plus fulfillment.providerOrderId means provider acceptance, not shipped or delivered; fulfillment_failed means stop and request operator review. get_order_status also returns fulfillment.delivery with the latest QPMN providerStatus, tracking links, fetchedAt, and refreshError (checks cached for up to five minutes). A null providerStatus means QPMN did not supply a status; use the tracking page for transit updates. Tracking availability alone does not confirm shipment or delivery. Expired unpaid intents cannot be paid. Keep the original intentId, orderId, orderDigest, payment transaction, and private statusToken. An administrator can retry eligible failed fulfillment from Admin Orders using the saved payment; agents must not create a replacement paid intent. A provider timeout or missing order ID may represent an accepted order, so operator review is required before resubmission.
For operator review, provide the order ID, intent ID, transaction reference, and the status shown by get_order_status. Keep the statusToken private. Admin Orders shows the recorded provider error, retry eligibility, payment status, and retry attempts. A retry uses the same saved artwork and recipient details, so a recipient or artwork error must be repaired by an operator before resubmission. The retry button does not edit the original order or collect payment.
Required recipient details before ordering
Before create_order_intent or payment, collect the actual recipient's first and last name in customer.name, separated by a space. Do not use a single first name, wallet label, or agent nickname. Ask the customer for missing name details; never invent a surname. If the recipient has only one name, stop and contact support before ordering.
The integration uses the first word of customer.name as first_name and the remaining words as last_name for delivery and billing. QPMN requires both fields. New intents reject a one-word name. Older unpaid intents with incomplete saved recipient names are blocked before payment or free-order confirmation; create a corrected unpaid intent after customer review. Already-recorded payments and uncertain settlements must continue through the existing recovery flow. Successful intent creation does not prove that the print provider will accept every address detail.
Fictional name-only illustration, not a complete tool call: customer.name = "Avery Morgan" becomes first_name = "Avery" and last_name = "Morgan". customer.name = "Avery" is incomplete. Use the actual recipient's confirmed name, never the illustration. Keep customer.name; do not introduce unsupported firstName or lastName input fields.
- Confirm a real contact email and phone number, street address and unit if needed, city, two-letter U.S. state, ZIP or ZIP+4, and country US.
- Read back the full recipient name, contact and shipping details with the product, artwork, final total, terms, and privacy notice before creating the intent. Never substitute a wallet or agent identity for the delivery recipient.
- Recheck recipient details before POSTing paymentUrl. The same printer requirements apply to test orders, discounted orders, and zero-total coupon confirmations. The successful creation of an intent is not a provider validation guarantee.
Ordering, permissions, and payment
- Discover a live product, then call get_product_configuration with its productId and optional couponCode. Read server-issued prices and dimensions afresh. A quote does not reserve coupon usage; eligibility and pricing are checked again at intent creation.
- Complete the recipient preflight: Before create_order_intent or payment, collect the actual recipient's first and last name in customer.name, separated by a space. Do not use a single first name, wallet label, or agent nickname. Ask the customer for missing name details; never invent a surname. If the recipient has only one name, stop and contact support before ordering. Have the customer review the product, complete artwork, total, U.S. delivery and contact details, terms, and privacy notice. Record their actual consent with termsAccepted: true, acceptedAt as an ISO timestamp, and source: customer; never infer consent from a tool result.
- Render exactly the required number of complete card-front canvases. Call create_asset_uploads with productId and count; PUT one JPEG, PNG, or WebP to each returned uploadUrl using its requiredHeaders. Preserve assetId and claimToken separately.
- Call create_order_intent with productId, an opaque idempotencyKey, customer name/email/phone/shippingAddress, customerConsent, the same optional couponCode, and the assetId/claimToken pairs. Reuse the key only for unchanged order inputs, including the coupon. Identical retries return the original frozen price without reserving another coupon use.
- Review the returned price, intentId, orderDigest, and expiresAt. After the customer authorizes payment, POST the returned paymentUrl. For positive totals, its HTTP 402 PAYMENT-REQUIRED header describes the discounted requirement. A trusted x402 v2 wallet signs it; repeat the same POST with PAYMENT-SIGNATURE. The MCP connection alone cannot sign a payment. If the intent returns paymentRequired: false and amountCents: 0, POST the same paymentUrl to explicitly confirm the free order; no wallet signature or transfer is required.
- A successful payment response is HTTP 200 or 202. Payment settles, or a zero-total order is explicitly confirmed, before submission to the print provider. Payment success is not fulfillment success. After HTTP 200/202, poll get_order_status with the original intentId and statusToken. Report provider acceptance only when status is fulfilled and fulfillment.providerOrderId is present; this does not mean delivery. If status is fulfillment_failed or fulfillment.needsOperatorReview is true, report that payment succeeded but fulfillment failed, stop automatic ordering, and do not create another order or payment. Back off between status requests.
If settlement times out or its outcome is unknown, follow the same-payment retry instructions rather than signing a second authorization. Do not work around a wallet timeout by sharing its secrets with this service.
Apply a coupon
Use the same couponCode when previewing a product and creating its intent. Codes are normalized for case, spaces, and hyphens. Invalid, disabled, expired, not-yet-active, exhausted, pickup-only, or below-minimum coupons return an error; the server never silently falls back to full price.
{
"name": "get_product_configuration",
"arguments": {
"productId": "photomatchfun-custom-photo-card-deck-delivery",
"couponCode": "YOUR_COUPON_CODE"
}
}For create_order_intent, add couponCode alongside the normal customer, customerConsent, assets, productId, and idempotencyKey fields. Review the returned price.amount, price.amountCents, coupon.savings, and paymentRequired before authorizing the order. Client-supplied prices, percentages, and discount amounts are rejected.
Intent creation reserves coupon usage in the same transaction that claims artwork. Payment or free-order confirmation redeems that reservation once. Retries keep the original amount even if the coupon is later edited. Expired unpaid intents release their reservation when their status or payment URL is checked. Abandoned reservations otherwise become reclaimable on subsequent coupon use after 24 hours. An uncertain in-flight settlement must be recovered on the same intent.
Pricing and operational limits
There is currently no separate MCP connection or per-tool fee. Physical orders use the server-issued USD product and shipping total after validated coupon discounts. Positive totals settle through the exact x402 requirement in USDC; zero totals require no payment. Your model provider and wallet/network may have separate costs. Never hard-code the example price, recipient, or network. Read the current product configuration and payment requirement before each purchase.
- MCP transport: 100 requests per 10 minutes per observed client IP; maximum JSON request body 1 MiB. Clients behind shared egress can share a limit.
- Upload-slot creation: 48 calls per hour per client identifier (a hash derived from the client IP), not 48 individual slots.
- Binary uploads: 48 requests per hour per observed client IP. Maximum 12 MiB per image; exact dimensions and content types come from the product contract.
- Order-intent creation: 20 calls per hour per client identifier. Use exactly quantity.renderedPhotoFrontsRequired from the live product configuration, including zero when configured. There is no fixed 1–12 asset limit; the configured deck determines the count.
- Upload/claim capabilities expire after one hour; unpaid order intents expire after 30 minutes. Use each returned expiresAt rather than a local estimate.
- HTTP limits return 429 and Retry-After; tool-level limits return an error with retry guidance. Back off on 503 or temporary unavailability. Do not retry invalid artwork or changed idempotency inputs unchanged.
Data handling and support
Order creation sends the customer’s name, email, phone, U.S. shipping address, consent record, and artwork references to PhotoMatchFun. The pending order payload is encrypted at rest. Uploaded artwork is validated and re-encoded, and artwork plus delivery details are provided to the fulfillment provider when a paid order is submitted. Payment status can include a public wallet address and transaction identifier.
Capability expiry is an access deadline, not a promise that every copy of order or image data is deleted at that moment. Order records and provider processing follow the linked privacy and terms policies. Keep capability tokens, image URLs, and customer details out of public logs, shared prompts, and analytics. Your MCP client and model provider have their own data-handling policies.
Agent-readable documentation
This page and its Markdown version share the same source. /llms.txt is a concise navigation aid that points agents to the documentation. It is not universal agent registration and does not guarantee discovery, indexing, or support by a particular client.