Skip to content

Latest commit

 

History

History

registry

Folders and files

README.md

Add your plugin to SurfSense

Thanks for building something for SurfSense users. This page takes you from an MCP server to a plugin anyone can connect in the app. It is written for people and for coding agents alike; if you are an agent helping someone list a plugin, also read the checklist for agents.

The short version: a SurfSense plugin is an MCP server. You run the server; this folder only holds a short JSON entry pointing at it. Listing a plugin is one pull request that adds that entry and an icon.

What a plugin is

MCP, the Model Context Protocol, is an open standard for giving AI apps tools. An MCP server offers tools, each with a name, a description, an input schema and a few hints about what it does. An MCP client connects to the server, lists those tools and calls them.

In SurfSense, the agent is the client:

 Settings → Plugins                         your MCP server
 ┌──────────────────┐   lists your tools    ┌──────────────────┐
 │ user clicks      │ ────────────────────► │ search_docs      │
 │ Connect          │                       │ read_page        │
 └──────────────────┘                       └──────────────────┘
          │                                          ▲
          ▼                                          │ calls a tool,
 an Agentic chat: "what do Acme's docs say           │ with approval
 about rate limits?" ────────────────────────────────┘ when needed
  1. A user turns on Allow third-party plugins in Settings → Plugins → Browse, finds your plugin there, reads its page, and presses Connect, signing in if your server needs it. Third-party plugins stay hidden and unused until the user allows them.
  2. In an Agentic chat, the agent sees your tools beside SurfSense's own and calls them when they help. The user can also type @your-plugin to point the agent at it.
  3. Your server does the work and answers. SurfSense shows the result as a step in the reply.

So there is nothing SurfSense-specific to build. If your server works in other MCP clients, it works here unchanged, and the server you write for SurfSense works in them too. Your code never enters this repository and never runs on the user's computer.

1. Get your server ready

  • Remote, over Streamable HTTP, on HTTPS, reachable from the public internet. SurfSense does not start servers from a command (npx, uvx) and does not speak the older SSE transport. Every official MCP SDK serves Streamable HTTP.

  • Protocol 2025-03-26 or newer, the first with Streamable HTTP; 2025-11-25 or later is best.

  • Stateless if you can. A server that keeps no session between requests survives restarts and scaling, and loses nothing when SurfSense reconnects.

  • Annotate every tool. readOnlyHint and destructiveHint decide when SurfSense asks the user before a call:

    Your tool says SurfSense
    readOnlyHint: true, or destructiveHint: false Asks until the user picks Always allow
    Neither, or destructiveHint: true Asks before every call: MCP assumes a tool that says nothing may destroy
  • Describe tools for a model. Say what the tool does and when to use it, briefly: every description reaches the model on every turn. Text that tells the model what to do, such as "always call this first", is turned away in review.

  • Keep the tool list short. A chat offers the agent at most 24 plugin tools across all of a user's plugins, so a few well-chosen tools beat many narrow ones.

  • Pick how users sign in:

    auth The user Your server receives
    none Does nothing No credentials
    token Pastes a key you give them Authorization: Bearer <key>
    oauth Signs in on your page in their browser Authorization: Bearer <access token>

    OAuth follows MCP's authorization spec: serve protected resource metadata, and accept Client ID Metadata Documents or dynamic client registration. SurfSense signs in as https://plugins.surfsense.com/oauth/client.json and comes back to https://plugins.surfsense.com/oauth/callback. If you only accept clients registered in advance, register SurfSense with those values and put its client id in your entry's auth.client_id. SurfSense never holds a client secret.

  • Have a privacy policy. The user's requests and sign-in reach your server, so the policy must be yours, not your API provider's.

2. Try it in SurfSense first

No listing is needed to try your server:

  1. In the desktop app, open Settings → Plugins and turn on Allow third-party plugins.
  2. Choose Add custom plugin, with a name, your server's URL and, if it needs one, a key. A server that asks for OAuth starts its sign-in on its own.
  3. Open an Agentic chat and ask for something your tools do.

A server added this way is marked Custom, stays on that one computer, and is a good way to polish your tool descriptions before anyone reviews them.

3. Write your entry

Add one object to the plugins array in plugins.json:

{
  "id": "acme-docs",
  "kind": "remote",
  "verification": "community",
  "name": "Acme Docs",
  "description": "Search and read Acme's public documentation.",
  "author": "Acme Inc.",
  "url": "https://mcp.acme.example/mcp",
  "auth": { "type": "none" },
  "hosts": ["mcp.acme.example"],
  "access": "free",
  "privacy_policy": "https://acme.example/privacy",
  "homepage": "https://acme.example",
  "icon": "acme-docs.svg",
  "about": "Search Acme's public documentation and read any page of it in full, so the agent answers from the current docs rather than from memory.",
  "tools": ["search_docs", "read_page"],
  "added": "2026-10"
}

DeepWiki's entry is a real one to compare with.

