From 5e358f187356916e1693ba78576dd767421dede5 Mon Sep 17 00:00:00 2001 From: Ben Senescu <44480372+bensenescu@users.noreply.github.com> Date: Sun, 10 May 2026 17:23:37 -0400 Subject: [PATCH] Add an MCP landing page and update footer navigation (#176) * Fix open-seo MCP auth discovery * Refine MCP marketing page route and copy --- web/src/components/site-footer.tsx | 58 +-- web/src/routeTree.gen.ts | 21 ++ web/src/routes/_marketing/features/mcp.tsx | 396 +++++++++++++++++++++ 3 files changed, 453 insertions(+), 22 deletions(-) create mode 100644 web/src/routes/_marketing/features/mcp.tsx diff --git a/web/src/components/site-footer.tsx b/web/src/components/site-footer.tsx index fed0f69..6fd0ddd 100644 --- a/web/src/components/site-footer.tsx +++ b/web/src/components/site-footer.tsx @@ -3,28 +3,42 @@ import { Link } from "@tanstack/react-router"; export function SiteFooter({ className }: { className?: string }) { return (
-
- - OpenSEO - - Guides - - GitHub - - - Discord - - Pricing - Privacy - Terms +
+
+

Product

+
+ OpenSEO + MCP + Pricing + Guides +
+
+
+

Community

+
+ + GitHub + + + Discord + +
+
+
+

Legal

+
+ Privacy + Terms +
+
); diff --git a/web/src/routeTree.gen.ts b/web/src/routeTree.gen.ts index b51e8ab..96e578f 100644 --- a/web/src/routeTree.gen.ts +++ b/web/src/routeTree.gen.ts @@ -19,6 +19,7 @@ import { Route as GuidesSplatRouteImport } from './routes/guides/$' import { Route as ApiSubscribeRouteImport } from './routes/api/subscribe' import { Route as ApiEventRouteImport } from './routes/api/event' import { Route as MarketingPricingRouteImport } from './routes/_marketing/pricing' +import { Route as MarketingFeaturesMcpRouteImport } from './routes/_marketing/features/mcp' const TermsAndConditionsRoute = TermsAndConditionsRouteImport.update({ id: '/terms-and-conditions', @@ -69,6 +70,11 @@ const MarketingPricingRoute = MarketingPricingRouteImport.update({ path: '/pricing', getParentRoute: () => MarketingRoute, } as any) +const MarketingFeaturesMcpRoute = MarketingFeaturesMcpRouteImport.update({ + id: '/features/mcp', + path: '/features/mcp', + getParentRoute: () => MarketingRoute, +} as any) export interface FileRoutesByFullPath { '/': typeof MarketingIndexRoute @@ -80,6 +86,7 @@ export interface FileRoutesByFullPath { '/guides/$': typeof GuidesSplatRoute '/js/script.js': typeof JsScriptDotjsRoute '/guides/': typeof GuidesIndexRoute + '/features/mcp': typeof MarketingFeaturesMcpRoute } export interface FileRoutesByTo { '/privacy': typeof PrivacyRoute @@ -91,6 +98,7 @@ export interface FileRoutesByTo { '/js/script.js': typeof JsScriptDotjsRoute '/': typeof MarketingIndexRoute '/guides': typeof GuidesIndexRoute + '/features/mcp': typeof MarketingFeaturesMcpRoute } export interface FileRoutesById { __root__: typeof rootRouteImport @@ -104,6 +112,7 @@ export interface FileRoutesById { '/js/script.js': typeof JsScriptDotjsRoute '/_marketing/': typeof MarketingIndexRoute '/guides/': typeof GuidesIndexRoute + '/_marketing/features/mcp': typeof MarketingFeaturesMcpRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath @@ -117,6 +126,7 @@ export interface FileRouteTypes { | '/guides/$' | '/js/script.js' | '/guides/' + | '/features/mcp' fileRoutesByTo: FileRoutesByTo to: | '/privacy' @@ -128,6 +138,7 @@ export interface FileRouteTypes { | '/js/script.js' | '/' | '/guides' + | '/features/mcp' id: | '__root__' | '/_marketing' @@ -140,6 +151,7 @@ export interface FileRouteTypes { | '/js/script.js' | '/_marketing/' | '/guides/' + | '/_marketing/features/mcp' fileRoutesById: FileRoutesById } export interface RootRouteChildren { @@ -225,17 +237,26 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof MarketingPricingRouteImport parentRoute: typeof MarketingRoute } + '/_marketing/features/mcp': { + id: '/_marketing/features/mcp' + path: '/features/mcp' + fullPath: '/features/mcp' + preLoaderRoute: typeof MarketingFeaturesMcpRouteImport + parentRoute: typeof MarketingRoute + } } } interface MarketingRouteChildren { MarketingPricingRoute: typeof MarketingPricingRoute MarketingIndexRoute: typeof MarketingIndexRoute + MarketingFeaturesMcpRoute: typeof MarketingFeaturesMcpRoute } const MarketingRouteChildren: MarketingRouteChildren = { MarketingPricingRoute: MarketingPricingRoute, MarketingIndexRoute: MarketingIndexRoute, + MarketingFeaturesMcpRoute: MarketingFeaturesMcpRoute, } const MarketingRouteWithChildren = MarketingRoute._addFileChildren( diff --git a/web/src/routes/_marketing/features/mcp.tsx b/web/src/routes/_marketing/features/mcp.tsx new file mode 100644 index 0000000..4dfd250 --- /dev/null +++ b/web/src/routes/_marketing/features/mcp.tsx @@ -0,0 +1,396 @@ +import { createFileRoute } from "@tanstack/react-router"; +import type { ReactNode, SVGProps } from "react"; +import { useState } from "react"; +import { buildPageSeo } from "@/lib/seo"; + +const mcpDescription = + "Connect OpenSEO MCP to your AI agent so it can research keywords, SERPs, domains, backlinks, and rank tracking data."; + +const toolCategories = [ + { + label: "Keywords", + tools: [ + { + title: "Research keywords", + description: "Get keyword ideas with volume, difficulty, and CPC.", + }, + { + title: "Get SERP results", + description: "See live Google results for a keyword.", + }, + { + title: "Get rank tracking positions", + description: "Read tracked keyword positions.", + }, + { + title: "Get saved keywords", + description: "Pull your saved keyword lists.", + }, + { + title: "Save keywords", + description: "Save keywords back to OpenSEO.", + }, + ], + }, + { + label: "Domain", + tools: [ + { + title: "Get domain overview", + description: "Summarize a domain's organic footprint.", + }, + { + title: "Get domain keywords", + description: "Find keywords a domain already ranks for.", + }, + { + title: "Get backlinks overview", + description: "Check backlink and referring-domain stats.", + }, + ], + }, +] as const; + +export const Route = createFileRoute("/_marketing/features/mcp")({ + head: () => + buildPageSeo({ + title: "OpenSEO MCP", + description: mcpDescription, + path: "/features/mcp", + titleSuffix: "OpenSEO", + }), + component: McpPage, +}); + +function McpPage() { + return ( + <> +

OpenSEO MCP

+

+ OpenSEO MCP for your AI agent +

+

+ Connect OpenSEO to your AI agent so that it can research keywords, + SERPs, domains, backlinks, and rank tracking data for you. +

+ + + Skip to setup + + + +
+

What it does

+

+ MCP lets your AI do the most tedious parts of your job faster. Connect + OpenSEO once, then ask your agent to research keywords, inspect search + results, compare domains, and save useful ideas back to your + workspace. +

+
+ +
+

Available tools

+
+ {toolCategories.map((category) => ( +
+

+ {category.label} +

+
    + {category.tools.map((tool) => ( +
  • + + {tool.title} + +

    + {tool.description} +

    +
  • + ))} +
+
+ ))} +
+
+ +
+

Set up OpenSEO MCP

+

+ The first connection sends you through OpenSEO login. After + authorization, your AI client can call OpenSEO tools using your + workspace permissions. The MCP server URL is{" "} + https://app.openseo.so/mcp. For the most current setup UI + and a copyable endpoint, open{" "} + + AI & MCP in OpenSEO + + . +

+ +
+

+ Don't see your agent or AI app? +

+

+ Copy the link to this page into your AI tool and ask it how to + configure OpenSEO MCP for your tool of choice. +

+
+ +

+ Follow the setup steps for ChatGPT, Claude, Claude Code, Codex, or any + MCP-compatible AI tool. +

+ +
+ } + > +
    +
  1. + Open ChatGPT settings, then go to{" "} + Apps. +
  2. +
  3. + If you do not see the custom app form, open{" "} + + Advanced settings + {" "} + and turn on developer mode. +
  4. +
  5. + Return to Apps and click{" "} + Create app + . +
  6. +
  7. + Name the app OpenSEO. +
  8. +
  9. + Paste the OpenSEO MCP server URL into{" "} + + MCP Server URL + + . +
  10. +
  11. + Keep authentication set to{" "} + OAuth. +
  12. +
  13. + Review the custom MCP server warning, check{" "} + + I understand and want to continue + + , then click Create. +
  14. +
  15. + Approve the OpenSEO login when ChatGPT asks you to sign in. +
  16. +
+ +
+ + } + > +

+ Use user scope if you want OpenSEO available across projects, or + local scope for the current repository. +

+ +
+ + } + > +
    +
  1. Open Settings -> Connectors.
  2. +
  3. Click Add custom connector.
  4. +
  5. + Paste https://app.openseo.so/mcp. +
  6. +
  7. Approve the OpenSEO login when prompted.
  8. +
+

+ Requires a Claude plan that supports custom connectors. +

+
+ + } + > +

+ Add OpenSEO as a hosted MCP server, then run the OAuth login flow. +

+ +
+ + } + > +
    +
  1. Open Settings -> Integrations & MCP.
  2. +
  3. Click Add your own.
  4. +
  5. + Paste https://app.openseo.so/mcp. +
  6. +
  7. Approve the OpenSEO login when prompted.
  8. +
+
+
+
+ + ); +} + +function SetupOption({ + id, + title, + subtitle, + icon, + children, +}: { + id: string; + title: string; + subtitle: string; + icon?: ReactNode; + children: ReactNode; +}) { + const [open, setOpen] = useState(false); + const contentId = `setup-${id}`; + + return ( +
+ + {open ? ( +
+ {children} +
+ ) : null} +
+ ); +} + +function CodeBlock({ code }: { code: string }) { + return ( +
+      {code}
+    
+ ); +} + +function ClaudeIcon(props: SVGProps) { + return ( + + ); +} + +function CodexIcon(props: SVGProps) { + return ( + + ); +} + +function OpenAIIcon(props: SVGProps) { + return ( + + ); +}