Platform rewrite
Surnex moved from four separate services to a single TypeScript monorepo. The old Python API, Celery worker, and Node email service are replaced; the dashboard moved in largely intact.
A new job system
Celery and Redis-backed scheduling are gone. Jobs now run on pgmq with pg_cron driving a single scheduler that replaces five per-type scanners plus a report scanner.Schedules became real database rows with a realinterval cadence. Three things follow:- Timezones are honoured. A check set to 09:00 in
America/New_Yorkruns at 09:00 New York time. Previously the hour was applied as UTC regardless. - Cadences mean what they say. “Every 3 days” is three days from the last run, not the 1st, 4th and 7th of the month. “Weekly” is seven days later, not Mondays.
- Cadences below a day are now expressible — 12 hours, 90 minutes — without new code.
MCP is OAuth only
The MCP server no longer accepts API keys. Surnex is now an OAuth 2.1 resource server, with Supabase as the authorization server —/authorize, /token, and client registration all belong to it.A token identifies a person, so an agent inherits your role, reaches every organization you belong to, and can be revoked from your account. An API key is a bearer secret that lives in a config file indefinitely and belongs to nobody in particular; given the tools can create projects, start billable crawls and delete data, that difference matters.A consent screen was built to go with it — Supabase redirects to Surnex to render the approval, and without that page the connect flow dead-ends on a 404.The MCP server itself
All 88 tools at/mcp, each carrying MCP annotations — read-only, destructive, idempotent — so a client can confirm selectively rather than on every call.Organization resolution no longer guesses. Tools take an optional organization argument; a caller belonging to several who names none gets a refusal listing them. Previously an unnamed organization resolved to the user’s first membership from an unordered query, which meant lookups were billed to whichever row came back first.API
Rebuilt end to end: projects, rank tracking with alerts and competitors, keyword research and live SERP, backlinks, audits, domain overview, web vitals, GEO visibility, AI search, local SEO, notifications, reports with sharing and scheduled delivery, users, organizations, members, API keys, and job status.A parity sweep diffed everyapi.*() call in the dashboard against the served OpenAPI document. It caught four method mismatches, a notifications contract that was backwards, three endpoints that didn’t exist, and five missing AI-search routes — each of which would have looked correct in review and 404’d at runtime.Four further bugs surfaced only once live provider calls ran against it.Dashboard
The shell was replaced wholesale rather than restyled. Overlays moved onto one Radix dialog shell, the dashboard got a single z-index scale, and settings pages — API keys, team, project settings — moved onto shared chrome.Smaller fixes: the theme no longer flashes on load, the sidebar is readable, toasts moved out of the way, missing form primitives were added, and switching organization now clears the current project.Efficiency
Search results are now bought once per keyword and reused, rather than re-fetched per consumer.Known issues
Behaviour that reads as a defect, current as of this release:- Project creation drops most of its form. The create form collects keywords, competitors, location, language and search engine; the API accepts only name, domain and schedules. The rest is silently discarded. Add keywords and competitors from their own pages afterwards.
- The Domain field in Project settings doesn’t save. Only the project name is submitted, and the API has no way to change a domain either — it’s fixed for the project’s life.
- Editing a tracked keyword saves location and language only. The keyword text and search engine fields are editable but discarded.
- Admins can’t change billing, despite the invite panel describing them as having full access including billing. Only the owner can.
- Saved keywords have no promote-to-tracking action. Saving and tracking are separate.