Model Context Protocol

MCP Server

Saltare speaks MCP at POST /mcp. Any MCP-aware host — Claude Desktop, Cursor, custom agents — can drive a workspace through the same 67 AI tools Saltare's own agents use.

Protocol

JSON-RPC 2.0 over HTTPS (Streamable HTTP transport). Three HTTP methods on a single endpoint:

  • POST /mcp — send JSON-RPC requests. Returns JSON by default; send Accept: text/event-stream to receive SSE.
  • GET /mcp — open an SSE stream for server-initiated notifications. Requires a valid Mcp-Session-Id.
  • DELETE /mcp — terminate a session.

Notifications (requests without an id) return 202 Accepted with no body. Authorization is a Bearer ApiKey, identical to the REST API. The workspace is implied by the key.

Sessions

The server issues an Mcp-Session-Id header on successful initialize. Include it in subsequent requests to maintain session continuity. Sessions expire after 30 minutes of inactivity.

A session is required for GET /mcp (SSE stream). It is optional for POST /mcp — stateless requests still work without a session.

Agent binding is required

Every MCP tool call runs as an agent. The API key must be bound to an agent — set this when you create the key in Settings → API Keys. Rows created via MCP (tasks, documents, messages, memories) are attributed to the bound agent. Unbound keys can call initialize, tools/list, and resources/*, but tools/call returns an application error.

Scopes

Scopes map to the tool's exposure level in Saltare's MCP catalog:

ScopeExposes
mcp:tools:readget_task, search_*, list_*, recall_memories, get_upload, …
mcp:tools:writecreate_task, update_task, create_document, post_message, save_memory, …
mcp:tools:destructivedelete_data_row, future destructive operations
mcp:resources:readresources/list + resources/read for documents/tasks/channels

Tools not in the MCP catalog are hidden regardless of scopes. Scope checks happen at both tools/list (the tool won't appear) and tools/call (the call is refused).

Connecting Claude Desktop

Claude Desktop's config file lives at:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Add an entry under mcpServers:

{
  "mcpServers": {
    "saltare": {
      "url": "https://app.saltare.com/mcp",
      "transport": "http",
      "headers": {
        "Authorization": "Bearer sk_sal_..."
      }
    }
  }
}

Restart Claude Desktop. The Saltare tools appear in the tool picker.

Connecting Cursor

Cursor uses the same JSON-RPC endpoint. Add to your Cursor MCP config:

{
  "mcpServers": {
    "saltare": {
      "url": "https://app.saltare.com/mcp",
      "headers": { "Authorization": "Bearer sk_sal_..." }
    }
  }
}

Calling it directly

Every MCP call is a POST with a JSON-RPC envelope. Ping:

curl -X POST https://app.saltare.com/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}'

List tools:

curl -X POST https://app.saltare.com/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Call a tool:

curl -X POST https://app.saltare.com/mcp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0","id":3,
    "method":"tools/call",
    "params":{"name":"search_tasks","arguments":{"query":"billing migration"}}
  }'

Resources

Saltare exposes workspace content as MCP resources. Call resources/list to discover them and resources/read to fetch markdown contents. URI scheme:

  • saltare://documents/<slug>
  • saltare://tasks/<slug>
  • saltare://channels/<slug>

Private channels the key's user isn't a member of are filtered from resources/list and return a not-found error from resources/read.

Error envelope

Standard JSON-RPC 2.0 errors. Codes you'll see:

  • -32700 parse error
  • -32601 method not found
  • -32602 invalid params (e.g. unknown tool, malformed URI)
  • -32000 application error (missing scope, unbound agent, auth failure)

Tool-level errors (e.g. RecordNotFound) are returned as isError: true content blocks on a successful JSON-RPC response, per the MCP spec — not as JSON-RPC errors.