- A plugin's server.py may expose a lifespan: the host enters it at startup,
warm-ups run in the background, and scraping/lifecycle.py closes the shared
sessions, browsers and API clients once at shutdown.
- One license cache per process, stale-while-revalidate, instead of one per
plugin: the app's 5-minute check no longer pays a Keygen round trip per
plugin. Refusals and the 24 h grace work as before.
- Kept API clients for Keygen, SearXNG and the captcha solver, which now polls
every second.
- mcp_server/results.py: tool_result puts each item in the text as one
compact JSON line, within 32 KB. opencode reads only a result's text when
there is any, so the agent never saw prices, page text or reviews. A request
with x-surfsense-text-only: 1 gets no structured copy.
- mcp_server/progress.py: stage progress, so a long call never sits silent.
- GET and DELETE on /<id>/mcp answer 405: the stateless host has no stream to
offer, and each GET held an idle SSE connection open per plugin.