# MCP Tools for Commerce: The Complete Guide

URL: https://firestarter.network/blog/mcp-tools-for-commerce
Published: 2026-06-11
Author: Victor Young

What makes a good commerce MCP tool design? Approval gates, idempotent polling, consequential action marking. Deep-dive the 5 Firestarter tools with example tool-call JSON.

MCP tools for commerce require different design principles than tools for search or information retrieval. A failed search can be retried with no consequences. A failed checkout call might result in a charge with no order, or an order with no tracking. This guide covers what makes a commerce MCP tool robust, deep-dives the five Firestarter tools with example call JSON, and explains how MCP differs from standard function calling for consequential actions.

## Why Commerce Tools Need Different Design

The [Model Context Protocol](https://modelcontextprotocol.io) gives models a standard way to call external tools. The protocol itself is tool-agnostic — the hard design work is in the tools themselves.

For read-only tools (search, lookup, status), the main design concern is response shape: give the model well-structured output it can reason over. For consequential tools — tools that move money, place orders, or trigger irreversible actions — four additional properties matter:

**1. Idempotency where possible.** Status polling should be safe to call repeatedly. If a model retries a status check because it didn't get a clean response, nothing bad should happen.

**2. Non-idempotent actions must be explicit.** Approve and execute are not idempotent. The tool schema should make this visible, and the tool description should tell the model when not to retry blindly.

**3. Approval gates separate research from commitment.** A commerce tool that goes straight from "here's what I found" to "I charged your card" is unsafe by design. There must be an explicit step where a human (or an authorized autonomous rule) provides approval.

**4. Exception handling returns to a defined state.** Every tool call should leave the execution in a known status — even on failure. "Unknown" is not a valid post-call state for a purchasing tool.

These principles are reflected in the Firestarter MCP tool design. See [/mcp](/mcp) for the full manifest and [/use-cases/mcp-commerce-tool](/use-cases/mcp-commerce-tool) for the design rationale.

## MCP vs Function Calling for Commerce

Both MCP and function calling (in the OpenAI/Anthropic sense) let models invoke external tools. For commerce, the differences matter:

**Tool discovery.** With function calling, you define the tools per-request in the API call. With MCP, tools are declared in a manifest the client fetches at connection time. This means the model always has an up-to-date view of available tools — including any new capabilities added to the server — without you rebuilding your prompt.

**Consequential action metadata.** MCP tool definitions can carry metadata fields that hint to the client how to handle a tool. Firestarter marks approve and execute calls as consequential, which clients like Claude use to display confirmation prompts before calling.

**Persistent server connection.** An MCP server maintains state across a session. For a multi-step purchase flow — execute, refine, approve, track — the execution ID is threaded through the session without you manually tracking it in your prompt context.

**Standardized auth.** MCP auth is configured once at install time (`--header "Authorization: Bearer ..."`), not injected into every API call. This means the key never appears in prompt context.

The practical difference: for one-off integrations, function calling is simpler to set up. For a commerce capability you want available across Claude sessions and projects, MCP is the right abstraction. See also [/openapi](/openapi) for the function-calling-compatible OpenAPI spec.

## The Five Firestarter MCP Tools

### `firestarter_execute`

**What it does:** Creates a new purchase execution from a natural-language request. Firestarter parses the request, queries its seller network, scores options, and returns the top matches. The execution is created in `awaiting_approval` status by default — nothing is charged.

**When to call it:** When the user asks to buy, order, source, or find a product with intent to purchase.

**Input schema:**

```json
{
  "name": "firestarter_execute",
  "description": "Create a new purchase execution. Returns execution ID and ranked options. Does not charge until approve is called.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "request": {
        "type": "string",
        "description": "Natural language description of what to buy"
      },
      "budget": {
        "type": "object",
        "properties": {
          "max_total": { "type": "number" }
        }
      }
    },
    "required": ["request"]
  }
}
```

**Example call:**

```json
{
  "tool": "firestarter_execute",
  "arguments": {
    "request": "ergonomic office chair under $400, lumbar support required",
    "budget": { "max_total": 400 }
  }
}
```

**Example response:**

```json
{
  "id": "exec_01jcm...",
  "status": "awaiting_approval",
  "options": [
    {
      "rank": 1,
      "title": "Autonomous ErgoChair Pro",
      "price": 349.00,
      "seller_rating": 4.6,
      "estimated_delivery": "3–5 days",
      "notes": "Adjustable lumbar, 4D armrests"
    },
    {
      "rank": 2,
      "title": "Branch Ergonomic Chair",
      "price": 329.00,
      "seller_rating": 4.7,
      "estimated_delivery": "5–7 days",
      "notes": "Dynamic lumbar support"
    }
  ],
  "approval_required": true
}
```

---

### `firestarter_status`

**What it does:** Returns the current state of an execution. Idempotent — safe to call any number of times without side effects. Returns status, selected item details (post-approval), tracking information (post-shipment), and receipt URL (post-delivery).

**When to call it:** After approval to check checkout progress; whenever the user asks for an order update; to verify final delivery.

**Example call:**

```json
{
  "tool": "firestarter_status",
  "arguments": {
    "execution_id": "exec_01jcm..."
  }
}
```

**Example response (post-shipment):**

```json
{
  "id": "exec_01jcm...",
  "status": "shipped",
  "selected": {
    "title": "Autonomous ErgoChair Pro",
    "price": 349.00
  },
  "tracking_number": "EZ1234567890",
  "tracking_url": "https://track.easypost.com/EZ1234567890",
  "estimated_delivery": "2026-06-16",
  "receipt_url": "https://api.firestarter.network/receipts/exec_01jcm..."
}
```

Status values follow a defined lifecycle: `awaiting_approval` → `processing` → `shipped` → `delivered` (or `cancelled`, `exception`). No status is a dead end — `exception` transitions to `awaiting_action` with a structured description of what's needed.

---

### `firestarter_approve`

**What it does:** Triggers checkout for an execution in `awaiting_approval` state. Initiates the Stripe charge (held in escrow) and EasyPost label generation. **Not idempotent** — do not retry on timeout without first calling `firestarter_status` to check whether the approval completed.

**When to call it:** Only after presenting options to the user and receiving explicit confirmation. The tool description marks this as a consequential action.

**Example call:**

```json
{
  "tool": "firestarter_approve",
  "arguments": {
    "execution_id": "exec_01jcm...",
    "selected_option_rank": 1
  }
}
```

**Important:** If `firestarter_approve` returns a timeout or network error, call `firestarter_status` before retrying. Calling approve twice on the same execution returns an error (the execution is no longer in `awaiting_approval` state), but it's better to check than to handle the error.

---

### `firestarter_cancel`

**What it does:** Cancels an execution. If called before checkout completes, releases the escrow hold. If called after shipment, initiates the return flow. Returns the execution in `cancelled` status with any applicable refund details.

**When to call it:** When the user explicitly asks to cancel; if an exception state cannot be resolved; as a cleanup step in error handling.

**Example call:**

```json
{
  "tool": "firestarter_cancel",
  "arguments": {
    "execution_id": "exec_01jcm...",
    "reason": "User changed mind before shipment"
  }
}
```

---

### `firestarter_message`

**What it does:** Sends a follow-up message to an in-progress execution to refine requirements. Can be called in `awaiting_approval` state to change constraints before checkout. Returns an updated options list.

**When to call it:** When the user wants to change color, size, budget, or delivery speed after an execution has started but before approval; when an exception state requires clarification.

**Example call:**

```json
{
  "tool": "firestarter_message",
  "arguments": {
    "execution_id": "exec_01jcm...",
    "message": "Need delivery by end of week — prioritize fastest shipping option even if slightly over budget"
  }
}
```

This returns an updated `options` array without creating a new execution. The execution ID is preserved, which is important for audit continuity — the full refinement history is attached to the single execution record.

## Designing the Approval Gate in Practice

The approval gate is where MCP tool design meets human-computer interaction. The model can gather all the information needed for a purchase decision and surface it cleanly — but the decision itself should involve a human.

A well-designed agent flow using these tools:

1. **`firestarter_execute`** — gather options
2. Present options clearly with price, delivery time, and seller rating
3. Ask the user to confirm a specific option
4. **`firestarter_approve`** only after explicit confirmation
5. **`firestarter_status`** to report the outcome

What to avoid: calling `firestarter_approve` as part of the same response that presents options ("Here are two choices — I went ahead and ordered the first one"). The approval step should be a separate model turn, after user input.

The server-side approval checkpoint is a safety net, not a substitute for good client-side design. See [/use-cases/agent-approval-audit-api](/use-cases/agent-approval-audit-api) for the full control plane design.

## Getting Started

Install the MCP server:

```bash
claude mcp add firestarter \
  --transport sse \
  --url https://api.firestarter.network/mcp \
  --header "Authorization: Bearer fs_live_YOUR_KEY"
```

Full manifest: [https://api.firestarter.network/.well-known/mcp.json](https://api.firestarter.network/.well-known/mcp.json)

API key and free tier at [/developers](/developers). See also [/scenarios](/scenarios) for example use cases, and [/compare/firestarter-vs-rye](/compare/firestarter-vs-rye) for how the tool set compares to other commerce API approaches.

## FAQ

### Can I use these tools with OpenAI models instead of Claude?

The MCP server uses SSE transport per the MCP spec. OpenAI doesn't yet have native MCP client support, but you can use the Firestarter OpenAPI spec as function definitions with any OpenAI-compatible API. See [/openapi](/openapi).

### What's the difference between `firestarter_execute` and just sending a message to `firestarter_message`?

`firestarter_execute` creates a new execution with a new ID. `firestarter_message` refines an existing execution without creating a new one. Use `message` when you want to iterate on an open execution; use `execute` to start fresh.

### How do I handle the `exception` status?

Call `firestarter_status` to get the structured exception description, surface it to the user, and either call `firestarter_message` with a resolution instruction or `firestarter_cancel` to stop the execution and release the escrow hold.

### Are there rate limits on status polling?

Standard polling limits apply (see [/docs](/docs)). For high-frequency status checks in autonomous pipelines, use webhook callbacks rather than polling — configure a `webhook_url` in the execution request body.

### How does the seller network work?

Sellers list catalogs via the Firestarter [seller API](/sell). When an execution is created, the network is queried in real time. Sellers pay a 3% commission on completed sales only — no listing fee. Buyers pay no transaction fees.
