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

# REST vs MCP vs CLI

> Choose the right Salty surface for your task — REST API, MCP server, CLI, or webhooks. A decision matrix for AI agents, application code, and humans.

> Salty exposes four interfaces over the same workspace data: **REST API**, **MCP server**, **CLI**, and **signed webhooks**. They share auth, rate limits, usage caps, idempotency, and audit logging — but they're built for different callers. This page tells you which one to use when.

## TL;DR — which surface for which caller

| Caller                                                             | Use                       | Why                                                                          |
| ------------------------------------------------------------------ | ------------------------- | ---------------------------------------------------------------------------- |
| AI agent in Claude Desktop / Cursor / ChatGPT                      | **MCP**                   | OAuth 2.1, 15 tools curated for context efficiency, instructions auto-loaded |
| Your application code (Node, Python, Go, etc.)                     | **REST** + TypeScript SDK | Full surface, generated typed client, idempotency keys                       |
| Human at a terminal — one-off lookups, key management, log tailing | **CLI** (`salty`)         | Browser OAuth, OS keychain, `salty logs tail`                                |
| External system that needs to react to changes                     | **Webhooks**              | Signed (HMAC-SHA-256), retried with backoff, auto-deactivated on 8 fails     |

## Detailed comparison

|                          | REST API                                    | MCP                                                    | CLI                                   | Webhooks                                                                   |
| ------------------------ | ------------------------------------------- | ------------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------------------- |
| **URL / host**           | `$SALTY_API` (`api.trysalty.com`)           | `$SALTY_MCP/mcp`                                       | local — `salty` binary                | your URL (passed on subscribe)                                             |
| **Transport**            | HTTPS JSON                                  | HTTPS JSON (Streamable HTTP, stateless)                | HTTPS via OAuth-bearer                | HTTPS POST from Salty to you                                               |
| **Auth**                 | `Authorization: Bearer sk_live_…` (API key) | `Authorization: Bearer salty_oat_…` (OAuth 2.1 + PKCE) | OAuth (browser, token in OS keychain) | HMAC signature on inbound request                                          |
| **Surface size**         | 34 endpoints, full CRUD on everything       | 15 curated tools (no `delete_*` by design)             | 9 command groups                      | events for every object's create/update/delete + schema mutations          |
| **Pagination**           | cursor (`next_cursor`)                      | cursor (returned in tool output)                       | cursor (auto-paginated via `--limit`) | one event per delivery                                                     |
| **Idempotency**          | `Idempotency-Key` header (24h)              | inherited via REST forward                             | inherited                             | `delivery_id` for receiver-side dedupe                                     |
| **Rate limit**           | per-workspace token bucket (plan tier)      | same — inherited                                       | same                                  | inbound: rate-limited at delivery worker (\~50 req/s to a single endpoint) |
| **Usage cap**            | meters agent traffic, exempts JWT admin     | meters (MCP forwards)                                  | meters (CLI uses OAuth)               | doesn't count — outbound only                                              |
| **Schema introspection** | `GET /schema`                               | `get_schema` tool                                      | `salty schema show`                   | N/A                                                                        |
| **Audit log**            | every call lands in `api_call_log`          | same                                                   | same                                  | `webhook_deliveries` table                                                 |

## Decision tree

**Is the caller a human, an AI agent, or another machine?**

* **Human (you) at the terminal** → CLI. `salty login` once, then `salty people list`, `salty keys create`, `salty logs tail`. Stays out of the way.
* **AI agent connected via Claude Desktop, Cursor, or ChatGPT** → MCP. Drop the config snippet, restart, done. The agent gets [server-level instructions](/docs/mcp/agent-guide) automatically.
* **Your own application code (a backend service, a script, a worker)** → REST. Use the TypeScript [SDK](/docs/api-reference/introduction) for ergonomics, or curl/Postman for one-offs.
* **External system reacting to state changes** → Webhooks. Register an endpoint with `POST /webhook-endpoints` (REST) or `salty webhooks add` (CLI), verify signatures, react.

