Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt

Use this file to discover all available pages before exploring further.

MCP Provider

An MCP Provider registers extra Model Context Protocol tools with the merchant’s MCP server. Once a merchant installs your app, every tool your manifest declares becomes available to any AI assistant the merchant already pointed at LaunchMyStore — Claude Desktop, Claude Code, Cursor, Nova AI, and any other MCP-compatible client. Where App Proxy lets a buyer’s browser call your server, an MCP Provider lets a merchant’s AI assistant call your server. Same idea — signed forwarding — different audience.
LaunchMyStore already ships 143 built-in MCP tools (get_products, add_coupon, refund_order, …). An MCP Provider extension adds your app’s tools to that registry. They show up in the same tools/list response and are callable with the same client config — no extra MCP server to add.

When to use an MCP Provider

Use caseTools to expose
Reviews appreviews_list, reviews_moderate, reviews_reply
Loyalty apployalty_get_points, loyalty_grant_points, loyalty_redeem
Shipping appshipping_quote, shipping_create_label, shipping_track
Email marketing appcampaign_create, campaign_send_test, audience_segment
Analytics appanalytics_run_query, report_generate
Anything the merchant might reasonably ask an AI to do on your app’s behalf is a candidate. Read-only tools are usually safe to expose liberally; write tools should be guarded by your own scope checks. If your tool needs to be callable by buyers (not merchants), use App Proxy instead — MCP is merchant/operator only.

How it works

AI client                LaunchMyStore MCP             Your app server
─────────                ─────────────────             ───────────────
tools/list  ───────────► 1. Built-in tools (143)
                         + 2. Installed-app tools
                              from every app's
                              extensions.mcpProvider
                         ◄─── combined list

tools/call               3. Match tool by namespace:
  reviews_moderate ────► 4. Forward to your endpoint
                              with signed payload  ──► 5. Verify signature
                                                       6. Run tool
                                                       7. Respond
                         ◄──── response                ◄──
        ◄────────────────  pass-through
  1. The merchant adds the LaunchMyStore MCP server to their AI client (one-time, per the MCP Overview).
  2. When the client lists tools, the platform returns the built-in registry plus every tool declared by every app the merchant has installed.
  3. When the client calls a tool that belongs to your app, the platform forwards the call to your mcpProvider.endpoint with an HMAC-signed body.
  4. Your server verifies the signature, runs the tool, returns the result (JSON), and the platform streams it back to the AI client.

Manifest

Declare your tools in app.json under extensions.mcpProvider:
{
  "handle": "foundry-reviews",
  "name": "Foundry Reviews",
  "version": "1.0.0",
  "extensions": {
    "mcpProvider": {
      "endpoint":   "https://reviews.your-domain.app/mcp",
      "namespace":  "reviews",
      "timeoutMs":  10000,
      "tools": [
        {
          "name":        "reviews_list",
          "description": "List recent reviews for a product, optionally filtered by rating or moderation status.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "productId":    { "type": "string", "description": "Product UUID" },
              "minRating":    { "type": "number", "minimum": 1, "maximum": 5 },
              "status":       { "type": "string", "enum": ["pending", "published", "rejected"] },
              "limit":        { "type": "number", "default": 20, "maximum": 100 }
            },
            "required": ["productId"]
          },
          "scopes": ["read_products"]
        },
        {
          "name":        "reviews_moderate",
          "description": "Approve or reject a review by ID.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "reviewId": { "type": "string" },
              "action":   { "type": "string", "enum": ["approve", "reject"] },
              "reason":   { "type": "string" }
            },
            "required": ["reviewId", "action"]
          },
          "scopes": ["write_products"],
          "destructive": true
        }
      ]
    }
  }
}

Top-level fields

FieldRequiredDescription
endpointyesHTTPS URL of your MCP handler. The platform POSTs every tools/call for a tool in this provider to this URL.
namespaceyesLowercase prefix prepended to every tool name when the platform exposes them. Tools below ship to the AI as reviews_list, reviews_moderate (manifest names are kept verbatim — pick names already prefixed with your namespace).
timeoutMsnoPer-call timeout (default 10000, max 30000). Calls exceeding this return an MCP error to the client.
toolsyesArray of tool definitions. At least one.

