# MCP server

The Model Context Protocol (MCP) lets an AI assistant call tools on your behalf. Ship Jay runs an MCP server so an assistant can quote shipments, read tracking and, if you allow it, buy labels.

- **Endpoint:** `https://shipjay.com/api/mcp`
- **Transport:** JSON-RPC 2.0 over HTTP POST. Responses are plain JSON, with no streaming.
- **Auth:** the same bearer API key as the REST API.
- **Protocol versions:** `2025-06-18`, `2025-03-26` and `2024-11-05`.

The server runs the same handlers as the REST API, with the same permissions, limits and audit trail. An agent can never do more than its key allows.

## Connect a client

Create a key first (see [Authentication and API keys](/docs/authentication)). Give an agent key only the permissions it needs.

Claude Desktop starts local servers, so use the `mcp-remote` bridge to reach a remote one. Edit `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "shipjay": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://shipjay.com/api/mcp", "--header", "Authorization:${SHIPJAY_AUTH}"],
      "env": { "SHIPJAY_AUTH": "Bearer sj_..." }
    }
  }
}
```

Restart Claude Desktop. The Ship Jay tools appear in the tools menu.
```bash
claude mcp add --transport http shipjay https://shipjay.com/api/mcp \
  --header "Authorization: Bearer sj_..."
```
Add this to `.cursor/mcp.json` in your project, or `~/.cursor/mcp.json` for every project:

```json
{
  "mcpServers": {
    "shipjay": {
      "url": "https://shipjay.com/api/mcp",
      "headers": { "Authorization": "Bearer sj_..." }
    }
  }
}
```
Any client that speaks MCP over HTTP needs two things: the URL `https://shipjay.com/api/mcp` and an `Authorization: Bearer sj_...` header. If your client can only start local programs, put the `mcp-remote` bridge in front as shown for Claude Desktop.

You can also talk to the server directly:

```bash
# List the tools this key may use
curl https://shipjay.com/api/mcp \
  -H "Authorization: Bearer $SHIPJAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'

# Call a tool
curl https://shipjay.com/api/mcp \
  -H "Authorization: Bearer $SHIPJAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": { "name": "get_tracking", "arguments": { "shipment_id": "2f6c3a9e-5d1b-4c7e-9a41-8b0d6e7f1c20" } }
  }'
```
Do not put the key in a shared repository. Use your client's way of keeping secrets, or an environment variable.

## Tools

`tools/list` returns only the tools the key may use. A key with `shipments:read` and nothing else sees the read tools and none of the buying tools. Tool names and permissions below come from the server itself.

| Tool | Permission | What it does |
| --- | --- | --- |
| `get_account` | any valid key | Show the organization, its wallet currency and what this key may do. |
| `list_ship_from` | `shipments:read` | List the saved ship-from addresses. Use one of the ids as from_address_id when quoting. |
| `verify_address` | `shipments:write` | Check whether a US address is deliverable and get the corrected version. |
| `quote_shipment` | `shipments:write` | Get rates for a package. Saves the shipment and does not spend money. |
| `buy_label` | `shipments:buy` | Buy a label for a rate from a quote. Spends wallet money. This tool spends money. |
| `list_shipments` | `shipments:read` | List recent shipments, newest first, optionally by status or tracking number. |
| `get_shipment` | `shipments:read` | Get one shipment. |
| `get_tracking` | `shipments:read` | Get the tracking status and scan history of a shipment. |
| `request_refund` | `refunds:write` | Ask the carrier to refund an unused label. |
| `get_wallet_balance` | `wallet:read` | Get the wallet balance in cents. |
| `list_returns` | `returns:read` | List return requests, optionally by status. |
| `approve_return` | `returns:write` | Approve a return. Buys a prepaid return label and spends wallet money. This tool spends money. |
| `list_rules` | `rules:read` | List the shipping rules. |
| `list_events` | `events:read` | Read recent account events, oldest first. |

Tool arguments are the fields of the matching REST call. For path ids the argument is named after the object, such as `shipment_id` for `buy_label` and `get_tracking`. Amounts are integer cents. The label file download is not offered as a tool, because a file does not fit a text answer.

A failed tool call comes back with `isError: true` and the same JSON error body as the REST API, with its `code` and `request_id`. See [Errors](/docs/errors).

## Buying through an agent

`buy_label` spends wallet money. The server derives the idempotency key from the shipment and the rate, so an agent that retries cannot buy the same label twice. The server tells the client to quote first and buy only after the person approves, and a well behaved client will ask. You should not rely on that alone.

**Safety advice for agents that can spend money:** - **Do not give an agent `shipments:buy` unless it must buy.** A key with `shipments:read` and `shipments:write` can research and quote all day and cannot spend anything.
- **Always set limits on the key.** A per label and a per day limit decide the worst case if the agent misbehaves, is tricked by text in a web page or an email, or is simply wrong.
- **Keep a person in the loop.** Configure your client to ask for confirmation before it calls `buy_label` and `approve_return`. Show the carrier, service and price in the prompt.
- **Use a separate key for each agent**, with an expiry date, and an IP allowlist if it runs from a fixed address. Revoke it when the job is done.
- **Treat shipment data as untrusted input.** Names, notes and references may contain instructions meant for the model. Your policy should live in shipping rules and key limits, not in a prompt.
- **Review the audit trail.** Everything the key does is recorded with the key's name.

Shipping rules apply to agents too. A rule that blocks a destination or removes a carrier holds no matter who asks. See [Shipping rules](/docs/shipping-rules).