> ## Documentation Index
> Fetch the complete documentation index at: https://docs.safefetch.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server

> Connect SafeFetch to Claude Desktop, Cursor, and other MCP clients

SafeFetch includes a built-in [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server. This lets AI assistants send actions, check status, and manage approvals directly through their tool interface.

## Setup

### 1. Get your account ID

Your account ID is shown on your [dashboard](https://api.safefetch.dev/dashboard). It looks like `acct_abc123`.

### 2. Configure your MCP client

Add SafeFetch to your MCP client config. The server runs over stdio.

**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json theme={null}
{
  "mcpServers": {
    "safefetch": {
      "command": "npx",
      "args": ["-y", "@safefetch/mcp"],
      "env": {
        "DATABASE_URL": "your-database-url",
        "MCP_ACCOUNT_ID": "your-account-id"
      }
    }
  }
}
```

**Cursor** (`.cursor/mcp.json` in your project root):

```json theme={null}
{
  "mcpServers": {
    "safefetch": {
      "command": "npx",
      "args": ["-y", "@safefetch/mcp"],
      "env": {
        "DATABASE_URL": "your-database-url",
        "MCP_ACCOUNT_ID": "your-account-id"
      }
    }
  }
}
```

### 3. Restart your client

The SafeFetch tools will appear in your assistant's tool list.

## Available tools

### `send_action`

Send a new action. Returns immediately with an action ID, or set `sync: true` to wait for completion.

```
send_action({
  url: "https://api.stripe.com/v1/refunds",
  method: "POST",
  body: { charge: "ch_3Qx9R2eZ" },
  approve: true
})
```

**Parameters:**

| Field     | Type    | Default  | Description                                 |
| --------- | ------- | -------- | ------------------------------------------- |
| `url`     | string  | required | Target URL                                  |
| `method`  | string  | `POST`   | HTTP method (GET, POST, PUT, PATCH, DELETE) |
| `body`    | object  | —        | Request body                                |
| `headers` | object  | —        | Custom headers                              |
| `approve` | boolean | `false`  | Require human approval before execution     |
| `dedupe`  | string  | —        | Deduplication key (24h window)              |
| `retries` | number  | `3`      | Max retry attempts (1-100)                  |
| `sync`    | boolean | `false`  | Wait for completion and return result       |

### `get_action`

Get the current status and result of an action.

```
get_action({ id: "act_Xk9mP2nQ4rT1vW" })
```

### `list_actions`

List recent actions, optionally filtered by status.

```
list_actions({ status: "awaiting_approval", limit: 10 })
```

### `approve`

Approve an action waiting for human sign-off. Moves it to `pending` for immediate dispatch.

```
approve({ id: "act_Xk9mP2nQ4rT1vW" })
```

### `cancel`

Cancel a pending or awaiting-approval action.

```
cancel({ id: "act_Xk9mP2nQ4rT1vW" })
```

### `retry`

Retry a failed or cancelled action. Creates a new action with the same parameters.

```
retry({ id: "act_Xk9mP2nQ4rT1vW" })
```

## Example conversation

```
You: Refund charge ch_3Qx9R2eZ on Stripe, but I want to approve it first.

Assistant: I'll send that refund through SafeFetch with approval required.

> send_action({ url: "https://api.stripe.com/v1/refunds", method: "POST",
>   body: { charge: "ch_3Qx9R2eZ" }, approve: true })

The refund action has been created (act_Xk9mP2nQ4rT1vW) and is
awaiting your approval. Want me to approve it?

You: Yes, approve it.

Assistant:
> approve({ id: "act_Xk9mP2nQ4rT1vW" })

Approved. The refund is now being dispatched to Stripe.

> get_action({ id: "act_Xk9mP2nQ4rT1vW" })

Completed — Stripe returned 200. The refund went through.
```

## Action statuses

| Status              | Description               |
| ------------------- | ------------------------- |
| `pending`           | Queued for dispatch       |
| `active`            | Currently being delivered |
| `awaiting_approval` | Held for human approval   |
| `completed`         | Successfully delivered    |
| `failed`            | All retries exhausted     |
| `cancelled`         | Manually cancelled        |
