Skip to main content
Glama
mehere14

SEO Thermostat MCP

by mehere14
README.md
# SEO Thermostat MCP

SEO Thermostat is a local-first Model Context Protocol (MCP) project for improving existing SEO pages with evidence from search performance, analytics, product usage, and page content.

The goal is to help answer questions like:

- Which pages have search demand but weak click-through rate?
- Which pages rank for intents the content does not clearly satisfy?
- Which pages are decaying over time?
- Which traffic pages fail to create useful product or business outcomes?
- Which low-visibility pages deserve more investment because they convert or activate well?

The project is designed for public GitHub distribution. Users bring their own credentials, local SQLite database, analytics data, and content folders.

## Table of Contents

- [Current Status](#current-status)
- [Using the MCP: Example Questions](#using-the-mcp-example-questions)
  - [Discovery & Overview](#discovery--overview)
  - [Page Analysis](#page-analysis)
  - [Data Refresh & Status](#data-refresh--status)
  - [Available Tools](#available-tools)
  - [Available Resources](#available-resources)
- [Setup](#setup)
- [Configuration](#configuration)
  - [Google Search Console](#google-search-console)
  - [Google Analytics 4](#google-analytics-4)
  - [PostHog](#posthog)
  - [Credential References](#credential-references)
- [CLI Examples](#cli-examples)
- [Local MCP Client Configuration](#local-mcp-client-configuration)
- [Optional Nightly Scheduling](#optional-nightly-scheduling)
- [Public Repository Guidance](#public-repository-guidance)
- [Project References](#project-references)

## Current Status

This repository is in an alpha implementation stage.

Currently present:

- Technical specification in `docs/SEO_THERMOSTAT_SPEC.md`
- Canonical task checklist in `docs/TASKS.md`
- Python package under `src/seo_thermostat/`
- `seo-thermostat` console script
- SQLite initialization and idempotent fact-table upserts
- Content manifest indexing and import for Markdown, MDX, and HTML
- Mock-friendly GSC, GA4, and PostHog connectors
- CTR baselines, scoring, flags, recommendations, and nightly builds
- Local stdio MCP server backed by SQLite analysis data
- Public-safe `.env.example`
- Public-safe `.gitignore`
- Pytest coverage and public-safe sample fixture content

Use `docs/TASKS.md` as the source of truth for what is done versus planned.

## Using the MCP: Example Questions

The SEO Thermostat MCP supports natural-language queries about your site's SEO performance. Here are the kinds of questions you can ask:

### Discovery & Overview

- "What pages have the most search impressions but low click-through rates?"
- "Show me all flagged pages that need attention."
- "Which pages rank for search queries but don't clearly satisfy user intent?"
- "List all pages in the blog directory with performance metrics."
- "Find pages with the highest priority for improvement."
- "What are the top SEO opportunities across my site?"

### Page Analysis

- "What is the health status of the /pricing page?"
- "Show me specific improvements and recommendations for /about-us."
- "Which queries does the /features page rank for, and where is it underperforming?"
- "What content gaps exist that we should address?"
- "Where can I find quick wins to improve CTR for a specific page?"

### Data Refresh & Status

- "Refresh the analysis with the latest search console data."
- "Run an analysis build for a specific date."
- "Show me the status of recent analysis builds."
- "Update the dataset and show me what changed."

### Available Tools

The MCP provides these core tools for querying your SEO data:

- **discover_urls** — Find pages by search term, URL pattern, or flag status. Includes metrics like impressions, sessions, and recommendations.
- **get_page_health** — Get comprehensive health data for a specific page including scores, flags, metrics, and recommendations.
- **list_flagged_pages** — See all pages with open flags that need attention, filterable by flag type.
- **analyze_page_improvements** — Get detailed improvement recommendations for a specific URL.
- **find_content_gaps** — Identify pages with content gap flags and related recommendations.
- **list_seo_opportunities** — View prioritized SEO opportunities ranked by impact potential.
- **get_query_opportunities** — See query-level performance data for a specific page with CTR gap analysis.
- **get_analysis_build_status** — Check the latest analysis build results and recent build history.
- **refresh_analysis_dataset** — Fetch fresh data from Google Search Console, GA4, and PostHog, then recompute analysis.

### Available Resources

Quick-access data resources for snapshot views:

- **seo://latest/summary** — Overall SEO Thermostat analysis summary for the latest date.
- **seo://latest/pages** — All discovered pages with current metrics and flag counts.
- **seo://latest/flagged-pages** — All pages with open flags for the latest analysis date.
- **seo://latest/opportunities** — Prioritized SEO opportunities ranked by impact.
- **seo://pages/{url}/health** — Health snapshot for any specific page URL.
- **seo://pages/{url}/recommendations** — Improvement recommendations for any page URL.

## Setup

Requirements:

- Python 3.10 or newer
- `pip`
- Optional but recommended: a virtual environment

Create and activate a virtual environment:

```bash
python -m venv .venv
source .venv/bin/activate
```

Install the package in editable mode with development test dependencies and
local OAuth setup helpers:

```bash
python -m pip install -e ".[dev,auth]"
```

Run the test suite:

```bash
python -m pytest
```

The package declares a console script named `seo-thermostat`.

## Configuration

Start from the example environment file:

```bash
cp .env.example .env
```

Then edit `.env` locally with your own values.

Important configuration groups in `.env.example`:

- `SEO_THERMOSTAT_DB_PATH`: local SQLite database path.
- `SEO_THERMOSTAT_CONTENT_ROOT`: local content folder to index.
- `SEO_THERMOSTAT_CONTENT_MANIFEST`: generated content manifest path.
- `GSC_*`: Google Search Console read-only OAuth settings.
- `GA4_*`: Google Analytics 4 property and credential settings.
- `POSTHOG_*`: PostHog host, project, API key, and event settings.
- `SEO_THERMOSTAT_MCP_TRANSPORT`: MCP transport setting, currently `stdio`.
- `SEO_THERMOSTAT_SETTLED_DATA_OFFSET_DAYS`: default settled-data lag for nightly analysis.

Do not commit your real `.env`, OAuth client files, API keys, tokens, service-account JSON, private database files, generated manifests, or local MCP client configuration.

## Credential Setup

Keep all credentials in `.env`, `./secrets/`, `./.secrets/`, or another ignored local path. The repository should contain placeholders only.

### Google Search Console

Use OAuth for Search Console. The connector can use a short-lived bearer token,
but for normal use you should give it a refresh token so it can mint fresh access
tokens before API calls.

1. Open the [Google Cloud Console](https://console.cloud.google.com/) and create or select a project.
2. Go to **APIs & Services > Library**, enable the **Google Search Console API**.
3. Go to **APIs & Services > OAuth consent screen**.
4. Choose **Internal** if you are on a Google Workspace account and only internal users need access; otherwise choose **External**.
5. Fill in the app name and support email. If the app is in testing mode, add your Google account as a test user.
6. Go to **APIs & Services > Credentials > Create credentials > OAuth client ID**.
7. Choose **Desktop app** as the application type.
8. Download the OAuth client JSON and save it locally:

```bash
mkdir -p secrets
mv ~/Downloads/client_secret_*.json ./secrets/google-oauth-client.json
```

9. Set these values in `.env`:

```bash
GSC_SITE_URL=https://example.com/
GSC_OAUTH_CLIENT_SECRETS_PATH=./secrets/google-oauth-client.json
GSC_OAUTH_TOKEN_PATH=./secrets/gsc-token.json
```

Use the exact `GSC_SITE_URL` shown by Search Console, such as
`https://example.com/` for a URL-prefix property or `sc-domain:example.com` for
a domain property.

10. Create the refresh token with the local Desktop OAuth flow:

```bash
python scripts/generate_gsc_token.py
```

The script reads `GSC_OAUTH_CLIENT_SECRETS_PATH` and `GSC_OAUTH_TOKEN_PATH` from
`.env`, opens a browser consent flow, and writes the refresh token JSON locally.

11. Smoke-test access:

```bash
seo-thermostat gsc list-sites
```

If you prefer the OAuth 2.0 Playground, create a **Web application** OAuth
client instead and add `https://developers.google.com/oauthplayground` as an
authorized redirect URI. The Playground route is not compatible with a Desktop
OAuth client.

### Google Analytics 4

For unattended nightly builds, prefer a service account. OAuth refresh tokens
also work, but service accounts are easier to operate on a schedule.

#### GA4 Option A: Service Account

1. Open the [Google Cloud Console](https://console.cloud.google.com/) and create or select a project.
2. Go to **APIs & Services > Library**, enable the **Google Analytics Data API**.
3. Go to **IAM & Admin > Service Accounts > Create service account**.
4. Give it a clear name such as `seo-thermostat-ga4-reader`.
5. After the service account is created, open it and go to **Keys > Add key > Create new key**.
6. Choose **JSON**, download the key, and save it locally:

```bash
mkdir -p secrets
mv ~/Downloads/*.json ./secrets/ga4-service-account.json
```

7. Copy the service account email from the JSON file or from Google Cloud. It looks like `name@project-id.iam.gserviceaccount.com`.
8. Open [Google Analytics](https://analytics.google.com/), select the GA4 property, and go to **Admin > Property access management**.
9. Add the service account email with **Viewer** or **Analyst** access.
10. Find the numeric GA4 property id in **Admin > Property details**.
11. Set these values in `.env`:

```bash
GA4_PROPERTY_ID=123456789
GA4_CREDENTIALS_PATH=./secrets/ga4-service-account.json
GA4_CONVERSION_EVENTS=signup,trial_started,purchase
```

The connector reads `GA4_CREDENTIALS_PATH` and refreshes a readonly GA4 access
token with `google-auth`.

Smoke-test GA4 access after setting `.env`:

```bash
seo-thermostat ga4 smoke-test
```

The smoke test runs a tiny GA4 Data API report for the last 7 days and prints
how many rows were returned. It does not write to the local database.

#### GA4 Option B: OAuth Refresh Token

Use this when you cannot grant a service account access to the GA4 property.

1. Enable the **Google Analytics Data API** in Google Cloud.
2. Create a **Desktop app** OAuth client under **APIs & Services > Credentials**.
3. Save the OAuth client JSON locally:

```bash
mkdir -p secrets
mv ~/Downloads/client_secret_*.json ./secrets/google-oauth-client.json
```

4. Use the [OAuth 2.0 Playground](https://developers.google.com/oauthplayground/) with your own OAuth credentials.
5. Authorize this scope:

```text
https://www.googleapis.com/auth/analytics.readonly
```

6. Exchange the authorization code for tokens and copy the `refresh_token`.
7. Save the token locally:

```json
{
  "refresh_token": "REFRESH_TOKEN_PLACEHOLDER"
}
```

Save that JSON as `./secrets/ga4-token.json`.

8. Set these values in `.env`:

```bash
GA4_PROPERTY_ID=123456789
GA4_OAUTH_CLIENT_SECRETS_PATH=./secrets/google-oauth-client.json
GA4_OAUTH_TOKEN_PATH=./secrets/ga4-token.json
GA4_CONVERSION_EVENTS=signup,trial_started,purchase
```

`GA4_ACCESS_TOKEN` is supported for short local smoke tests, but raw Google
access tokens expire quickly and are not enough for unattended scheduling.

### PostHog

PostHog uses a project id, host URL, and a personal API key. Do not use the
public project token for `POSTHOG_API_KEY`; project tokens are for client-side
event capture and cannot query private analytics data.

1. Open your PostHog workspace.
2. Confirm the host:
   - US Cloud is usually `https://us.posthog.com` or `https://app.posthog.com`.
   - EU Cloud is usually `https://eu.posthog.com`.
   - Self-hosted deployments use your own base URL.
3. Open the project settings and copy the numeric project id.
4. Open your personal settings or account settings and create a personal API key
   with permission to read/query events. HogQL query endpoints require this
   private API key.
5. Decide which events represent product outcomes:
   - Activation events: examples include `onboarding_completed`, `project_created`.
   - Interaction events: examples include `cta_clicked`, `tool_used`.
6. Set these values in `.env`:

```bash
POSTHOG_HOST=https://us.posthog.com
POSTHOG_PROJECT_ID=12345
POSTHOG_API_KEY=POSTHOG_API_KEY_PLACEHOLDER
POSTHOG_ACTIVATION_EVENTS=onboarding_completed,project_created
POSTHOG_INTERACTION_EVENTS=cta_clicked,tool_used
```

Smoke-test PostHog access after setting `.env`:

```bash
seo-thermostat posthog smoke-test
```

The smoke test runs a small HogQL query for the configured activation and
interaction events over the last 7 days and prints how many grouped rows were
returned. It does not write to the local database.

### Credential References

- Search Console authorization: <https://developers.google.com/webmaster-tools/v1/how-tos/authorizing>
- GA4 Data API quickstart: <https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart-client-libraries>
- OAuth 2.0 Playground: <https://developers.google.com/oauthplayground/>
- PostHog API docs: <https://posthog.com/docs/api>

## CLI Examples

Common local commands:

```bash
seo-thermostat --help
seo-thermostat init-db --db ./seo_thermostat.db
seo-thermostat index-content --root ./content --out ./content_manifest.json
seo-thermostat import-content --manifest ./content_manifest.json --db ./seo_thermostat.db
seo-thermostat gsc list-sites
seo-thermostat ga4 smoke-test
seo-thermostat posthog smoke-test
seo-thermostat refresh-live
seo-thermostat compute-ctr-baseline --db ./seo_thermostat.db
seo-thermostat build-nightly --db ./seo_thermostat.db
seo-thermostat mcp --db ./seo_thermostat.db
```

## Local MCP Client Configuration

The MCP server is a local stdio server intended for clients such as Codex, Claude, and other MCP-compatible tools.

Local client configuration should point to the installed command and the private local database path, for example:

```json
{
  "command": "seo-thermostat",
  "args": ["mcp", "--db", "./seo_thermostat.db"]
}
```

If your MCP client requires a named server entry, use:

```json
{
  "mcpServers": {
    "seo-thermostat": {
      "command": "seo-thermostat",
      "args": ["mcp", "--db", "./seo_thermostat.db"],
      "cwd": "/path/to/seo-thermostat"
    }
  }
}
```

Keep client config private. The repository ignores common local MCP files such as `.mcp/`, `.mcp.json`, `mcp.json`, and `claude_desktop_config.json`.

MCP protocol JSON should go to stdout, and logs should go to stderr so clients can parse responses reliably.

After credentials and local paths are set in `.env`, the MCP client can ask the
server to create the working dataset directly. The `refresh_analysis_dataset`
tool indexes `SEO_THERMOSTAT_CONTENT_ROOT` when configured, pulls live GSC, GA4,
and PostHog rows into SQLite, then runs the analysis build. For example, in an
LLM client you can ask: "Refresh the SEO dataset for the latest settled date,
then show the highest-priority opportunities."

The same tool accepts an explicit date, exact date range, or `backfill_days`.
Use `sources` to limit refresh work, such as `["gsc", "ga4"]`, and use
`continue_on_source_error` only when a partial dataset is acceptable.

## Optional Nightly Scheduling

`seo-thermostat build-nightly` defaults to settled analytics data from `T-3`. Use `--date YYYY-MM-DD` for a deterministic backfill or `--settled-offset-days N` to change the lag.

To run the nightly workflow immediately instead of waiting for a scheduler, refresh
live data for the settled date and then build the analysis:

```bash
seo-thermostat refresh-live
seo-thermostat build-nightly
```

For an explicit date:

```bash
seo-thermostat refresh-live --date 2026-06-23
seo-thermostat build-nightly --date 2026-06-23
```

For an initial backfill, fetch a wider live-data window before building the
latest settled date. `--backfill-days` is inclusive and ends on `--date`, or on
the default settled date (`T-3`) when `--date` is omitted:

```bash
seo-thermostat refresh-live --backfill-days 180
seo-thermostat build-nightly
```

To pin that six-month backfill to a specific settled date:

```bash
seo-thermostat refresh-live --date 2026-06-23 --backfill-days 180
seo-thermostat build-nightly --date 2026-06-23
```

If you already know the exact range, use explicit boundaries:

```bash
seo-thermostat refresh-live --start-date 2025-12-26 --end-date 2026-06-23
```

`refresh-live` pulls GSC, GA4, and PostHog rows into SQLite. `build-nightly`
then computes baselines, scores, flags, and recommendations from that local
database.

Set `SEO_THERMOSTAT_LOG_LEVEL=INFO` in `.env` to see refresh progress for each
live source. Logs go to stderr so MCP protocol output on stdout stays clean.

Example cron entry for a nightly local build:

```cron
15 2 * * * cd /path/to/seo-thermostat && . .venv/bin/activate && seo-thermostat build-nightly --db ./seo_thermostat.db >> logs/nightly.log 2>&1
```

Example macOS `launchd` command arguments:

```text
cd /path/to/seo-thermostat
.venv/bin/seo-thermostat build-nightly --db ./seo_thermostat.db
```

Keep scheduler files that contain machine-specific paths outside the repository or in an ignored local config folder.

## Public Repository Guidance

This repository should stay safe to publish.

- Commit source code, tests, docs, and public-safe fixtures only.
- Use `.env.example` for placeholder configuration, never real credentials.
- Keep `.env`, `.env` copies, SQLite databases, generated manifests, tokens, OAuth files, service-account JSON, `./secrets/`, `./.secrets/`, and local client config out of version control.
- Use example domains such as `example.com` in docs and fixtures.
- Prefer mocked connector tests for CI and public contributors.
- Document any optional live API smoke tests separately from the default test path.
- Run `python -m pytest tests/test_public_repo_hardening.py` before publishing if credentials or fixtures changed locally.

Before publishing or opening a pull request, check that no private domains, tokens, analytics exports, or user-specific paths are included.

## Project References

- Technical spec: `docs/SEO_THERMOSTAT_SPEC.md`
- Implementation checklist: `docs/TASKS.md`
- Example local configuration: `.env.example`
- Ignore rules for private/generated files: `.gitignore`