Per-tool fields

FieldRequiredDescription
nameyesTool name. Must start with {namespace}_ (validated at install). Lowercase + underscores.
descriptionyesOne- or two-sentence summary. This is the prompt the AI reads to decide when to call the tool — be precise about what it does and what it requires.
inputSchemayesJSON Schema (draft-07 subset) describing parameters. The platform validates inputs before forwarding.
scopesnoPermission scopes required to call the tool. The platform rejects calls if the merchant’s MCP token doesn’t carry them.
destructivenoSet true for tools that mutate / delete data. AI clients show a confirmation prompt before invoking. Defaults to false.
outputSchemanoJSON Schema describing the response shape. Used for client-side rendering hints; not enforced.

Wire protocol (LaunchMyStore → your app)

When a merchant’s AI client invokes one of your tools, the platform POSTs to your endpoint:
POST https://reviews.your-domain.app/mcp
Content-Type: application/json
X-LMS-Signature: <hex(HMAC-SHA256(rawBody, app.clientSecret))>
X-LMS-AppId:     <your app UUID>
X-LMS-RequestId: <uuid — also in body.request_id>
X-LMS-Shop:      <merchant domainSlug>
{
  "tool":      "reviews_moderate",
  "arguments": { "reviewId": "8f1d…-…", "action": "approve" },
  "shop": {
    "domainSlug":  "raja337276",
    "storeId":     "9c1ee…-…",
    "name":        "Raja's Store"
  },
  "actor": {
    "type":     "merchant",
    "userId":   "5f02b…-…",
    "scopes":   ["read_products", "write_products"]
  },
  "request_id": "8f1d…-…"
}
FieldDescription
toolThe full tool name (e.g. reviews_moderate).
argumentsValidated against your inputSchema before forwarding.
shopThe store the AI is operating on.
actor.typemerchant, staff, or nova (the platform’s built-in AI).
actor.userIdStable id of the human or AI principal.
actor.scopesScopes from the merchant’s MCP token.
request_idEcho this in your response logs for cross-correlation.

Verifying in your app

The signature is the hex HMAC-SHA256 of the raw request body using your app’s clientSecret. Identical to the Functions network-access signing and App Proxy patterns.
import express from 'express';
import crypto from 'node:crypto';

const app = express();
// Capture the RAW body so the HMAC over it matches.
app.use('/mcp', express.raw({ type: 'application/json', limit: '1mb' }));

app.post('/mcp', (req, res) => {
  const raw = req.body; // Buffer
  const given = req.get('X-LMS-Signature') || '';
  const expected = crypto
    .createHmac('sha256', process.env.CLIENT_SECRET)
    .update(raw)
    .digest('hex');

  if (
    given.length !== expected.length ||
    !crypto.timingSafeEqual(Buffer.from(given, 'hex'), Buffer.from(expected, 'hex'))
  ) {
    return res.status(401).json({ error: 'invalid signature' });
  }

  const body = JSON.parse(raw.toString('utf8'));
  return handle(body, res);
});

Response shape

Return one of the MCP tools/call content types in a plain { content } object — the platform wraps it into the full MCP envelope before sending to the client:
{
  "content": [
    { "type": "text", "text": "Approved review 8f1d…-… on product Cotton Shirt." }
  ]
}
To return structured data the AI can reason over, use the standard text block with a JSON string, or pass structuredContent:
{
  "content": [
    { "type": "text", "text": "Found 3 reviews matching status=pending." }
  ],
  "structuredContent": {
    "reviews": [
      { "id": "8f1d…", "rating": 5, "body": "Loved it" },
      { "id": "9c1ee…", "rating": 4, "body": "Solid quality" },
      { "id": "ab12c…", "rating": 2, "body": "Color was off" }
    ]
  }
}
To signal a soft failure (e.g. “review not found”), respond with isError: true:
{
  "isError": true,
  "content": [
    { "type": "text", "text": "Review 8f1d…-… does not exist." }
  ]
}
For hard server errors, return a non-2xx HTTP status; the platform maps it to an MCP protocol error and surfaces it to the client.

