SurfSense/surfsense_mcp
MODSetter b7ad5ecfff feat(models): drop catalogue models that cannot serve a turn
Passing OpenRouter's metadata filters does not prove a model can complete a
turn through this harness, so dead-but-advertised models kept reaching users
and failing mid-stream. A new model_compatibility table holds one verdict per
model, a weekly Celery sweep re-probes stale entries, and catalogue
generation reads the blocked ids back so those models are never offered.
Also excludes :batch variants, which advertise full chat metadata and then
reject completions outright.

Auto-pin now falls through to Auto when an explicitly selected global config
is absent from the current worker's catalogue. Returning it handed
load_llm_bundle an id it could not resolve, ending the turn with SERVER_ERROR
on one of the four uvicorn workers while the identical request succeeded on
the others. Catalogue refresh also re-materializes GLOBAL_MODELS, which
previously kept its boot snapshot until restart.

On the web side a single dropped connection surfaced as one toast per
in-flight query and dozens of PostHog exceptions, with no retry button.
Network errors now share a toast id, are deduped per endpoint before capture,
carry host and online context, and count as retryable.

Consolidates the model filter helpers duplicated between the model list and
OpenRouter services into openrouter_model_normalizer, renames OoxmlDefect to
OoxmlError, and includes a ruff format and import-order pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 18:59:11 +05:30
..
mcp_server fix(mcp): preserve note title on content replace 2026-08-06 12:24:04 +02:00
tests feat(models): drop catalogue models that cannot serve a turn 2026-08-14 18:59:11 +05:30
.dockerignore feat(mcp): add Dockerfile for remote streamable-http deployment 2026-07-07 18:27:19 +02:00
.env.example refactor(mcp): rename SURFSENSE_PAT to SURFSENSE_API_KEY 2026-07-06 03:40:36 +02:00
.gitignore chore(mcp): scaffold surfsense-mcp package 2026-07-06 02:29:19 +02:00
Dockerfile refactor(mcp): flatten to mcp_server package, drop src layout 2026-07-07 20:24:53 +02:00
pyproject.toml refactor(mcp): flatten to mcp_server package, drop src layout 2026-07-07 20:24:53 +02:00
README.md feat(docs): update README files to include Walmart as a data source for all language versions 2026-07-25 15:58:46 -07:00
uv.lock build(mcp): declare starlette and uvicorn dependencies 2026-07-07 18:27:19 +02:00

SurfSense MCP Server

A Model Context Protocol server that exposes SurfSense to MCP clients like Claude Code, Cursor, and Claude Desktop. It talks to a SurfSense backend purely over its REST API using a SurfSense API key — it imports no backend code.

Connect it two ways:

  • Hosted (recommended) — point your client at https://mcp.surfsense.com/mcp and pass your API key in a header. Nothing to install or keep running.
  • Self-host (stdio) — run the server yourself against any backend (cloud or your own). Best for self-hosters and clients without remote-server support.

Tools

Search-space selector

  • surfsense_list_workspaces — list the workspaces (search spaces) you can access
  • surfsense_select_workspace — pick the active workspace by name or id

Scrapers (all platforms)

  • surfsense_web_crawl, surfsense_google_search, surfsense_reddit_scrape, surfsense_youtube_scrape, surfsense_youtube_comments, surfsense_instagram_scrape, surfsense_instagram_details, surfsense_tiktok_scrape, surfsense_tiktok_comments, surfsense_tiktok_user_search, surfsense_tiktok_trending, surfsense_google_maps_scrape, surfsense_google_maps_reviews, surfsense_indeed_scrape, surfsense_amazon_scrape, surfsense_walmart_scrape, surfsense_walmart_reviews
  • surfsense_list_scraper_runs, surfsense_get_scraper_run — retrieve past results in full (useful when a large result was truncated inline)

Knowledge base

  • surfsense_search_knowledge_base — semantic + keyword search over stored content
  • surfsense_list_documents, surfsense_get_document
  • surfsense_add_document, surfsense_upload_file
  • surfsense_update_document, surfsense_delete_document

Workspace-scoped tools default to the active workspace; pass workspace (a name or id) to override for a single call. Ids never need to be typed by hand — the model carries them between calls.

Get an API key

  1. SurfSense → API Playground → API Keys: create a personal key (ss_pat_…). It is shown only once.
  2. Toggle API key access on for the workspace(s) you want to use.

Connect (hosted)

Point your client at the hosted server and send the key as a Bearer token. For clients that read an mcpServers map (Cursor, Claude Desktop, and others):

{
  "mcpServers": {
    "surfsense": {
      "url": "https://mcp.surfsense.com/mcp",
      "headers": { "Authorization": "Bearer ss_pat_your_key_here" }
    }
  }
}

Claude Code, from a terminal:

claude mcp add --transport http surfsense https://mcp.surfsense.com/mcp \
  --header "Authorization: Bearer ss_pat_your_key_here"

Most MCP clients accept this url + headers form; check your client's docs for its exact remote-server field.

Self-host (stdio)

Run the server yourself when you host your own backend or use a client without remote support. It uses uv:

cd surfsense_mcp
uv sync
uv run python -m mcp_server.selfcheck   # verify tools register correctly

Then add it to your client. Cursor (~/.cursor/mcp.json or a project .cursor/mcp.json):

{
  "mcpServers": {
    "surfsense": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/SurfSense/surfsense_mcp", "python", "-m", "mcp_server"],
      "env": {
        "SURFSENSE_BASE_URL": "http://localhost:8000",
        "SURFSENSE_API_KEY": "ss_pat_your_token_here"
      }
    }
  }
}

Claude Code:

claude mcp add surfsense \
  -e SURFSENSE_BASE_URL=http://localhost:8000 \
  -e SURFSENSE_API_KEY=ss_pat_your_token_here \
  -- uv run --directory /absolute/path/to/SurfSense/surfsense_mcp python -m mcp_server

Claude Desktop: add the same mcpServers block as Cursor to claude_desktop_config.json (Settings → Developer → Edit Config).

Configuration

See .env.example. For self-host, secrets are passed as environment variables by the client; never commit tokens.

Backend dependency

surfsense_search_knowledge_base calls POST /api/v1/documents/search-semantic, a thin endpoint that exposes the backend's existing hybrid retriever over REST. All other tools use pre-existing SurfSense endpoints.