Skip to content

Network Setup (SSE)

Network mode serves MCP over HTTP directly from the SQLatte FastAPI app — no local Python script, no subprocess. Any user with a URL and a token can connect. This is the right mode when several people share one SQLatte deployment.

Enable It

In config/config.yaml:

mcp:
  sse:
    enabled: true

This mounts /mcp on the running server:

Route Purpose
GET /mcp/sse SSE connection — clients connect here
POST /mcp/messages/ MCP protocol message endpoint

Client Config

{
  "mcpServers": {
    "sqlatte": {
      "url": "http://your-sqlatte-server:8000/mcp/sse",
      "headers": { "x-mcp-token": "<token>" }
    }
  }
}

The token can also be passed as a ?token= query parameter if your client doesn't support custom headers. Generate a token the same way as for local setup — see API Tokens & Admin Auth.

How Isolation Works

Each SSE connection validates its token against the config database and creates its own session — there is no shared mutable state between users. Per-connection identity (session ID, mask rules, SQL dialect for the connected database provider) is stored in contextvars, so concurrent connections from different users never see each other's session or masking rules. A missing or invalid token gets a 401 before any session is created.

GET /mcp/sse?token=<token>
  → validate token against config DB
  → create isolated session (username, db_config, api_token)
  → load that user's active mask rules
  → run MCP server loop scoped to this connection

Discovery Tools (Trino only)

When plugins.auth.enable_discovery_tokens: true, the SSE server advertises a fourth tool, discover_tables, that the local stdio server never exposes — it's checked per-connection via GET /auth/config's discovery_enabled flag, so a single running server can serve both discovery-enabled and legacy tokens correctly. It searches table/collection names by partial match across every catalog in allowed_catalogs, metadata only, no row data — useful for finding which catalog/schema a table actually lives in before querying it with ask_database. See Security Overview.

Notes

  • DNS rebinding protection is intentionally disabled at the transport layer — SQLatte handles authentication itself via the token, so this doesn't weaken security, but it does mean the endpoint should still sit behind TLS in production (reverse proxy termination, same as the rest of the app).
  • The SSE server reuses the same ask_database, list_tables, and get_schema tools, the same masking logic, and the same audit logging as the local stdio server — the only difference is transport, how the session is established, and the optional fourth discover_tables tool above.