Permissions & scopes

The merchant’s MCP token carries the scopes they granted to your app at install. The platform enforces three layers before reaching your server:
  1. Tool scope check — if a tool declares scopes: ["write_products"] and the token lacks it, the platform rejects without calling you.
  2. Schema validationarguments must satisfy inputSchema. Type mismatches return an MCP error without reaching you.
  3. Destructive confirmation — clients are encouraged to prompt for destructive: true tools, but it’s a UI hint, not a hard guarantee. Treat every write call as if it could fire.
Your handler should still re-check that the actor is allowed to perform the tool — defense in depth.

Namespacing & collisions

All installed providers share one tool namespace. To prevent collisions:
  • Every tool name must start with {namespace}_ (validated on install).
  • Pick a unique, app-specific namespace — reviews, loyalty, shipping_aero, etc. The install endpoint rejects manifests that collide with a built-in tool name or a tool already installed on the merchant.
For multi-word app names use a short prefix: Foundry Reviewsnamespace: "reviews" (already short and clear) or namespace: "foundry" if you ship more than one tool family later.

Caching, batching, and rate limits

ConcernBehaviour
ConcurrencyThe platform calls your endpoint sequentially per merchant per MCP session. Concurrent merchants are independent.
TimeoutDefault 10 s per call, max 30 s. Override via timeoutMs.
RetriesNone. MCP tools/call is one-shot — surface partial-result info inside content.
Rate limitSubject to the merchant’s MCP server quota (see MCP Overview). Your endpoint doesn’t have its own quota.
If a tool needs heavy work, return early with a job id and expose a companion *_status tool the AI can poll.

Discovery

Once your app is installed, the merchant can confirm the tools loaded by running tools/list from their AI client. The standard MCP Tools Reference page lists built-in tools — your app’s tools appear in tools/list output but not in the public docs (since they’re per-app).

Versioning

Your tool definitions are pinned to the app version that was installed. When you publish a new app version with a changed mcpProvider, the platform:
  • Adds new tools immediately for fresh installs.
  • Holds existing installs at the version they installed at — the merchant upgrades through the standard app-update flow (App Versioning).
So removing a tool in a new version doesn’t yank it out from under existing merchants. Bump the major version when removing a tool to make the change visible.

Security checklist

  • Verify X-LMS-Signature on every call. Reject unsigned calls with 401.
  • Re-authorize on the server side. Don’t trust actor.scopes blindly — re-check that the actor owns the resource they’re touching (e.g. the review really belongs to this merchant).
  • Be conservative with destructive: false. If in doubt, mark destructive so AI clients prompt for confirmation.
  • Bound response size. Return at most ~50 KB of text per call; the AI has a context budget.
  • Don’t return raw error stacks in content — AI assistants will paste them at the merchant. Log internally; respond with a clean message.

Development & testing

  1. Run your MCP handler locally (http://localhost:PORT/mcp).
  2. Tunnel it (ngrok / cloudflared) so the platform can reach it.
  3. Set extensions.mcpProvider.endpoint to the tunnel URL in your dev app’s app.json.
  4. Install the dev app on a test store.
  5. Add the LaunchMyStore MCP server to your AI client (per MCP Overview) and ask the AI to call your tool by description — e.g. “list pending reviews for product X”.
To unit-test your handler in isolation, mimic the platform’s POST:
import crypto from 'node:crypto';
const body = JSON.stringify({
  tool: 'reviews_list',
  arguments: { productId: 'p-1' },
  shop: { domainSlug: 'dev-store', storeId: 's-1', name: 'Dev Store' },
  actor: { type: 'merchant', userId: 'u-1', scopes: ['read_products'] },
  request_id: 'r-1',
});
const sig = crypto.createHmac('sha256', process.env.CLIENT_SECRET).update(body).digest('hex');
const res = await fetch('http://localhost:4101/mcp', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-LMS-Signature': sig },
  body,
});
console.log(await res.json());

See also