Field What to put
id Lowercase letters, digits and hyphens, starting with a letter. Unique, and never reused once listed
kind remote
verification community. Only a maintainer sets verified (below)
name, author Up to 80 characters. author is the company or project that runs the server, not a person
description Up to 200 characters: the one line on your card
url Your server's MCP endpoint, https, with no credentials in it
auth {"type": "none"}; {"type": "token", "title": "...", "description": "..."}, the words shown when asking for the key; or {"type": "oauth"}, with an optional client_id and scopes. Never a secret
hosts Every host SurfSense contacts for your plugin: your server's, and for OAuth your authorization server's. The user agrees to each before anything is sent
access free, or external with an access_note (up to 200 characters) saying what the user must buy or have, such as an Acme subscription
privacy_policy Required, https
homepage Optional, https
icon A file you add to icons/: SVG or PNG, square, at most 32 KB, a PNG at least 64×64, an SVG with no scripts, event handlers or outside references. Without one, SurfSense shows your name's first letter
about Up to 600 characters for your plugin's page: what it lets someone do, and when it helps
tools The name of every tool your server lists, as your page shows them before anyone connects
added This month, like 2026-10
min_app_version Optional: the oldest SurfSense version your plugin works with, like 2.3.0

The check lets about, tools and added out, but review asks for all three, since they make your plugin's page.

4. Check it

From check/, with uv installed:

uv sync
uv run python -m registry_check static   # the entry rules and your icon
uv run python -m registry_check live     # connects to your server, as the app would

It prints static check: passed, or one line per problem naming your entry and the field, such as plugins[1] "acme-docs": hosts: must include the url's host, mcp.acme.example. live connects to your server with the app's own MCP client and fails if the app could not use it: unreachable, not MCP over Streamable HTTP, asking for sign-in when auth is none, listing other tools than tools, or, for OAuth, no authorization server, a sign-in host missing from hosts, or no way for SurfSense to register. What MCP leaves optional, such as tool hints, only warns. It never signs in, so a server behind a key or an account is checked up to its sign-in. CI runs both on your pull request.

5. Open the pull request

Fork the repository, branch from dev, and open the pull request into dev. Change only plugins.json and your icon. published/ is written by CI, and a pull request that touches it fails.

Fill in the template's headings, What, Why and How to test, and include:

  • A prompt to try, such as "What do Acme's docs say about rate limits?", and the tools it should call.
  • How a reviewer signs in, if your plugin needs a key or an account. Never put a key or password in the pull request: say that one is needed, and a maintainer will arrange it with you, or reach the maintainers on Discord.
  • Why you should be Verified, if you think you should be: a link from your own docs to the server, for example (below).

A title in Conventional Commits form helps, such as feat(registry): list Acme Docs.

What review looks at

A maintainer reviews your pull request, and once it is merged into dev, connects your plugin, signing in if it needs it, before it reaches a release. They check once:

  • who runs the server, and that author names them;
  • what each tool does, and that its annotations are honest;
  • that no description carries instructions aimed at the model;
  • that hosts is complete, and the privacy policy is real and yours.

Once merged, CI signs the list. It reaches every app that allows third-party plugins with SurfSense's next release from dev to main, with no app update.

Verified or Community

Every plugin starts as Community: the app shows a small badge and, before connecting, reminds the user who runs the server. Verified shows a checkmark instead, and means a maintainer is satisfied that author runs the server.

A maintainer decides it, on whatever convinces them that author runs the server: your own docs linking it, the pull request coming from your company's account, or someone they can ask. Nothing in the entry proves it, and no check decides it, so never set it yourself.

After your plugin is listed

  • Updating your server needs no pull request. Deploy whenever you like. A tool you add, or one whose description changes or whose annotations become less safe, is switched off in every app until the user turns it on, so tell your users when you add or reword something.
  • Changing your entry (name, URL, hosts, sign-in) is another pull request and another review.
  • Removing your plugin moves its entry to removed, as {"id": "acme-docs", "reason": "..."}. Apps stop offering its tools and show the reason; users keep their connection in case it returns. An id is never reused.
  • Reports. Anyone can report a listed plugin that is broken, misleading or unsafe with the Report a plugin form. A maintainer may then remove it, with the reason users see.

Questions

  • Can I charge for my plugin? Yes: bill on your own service, set access: external with an access_note, and sign users in with token or oauth. The SurfSense license is only for SurfSense's own plugins, and your server never sees it.
  • Can my plugin run on the user's computer? Not yet. Local plugins are planned as bundles.
  • Where are SurfSense's own plugins? In ../remote/, run by SurfSense's plugin host and listed in the app itself, not here (plugin host). Only maintainers change the paid ones, in remote/proprietary/.
  • How does the app handle all this? Plugins and the plugin registry describe it in full.

For coding agents

If you are helping someone list a plugin:

  1. Confirm the server is remote, Streamable HTTP, on HTTPS. If it only runs from a command or over SSE, stop and say so; it cannot be listed yet.
  2. Read each tool's name from the server, or ask for them; never invent tools. Check every tool has readOnlyHint or destructiveHint.
  3. Append one entry to plugins in plugins.json, with verification: "community". Never set verified: only a maintainer does.
  4. Put no key, token, password or client secret anywhere: not in the entry, the pull request or a commit message.
  5. Touch only plugins.json and icons/<file>. Never edit published/, check/ or another entry.
  6. Run uv run python -m registry_check static and uv run python -m registry_check live in check/, and fix every problem they print.
  7. Open the pull request into dev with What, Why and How to test, a prompt to try, and whether the reviewer needs sign-in details, without including them.