# MCP for AI agents

URL: https://docs.lastscanned.com/mcp

`https://mcp.lastscanned.com` is an MCP server (Streamable HTTP) over the same API. It signs in with your API key, and lookups count toward the same usage and limits as REST calls.

It also connects with no key at all: `track_package` then gets the same one free lookup a day as the REST API, and `list_carriers` always works. An MPP credit key (`lsk_pack_…`, from [paying per request](/authentication#pay-per-request)) works anywhere an API key does and spends its credits.

## Set up

```bash tab="Claude Code"
claude mcp add --transport http lastscanned https://mcp.lastscanned.com \
  --header "Authorization: Bearer lsk_live_…"
```

```text tab="Claude"
Settings → Connectors → Add custom connector

Server URL:              https://mcp.lastscanned.com
Request header:          Authorization: Bearer lsk_live_…
```

```text tab="ChatGPT"
Settings → Apps & Connectors → Advanced settings → Developer mode, then Create

Server URL:              https://mcp.lastscanned.com/lsk_live_…
Authentication:          No authentication
```

```json tab="Cursor"
// ~/.cursor/mcp.json
{
  "mcpServers": {
    "lastscanned": {
      "url": "https://mcp.lastscanned.com",
      "headers": { "Authorization": "Bearer lsk_live_…" }
    }
  }
}
```

```json tab="VS Code"
// .vscode/mcp.json
{
  "servers": {
    "lastscanned": {
      "type": "http",
      "url": "https://mcp.lastscanned.com",
      "headers": { "Authorization": "Bearer lsk_live_…" }
    }
  }
}
```

Other clients (Windsurf and the rest): an HTTP server at `https://mcp.lastscanned.com` with the header `Authorization: Bearer lsk_live_…`.

ChatGPT connectors can't send a header, so the key goes in the URL path instead. Treat that URL like the key itself. When you make a key in the [dashboard](https://app.lastscanned.com/keys), it shows each of these with your key filled in.

## Tools

| Tool | Arguments | Returns |
|---|---|---|
| `track_package` | `tracking_number`, `carrier?` | Status, estimated delivery and scan history: a [tracking result](/tracking#the-response). |
| `track_packages` | `tracking_numbers` (up to 100, 35 per carrier), `carrier?` | `{ results }`, one entry per number with `result` or `error`. |
| `list_carriers` | | Carrier ids for `carrier`. |

## Behavior

- Stateless: each POST is one JSON-RPC message answered with plain JSON. No sessions, no SSE.
- A failed lookup comes back as a tool result with `isError: true` and the same `{ "error": { "code", "message" } }` as the REST API, so the model can read it.
- When the free lookup or the daily limit is used up, or a key is invalid, the error also carries what to tell the person: `user_action`, plus `signup_url`, `lookup_url`, `upgrade_url` or `setup_command` as they apply. `track_packages` needs a key (`auth_required`).
- A successful result can carry a `notice` (the free lookup or the day's last free number was just used, or a credit key is running low) and, with a credit key, `credits_remaining`.
- `GET https://mcp.lastscanned.com/` and `/.well-known/mcp.json` describe the server (name, tools, endpoint) for MCP registries.
- Also served at `https://api.lastscanned.com/mcp`.