You'll often use **multiple** surfaces in the same product. Common pattern: a backend service writing via REST, an AI agent reading + writing via MCP, your alerting hooked up via webhooks, and you on the CLI for ops.

## Common workflows by surface

| Task                    | REST                            | MCP                           | CLI                                                                                              |
| ----------------------- | ------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------ |
| Create a person         | `POST /people`                  | `create_person`               | `salty people create --email …`                                                                  |
| List people with filter | `GET /people?filter=…`          | `search_people`               | `salty people list --limit 50`                                                                   |
| Get a single person     | `GET /people/:id`               | `get_person`                  | `salty people get <id>`                                                                          |
| Patch a person          | `PATCH /people/:id`             | `update_person`               | (REST only)                                                                                      |
| Add a schema attribute  | `POST /schema/:type/attributes` | `add_attribute`               | `salty schema add-attribute --object person --key tier --type enum --values free,pro,enterprise` |
| Log a meeting           | `POST /activities`              | `log_activity`                | (REST only)                                                                                      |
| Create a task           | `POST /tasks`                   | (no MCP tool by design)       | (REST only)                                                                                      |
| Register a webhook      | `POST /webhook-endpoints`       | (no MCP tool by design)       | `salty webhooks add --url … --events …`                                                          |
| Define a custom object  | `POST /custom-objects`          | (no MCP tool by design)       | (REST only)                                                                                      |
| Tail the audit log      | `GET /workspace/usage-logs`     | (no MCP tool)                 | `salty logs tail`                                                                                |
| Check usage             | `GET /workspace/usage`          | (no MCP tool — admin surface) | `salty usage`                                                                                    |

**Why is the MCP surface smaller?** More tools = larger context window pollution = worse agent performance. Deletion, task creation, webhook registration, custom-object definition, and usage queries are all admin-ish operations a human should drive. The 15 MCP tools are the agent's day-to-day write surface; everything else goes through REST or CLI where a human can review.

## Latency profile

All four surfaces hit the same Postgres in the same region — so end-to-end latency depends on which middleware chain runs:

| Surface          | Typical hot-path latency (p95)                 |
| ---------------- | ---------------------------------------------- |
| REST             | 30-50ms                                        |
| MCP              | 50-90ms (REST + JSON-RPC marshalling)          |
| CLI              | 80-200ms (includes OS keychain lookup + HTTPS) |
| Webhook delivery | 1-3s end-to-end (worker tick + receiver RTT)   |

Per-plan rate-limit ceilings are validated under load with k6.

## Mixing surfaces

A typical solopreneur stack might look like:

```text theme={null}
┌──────────────────────────────────┐
│  Claude Desktop / Cursor         │
│  → MCP (15 tools, OAuth)         │
└──────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────┐
│  Your backend (Node/Python)      │
│  → REST API (SDK or curl)        │
└──────────────────────────────────┘
              │
              ▼
┌──────────────────────────────────┐         ┌─────────────────────┐
│  Salty API + Postgres             │ ──────► │  Your webhook       │
│                                  │ signed  │  receiver           │
└──────────────────────────────────┘ HMAC    └─────────────────────┘
              ▲
              │
┌──────────────────────────────────┐
│  You at the terminal             │
│  → CLI (salty login, salty logs)   │
└──────────────────────────────────┘
```

Every interaction is logged. Every state change fires events. Every surface respects the same plan caps and rate limits.

## Related

* [REST API → Introduction](/docs/api-reference/introduction) — conventions, errors, pagination
* [MCP → Introduction](/docs/mcp/introduction) — 15 tools, OAuth flow
* [MCP → Agent guide](/docs/mcp/agent-guide) — the operating manual auto-loaded on initialize
* [CLI → Introduction](/docs/cli/introduction) — `salty login` and every command
* [Webhooks](/docs/webhooks/introduction) — signature verification, retry schedule, meta-events
