SurfSense/surfsense_mcp/mcp_server/server.py
CREDO23 116291a3b6 refactor(mcp): flatten to mcp_server package, drop src layout
Rename the import package surfsense_mcp -> mcp_server and remove the
src/ layer so the project mirrors the backend's shape (project folder
!= package name, e.g. surfsense_backend/app). Kills the redundant
surfsense_mcp/src/surfsense_mcp nesting.

Distribution name and console command (surfsense-mcp) are unchanged;
only python -m and internal import paths move to mcp_server. Dockerfile
CMD updated; no PYTHONPATH added since the editable install already
makes the package importable.
2026-07-07 20:24:53 +02:00

49 lines
2 KiB
Python

"""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(
api_base=settings.api_base,
timeout=settings.timeout,
fallback_api_key=settings.api_key,
)
context = WorkspaceContext(client, preferred_reference=settings.default_workspace)
mcp = FastMCP(
"SurfSense",
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,
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."
),
)
workspaces.register(mcp, context)
scrapers.register(mcp, client, context)
knowledge_base.register(mcp, client, context)
return mcp, client