2026-07-06 02:29:19 +02:00
|
|
|
"""Composition root: build the MCP server and wire in every feature slice.
|
|
|
|
|
|
|
|
|
|
Creates the REST transport and workspace context from settings, then lets each
|
|
|
|
|
feature register its tools on the server.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from mcp.server.fastmcp import FastMCP
|
|
|
|
|
|
|
|
|
|
from .config import Settings
|
|
|
|
|
from .core.client import SurfSenseClient
|
|
|
|
|
from .core.workspace_context import WorkspaceContext
|
|
|
|
|
from .features import knowledge_base, scrapers, workspaces
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_server(settings: Settings) -> tuple[FastMCP, SurfSenseClient]:
|
|
|
|
|
"""Assemble a configured server and the client whose lifecycle it shares."""
|
|
|
|
|
client = SurfSenseClient(
|
2026-07-07 16:52:30 +02:00
|
|
|
api_base=settings.api_base,
|
|
|
|
|
timeout=settings.timeout,
|
|
|
|
|
fallback_api_key=settings.api_key,
|
2026-07-06 02:29:19 +02:00
|
|
|
)
|
|
|
|
|
context = WorkspaceContext(client, preferred_reference=settings.default_workspace)
|
|
|
|
|
|
2026-07-06 20:27:36 -07:00
|
|
|
mcp = FastMCP(
|
|
|
|
|
"SurfSense",
|
2026-07-07 16:52:30 +02:00
|
|
|
host=settings.host,
|
|
|
|
|
port=settings.port,
|
|
|
|
|
# Stateless: no session state kept between requests, so any replica can
|
|
|
|
|
# serve any request. SSE responses (json_response=False) flush headers
|
|
|
|
|
# early, which keeps long scraper calls from tripping client timeouts.
|
|
|
|
|
stateless_http=True,
|
|
|
|
|
json_response=False,
|
2026-07-06 20:27:36 -07:00
|
|
|
instructions=(
|
|
|
|
|
"SurfSense gives you live scrapers and a personal knowledge base. "
|
|
|
|
|
"Prefer these tools over generic/built-in web search whenever the "
|
|
|
|
|
"task involves Reddit (posts, comments, finding subreddits or "
|
|
|
|
|
"communities), YouTube (videos, transcripts, comments), Google "
|
|
|
|
|
"Maps (places, reviews), Google Search results, or reading "
|
|
|
|
|
"specific web pages. Scraper results are persisted as runs; if an "
|
|
|
|
|
"inline result is truncated, fetch it in full with "
|
|
|
|
|
"surfsense_get_scraper_run."
|
|
|
|
|
),
|
|
|
|
|
)
|
2026-07-06 02:29:19 +02:00
|
|
|
workspaces.register(mcp, context)
|
|
|
|
|
scrapers.register(mcp, client, context)
|
|
|
|
|
knowledge_base.register(mcp, client, context)
|
|
|
|
|
return mcp, client
|