SurfSense/surfsense_local/backend/modules/plugins/installed/replace_headers.py
Anish Sarkar 762bb05887 feat(local): connect any remote MCP server with one Connect
Add custom plugin is one screen: name, URL and Connect, with the key, how it
is sent, more headers and the user's own OAuth app under Advanced settings,
opened by a refusal they fix. The same fields edit a connected plugin.

- Every connect path names a failure from its HTTP status: needs a key or a
  sign-in, not an MCP server, or out of reach.
- Servers on the older SSE transport connect, and a check finds a server
  that moved transports.
- OAuth registers as a public client, then as a confidential one, and tells
  a provider that registers no one from one that refused SurfSense.
- An OAuth plugin is kept once its sign-in page opens, needing a sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:30:43 +05:30

27 lines
1 KiB
Python

"""A connected plugin's headers, replaced in place so the user's choices per tool stay."""
from sqlalchemy.orm import Session
from modules.plugins.gateway.source_tool import SourceTool
from modules.plugins.installed.models import InstalledPlugin, PluginSource
from modules.plugins.installed.plugin_check import record_check
from modules.plugins.remote.sign_in.headers.header_rules import SignInHeader
from modules.plugins.remote.sign_in.headers.headers_credential import (
headers_auth,
write_headers,
)
def replace_headers(
session: Session,
plugin: InstalledPlugin,
headers: list[SignInHeader],
tools: list[SourceTool],
) -> None:
"""Only headers the server just accepted are saved, with what it listed as the check."""
write_headers(plugin, headers)
plugin.disconnected_at = None
# A registry plugin keeps its reviewed entry, which names and words its headers.
if plugin.source != PluginSource.REGISTRY:
plugin.entry = {**plugin.entry, "auth": headers_auth(headers)}
record_check(session, plugin, tools)