$SALTY_MCP/mcp. Set the env var to match your deployment:
@modelcontextprotocol/sdk 1.x with WebStandardStreamableHTTPServerTransport — the Streamable HTTP transport from the 2025-06 MCP spec. Single endpoint (POST /mcp), stateless mode, plain JSON responses.
The 15 tools
Tight by design — more tools = bigger context window = worse agent performance.| # | Tool | What it does |
|---|---|---|
| 1 | search_people | Filter / paginate people |
| 2 | get_person | Fetch a person by id |
| 3 | create_person | New person |
| 4 | update_person | Patch a person |
| 5 | search_companies | Filter / paginate companies |
| 6 | get_company | Fetch a company by id |
| 7 | create_company | New company |
| 8 | update_company | Patch a company |
| 9 | search_deals | Filter / paginate deals |
| 10 | create_deal | New deal |
| 11 | update_deal | Patch a deal |
| 12 | add_note | Note on a person/company/deal |
| 13 | log_activity | Activity on a person/company/deal |
| 14 | get_schema | Describe the workspace schema |
| 15 | add_attribute | Extend the schema with a new attribute |
delete_* tools. Deletion is destructive — agents go through the REST API or CLI where a human can review. This is a deliberate safety choice.
Every tool description ends with Returns errors with code and message; respect rate limit headers. Input schemas avoid oneOf/anyOf at the top level (breaks Claude’s MCP client).
How clients connect
You don’t configure anything per-client beyond pointing it at the MCP URL. The discovery + OAuth flow is automatic:- The client POSTs
/mcpwith no auth → server returns 401 +WWW-Authenticate: Bearer resource_metadata=…. - The client GETs the well-known protected-resource metadata to discover the auth server (it’s the same host as
$SALTY_API). - The client GETs
/.well-known/oauth-authorization-serverto discover the token + registration endpoints. - The client POSTs
/oauth/register(RFC 7591 dynamic client registration) → gets aclient_id. - The client redirects the user’s browser to
/oauth/authorize?…&code_challenge=…→ user lands on Salty’s consent page → clicks Approve → browser returns to client with?code=…. - The client POSTs
/oauth/tokenwithcode+code_verifier→ getssalty_oat_…access token (90-day lifetime) + refresh token. - The client retries
POST /mcpwithAuthorization: Bearer salty_oat_…→ server forwards the bearer to the Salty API and returns the tool result.
Adding Salty to Claude.ai (web)
Settings → Connectors → Add custom connector. URL:$SALTY_MCP/mcp. Click Connect; the OAuth flow above runs in a popup. Done.
Adding Salty to Claude Desktop / Cursor
These clients only speak stdio MCP, so we bridge throughmcp-remote — a stdio↔HTTP shim that forwards every JSON-RPC call to $SALTY_MCP/mcp.
Two ways to authenticate. Pick the one that matches your use case.
Option A — OAuth (recommended for end users)
The client runs the full PKCE dance on first connect.mcp-remote opens a browser, you approve at /oauth/consent, the salty_oat_… token is cached in ~/.mcp-auth. Subsequent launches are silent.
Option B — Static API key (recommended for dev / scripted setups)
Skip the browser flow by passing a long-livedsk_live_… key via --header. The MCP server forwards any bearer to the Salty API, which accepts all three kinds — sk_live_…, salty_oat_…, and Supabase JWTs (see Authentication).
- No
~/.mcp-authcache to invalidate if you reset local DB or rotate OAuth client rows. - One value to swap (
env.SALTY_API_KEY) — useful if a dev workspace gets reseeded. - Works in non-interactive contexts where there’s no browser to open.
POST /api-keys. Fully quit the client (⌘Q on macOS) after editing the config — most MCP clients only re-read on cold start.
Sample tool call
After the client is authorized, calls look like JSON-RPC 2.0:What MCP inherits from the REST API
Every tool forwards to the corresponding REST endpoint with the user’s bearer token, so MCP gets:- RLS — agents can only touch their own workspace
- Rate limits — per-plan sustained + burst
- Usage cap —
salty_oat_…tokens count as agent traffic - Idempotency — pass
Idempotency-Keyin the tool’s HTTP layer - Audit log — every call lands in
api_call_log
curl and the SDK.