OpenSEO Architecture Explained: A Full-Stack TypeScript App on Cloudflare Workers
OpenSEO is built as a modern, full‑stack TypeScript application running on Cloudflare Workers, separating the React front‑end, API layer, Durable Object agents, MCP server, and database into modular, maintainable components.
This deep dive breaks down how every‑app/open‑seo structures its codebase, routes requests, and integrates AI agents through the Model Context Protocol (MCP). All file paths and implementation details are drawn directly from the source code.
Front‑End Layer: TanStack React‑Start with Tailwind CSS
The user interface is a server‑side rendered React application built on TanStack React‑Start.
- TanStack React‑Start handles routing and SSR. The generated router tree lives in
src/routeTree.gen.ts, whilesrc/app.tsxserves as the entry point. - TanStack Query manages data fetching and caching.
- Tailwind CSS provides utility‑first styling via
tailwind.config.ts.
Front‑end requests hit the Worker at /api/* routes, which dispatch to server functions in src/serverFunctions/.
Worker Entrypoint: Central Request Dispatch
Every HTTP request flows through src/server.ts, the single Cloudflare Worker script. This file defines:
- The
fetchhandler for incoming requests - Scheduled cron jobs (OAuth KV purge, rank‑check loops, audit reconciliation, telemetry)
- Exports for Durable Object classes (
OnboardingChatAgent,SamChatAgent)
The Worker inspects the request path and routes accordingly:
| Path Prefix | Handler | Purpose |
|---|---|---|
/agents/* |
routeChatAgents |
Real‑time AI chat agents |
/mcp |
MCP transport | Machine‑readable API for AI agents |
/autumn-webhook |
handleAutumnWebhookRequest |
Billing events |
/api/* or other |
appFetch (TanStack router) |
Standard API and UI routes |
API Layer: Server Functions and Feature Modules
Business logic is organized by feature under src/serverFunctions/. Each module exports functions that the Worker imports and exposes as API endpoints:
src/serverFunctions/dashboard.ts– Dashboard data aggregationsrc/serverFunctions/rank-tracking.ts– Rank monitoring operationssrc/serverFunctions/seo.ts– Core SEO analysis functionssrc/serverFunctions/projects.ts– Project CRUD operations
These functions rely on repository classes (e.g., ProjectRepository in src/server/features/projects/repositories/ProjectRepository.ts) for database access.
Durable Object Agents: Real‑Time AI Chat
OpenSEO deploys stateful chat agents using Cloudflare Durable Objects and the Agents SDK:
OnboardingChatAgent(src/server/features/onboarding/OnboardingChatAgent.ts) – Guides new users through setupSamChatAgent– General SEO assistant
Agent routes are protected by authorizeChatAgent middleware. These objects maintain websocket connections and conversation state across requests.
MCP Server: AI Agent Integration
The Model Context Protocol (MCP) exposes a structured API that external AI agents (Claude, OpenClaw, Hermes) can call to retrieve SEO data and trigger workflows.
Implementation lives in src/server/mcp/:
transport.ts– Handles inbound MCP requests, authorization, and routing to server functionspublic-origin.ts– Origin validation for public MCP endpoints
The Worker injects the MCP pipeline when env.AUTH_MODE is hosted. For self‑hosted deployments, handleSelfHostedOpenSeoMcpRequest manages MCP access without OAuth.
Authentication: Hosted vs. Self‑Hosted
OpenSEO supports two deployment modes, determined by src/lib/auth-mode.ts:
| Mode | Auth Method | Use Case |
|---|---|---|
| Hosted | Cloudflare Access + OAuth KV store | Managed openseo.so deployments |
| Self‑hosted | No authentication | Local development or private infrastructure |
Middleware in src/middleware/ensure-user/resolve.ts enforces the appropriate guard based on getAuthMode().
Database Layer: Drizzle ORM with D1 and Postgres
Data persistence uses Drizzle ORM with dual backend support:
- Cloudflare D1 (SQLite) – Default for hosted deployments
- Postgres – Optional for self‑hosted or high‑volume scenarios
Key files:
src/db/schema.ts– Shared table definitionssrc/db/pg/*– Postgres‑specific extensionswithPgClienthelper – Supplies per‑request Postgres clients (noop for D1)
Scheduled Jobs and Background Work
The Worker's scheduled method (lines 90‑140 of src/server.ts) triggers:
- Daily OAuth KV purge – Removes expired tokens
- Rank‑check loop – Executes
RankCheckWorkflowfor active projects - Stale‑audit reconciliation – Cleans abandoned audit sessions
- Self‑host telemetry – Anonymous usage metrics
Billing and Compliance
src/server/billing/autumn-webhook.ts– Processes subscription events from Autumnsrc/gdpr/storage-erasure.ts– Handles GDPR Article 17 data deletion requests
Code Examples: Working with OpenSEO
Fetching Data from the Front‑End
import { createQuery } from '@tanstack/react-query';
import { fetch } from '@/lib/fetch';
export const useProjects = () =>
createQuery(['projects'], async () => {
const resp = await fetch('/api/projects');
if (!resp.ok) throw new Error('Failed to load projects');
return resp.json();
});
This TanStack Query hook calls /api/projects, routed by the Worker to src/serverFunctions/projects.ts.
Calling OpenSEO from an AI Agent via MCP
import { createMcpClient } from '@modelcontextprotocol/client';
const client = createMcpClient({ baseUrl: 'https://openseo.so/mcp' });
async function getKeywordIdeas(domain: string) {
const result = await client.call({
service: 'keywordResearch',
method: 'generateIdeas',
params: { domain },
});
return result.ideas;
}
The MCP transport in src/server/mcp/transport.ts validates the request and forwards it to the appropriate server function.
Triggering a Rank Check Programmatically
import { RankCheckWorkflow } from '@/server/workflows/RankCheckWorkflow';
async function runRankCheck(projectId: string) {
const workflow = new RankCheckWorkflow({ projectId });
await workflow.start();
}
RankCheckWorkflow (src/server/workflows/RankCheckWorkflow.ts) orchestrates external API calls and database updates. The same class is invoked by the nightly cron job.
Summary
- OpenSEO runs as a single Cloudflare Worker (
src/server.ts) that routes requests to React‑Start, API functions, Durable Objects, or MCP handlers. - The front‑end uses TanStack React‑Start with TanStack Query and Tailwind CSS.
- Server functions in
src/serverFunctions/*encapsulate business logic and use Drizzle repositories for database access. - Durable Object agents (
OnboardingChatAgent,SamChatAgent) enable stateful, real‑time AI conversations. - The MCP server (
src/server/mcp/) exposes machine‑readable endpoints for external AI agents. - Dual auth modes (hosted/self‑hosted) and dual database backends (D1/Postgres) provide deployment flexibility.
- Scheduled jobs handle background work like rank tracking and data cleanup.
Frequently Asked Questions
What framework does OpenSEO use for the front‑end?
OpenSEO uses TanStack React‑Start for server‑side rendering, file‑based routing, and API endpoints. TanStack Query handles client‑side data fetching, and Tailwind CSS provides styling. The entry point is src/app.tsx, with generated routes in src/routeTree.gen.ts.
How does OpenSEO handle authentication?
Authentication depends on the deployment mode. Hosted deployments use Cloudflare Access with an OAuth KV store for session management. Self‑hosted deployments run without authentication. The mode is determined at runtime via src/lib/auth-mode.ts and enforced by middleware in src/middleware/ensure-user/resolve.ts.
What is the MCP server in OpenSEO?
The Model Context Protocol (MCP) server exposes a structured API at /mcp that AI agents can call to access SEO data and trigger workflows. It is implemented in src/server/mcp/transport.ts and supports both hosted (OAuth‑protected) and self‑hosted (unauthenticated) modes. Agents like Claude use this to perform keyword research, run audits, and retrieve rankings programmatically.
Can OpenSEO run without Cloudflare D1?
Yes. OpenSEO supports Postgres as an alternative database backend via the withPgClient helper. The Drizzle ORM schema in src/db/schema.ts works with both D1 (SQLite) and Postgres implementations. Postgres‑specific code lives in src/db/pg/*.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →