-
Notifications
You must be signed in to change notification settings - Fork 0
Webhook Plugins Configuration
After a successful build_site call, the Hugo MCP server can automatically trigger up to four post-build plugins: Cloudflare cache purge, IndexNow submission, Google Indexing API notification, and (as of 2026-08-22) a BetterStack heartbeat ping. All four are opt-in — if the relevant config section is absent or empty, the plugin is silently skipped. Failures in any plugin are logged as warnings and do not affect the build response.
This page covers how to provision credentials for each plugin, configure them in /etc/mcp-hugo-server-go/config.yaml, and harden the setup for production.
These rules apply to all three plugins. Read before proceeding.
-
Never commit secrets to git.
api_token,key, and the Google SA JSON must exist only in the host config file or on the server filesystem. - Lock down the config file so only the service user can read it:
chmod 600 /etc/mcp-hugo-server-go/config.yaml
- Apply the same permission to the Google service account JSON:
chmod 600 /etc/mcp-hugo-server-go/google-sa.json
# /etc/mcp-hugo-server-go/config.yaml
cloudflare:
zone_id: YOUR_ZONE_ID # CF dashboard › Overview › Zone ID (right sidebar)
api_token: YOUR_TOKEN # CF token with Zone / Cache Purge / Purge permission
indexnow:
key: YOUR_KEY # 32–128 char hex key you generate
key_location: https://www.example.com/YOUR_KEY.txt # public URL to key verification file
host: www.example.com # your site hostname
endpoint: https://api.indexnow.org/indexnow # optional; this is the default
google_indexing:
service_account_path: /etc/mcp-hugo-server-go/google-sa.json
daily_quota_limit: 180 # Google allows 200/day; 180 gives a safety margin
quota_state_path: /var/lib/mcp-hugo-server-go/google-index-quota.json
heartbeat_hooks:
- https://uptime.betterstack.com/api/v1/heartbeat/YOUR_HEARTBEAT_IDOmit any section you do not need. Each plugin checks for the presence of its own section independently.
Purges the full zone cache via Cloudflare API v4 after every successful build. Also fires on delete_page (single-URL purge).
- Log in to the Cloudflare dashboard → My Profile → API Tokens → Create Token.
- Use the Cache Purge template, or create a custom token with:
- Permission: Zone / Cache Purge / Purge
- Zone resources: scoped to your site's zone
- Copy the generated token — it is shown only once.
- Find your Zone ID on the dashboard Overview page (right sidebar under the domain name).
cloudflare:
zone_id: "abc123def456..."
api_token: "your-cloudflare-api-token"Submits all content page URLs to IndexNow (api.indexnow.org) after every successful build. Taxonomy and search pages (/tags/, /categories/, /authors/, /search/) are automatically filtered out.
- Generate a random hex key (32–128 characters):
openssl rand -hex 32
- Save the key as a plain-text file in your Hugo site's
static/directory, using the key value as the filename:echo "YOUR_KEY" > static/YOUR_KEY.txt
- Build and deploy your site so the file is publicly accessible at the URL you will put in
key_location. Verify with:curl https://www.example.com/YOUR_KEY.txt
- The response body must be exactly the key string (no extra whitespace).
indexnow:
key: "YOUR_KEY"
key_location: "https://www.example.com/YOUR_KEY.txt"
host: "www.example.com"
# endpoint is optional; defaults to https://api.indexnow.org/indexnowSends a URL_UPDATED notification to the Google Indexing API v3 for each content URL after a successful build, using service-account JWT authentication. Taxonomy and search pages are automatically filtered out.
Google's free tier allows 200 URL notifications per day. The server tracks daily usage in a state file and stops submitting once daily_quota_limit is reached.
-
Verify site ownership in Google Search Console.
-
In Google Cloud Console, create or select a project and enable the Web Search Indexing API:
- Navigate to APIs & Services → Library → search for "Web Search Indexing API" → Enable.
-
Create a service account:
- IAM & Admin → Service Accounts → Create Service Account.
- Grant it no project-level IAM roles (access is granted via Search Console, not Cloud IAM).
- After creation, go to the service account → Keys → Add Key → JSON.
- Download the JSON key file.
-
Copy the JSON key to the server:
scp google-sa.json user@yourserver:/etc/mcp-hugo-server-go/google-sa.json chmod 600 /etc/mcp-hugo-server-go/google-sa.json
-
Grant the service account access in Search Console:
- Go to Search Console → Settings → Users and permissions → Add user.
- Enter the service account email (e.g.
my-sa@my-project.iam.gserviceaccount.com). - Set the role to Owner (required by the Indexing API).
-
Create the quota state directory and ensure it is writable by the service user:
mkdir -p /var/lib/mcp-hugo-server-go chown mcp-hugo-server-go:mcp-hugo-server-go /var/lib/mcp-hugo-server-go
google_indexing:
service_account_path: "/etc/mcp-hugo-server-go/google-sa.json"
daily_quota_limit: 180
quota_state_path: "/var/lib/mcp-hugo-server-go/google-index-quota.json"Pings a BetterStack dead-man's-switch heartbeat monitor after every build_site call — unsuffixed URL on success, /fail appended on OnBuildFailed. Fires asynchronously in a detached goroutine with a 15s bounded timeout; it never blocks the build response, and a ping failure is only logged as a warning. run_post_build_hooks also accepts an optional status param ("success"/"fail") to report a build/deploy result by hand outside the build_site path — this is what deploy.yml's heartbeat_report job uses via DEPLOY_HEARTBEAT_URL, since a deploy pipeline's pass/fail isn't itself a build_site call.
Treat the heartbeat URL as a secret, not a public identifier. Anyone who learns it can POST arbitrary success/fail pings and mask a real incident or trigger a false one. Never commit the real value — host-local config.yaml only (root-owned, outside git) plus the deploy pipeline's secret store.
- Create a heartbeat monitor in BetterStack (Monitors → Heartbeats → New).
- Set the expected period/grace to match your deploy + build cadence.
- Copy the ping URL — shown on the monitor's detail page.
heartbeat_hooks:
- "https://uptime.betterstack.com/api/v1/heartbeat/YOUR_HEARTBEAT_ID"Multiple URLs are supported (pings all of them); most deployments only need one.
If the service unit uses ReadWritePaths (recommended), ensure the quota state directory and site directories are listed:
[Service]
ReadWritePaths=/var/lib/mcp-hugo-server-go /home/jm/hugo-site/content /home/jm/hugo-site/publicWithout this, the server cannot write the quota state file and will log permission errors on every build.
If the Google SA JSON is in a directory owned by a different group (e.g. hugo-mcp), add the service user to that group:
usermod -aG hugo-mcp mcp-hugo-server-go
systemctl restart mcp-hugo-server-go| Plugin | Trigger | Filtered URLs | Failure effect |
|---|---|---|---|
| Cloudflare Cache Purge |
build_site (full zone), delete_page (single URL) |
None | Warning logged; build succeeds |
| IndexNow | build_site |
Taxonomy + search pages | Warning logged; build succeeds |
| Google Indexing API | build_site |
Taxonomy + search pages | Warning logged; build succeeds |
| BetterStack Heartbeat |
build_site (success and OnBuildFailed), or manually via run_post_build_hooks(status=...)
|
N/A | Warning logged; build succeeds (async, never blocks) |
All four plugins fire in sequence (heartbeat fires asynchronously). No plugin failure blocks the others or the build response.