Skip to main content
Glama
README.md
# Hugo MCP server

A generic **MCP (Model Context Protocol) server** for any Hugo blog, deployed on Cloudflare Workers.

It reads your blog's `llms.txt` and `llms-full.txt` files and exposes them as structured tools that AI assistants (Claude, Cursor, and others) can query to understand your content.

---

## How it works

```
Your Hugo blog           Cloudflare Worker          AI assistant
─────────────────        ──────────────────         ──────────────
/llms.txt          ───►  /mcp  (MCP tools)  ◄───►  Claude / Cursor
/llms-full.txt     ───►  /llms.txt (proxy)          etc.
                         /llms-full.txt (proxy)
```

The Worker fetches your blog's `llms.txt` and `llms-full.txt` at runtime (with an in-memory cache), and exposes three MCP tools:

| Tool | What it does |
|------|-------------|
| `get_blog_summary` | Returns the concise overview from `/llms.txt` |
| `get_blog_full_index` | Returns the full content index from `/llms-full.txt` |
| `search_content` | Searches for a keyword across the full index and returns matching paragraphs with context |

---

## Prerequisites

- A Hugo blog publicly accessible on the web
- `llms.txt` and `llms-full.txt` files in your Hugo `static/` folder (see [Step 1](#step-1--create-your-llmstxt-files))
- A [Cloudflare account](https://dash.cloudflare.com/sign-up) (free tier is enough)
- [Node.js](https://nodejs.org/) ≥ 18
- [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/) (`npm install -g wrangler`)

---

## Step 1 — Create your llms.txt files

`llms.txt` and `llms-full.txt` are plain-text files that describe your blog's content to language models. They live in your Hugo `static/` folder and are served automatically at `/llms.txt` and `/llms-full.txt`.

### Option A — Use the helper script

```bash
# Clone this repo
git clone https://github.com/your-username/hugo-llms-mcp.git
cd hugo-llms-mcp

# Edit the configuration at the top of the script
nano scripts/generate-llms.py

# Run it — outputs static/llms.txt and static/llms-full.txt
python3 scripts/generate-llms.py
```

Then copy the generated files to your Hugo site's `static/` folder, review and enrich them manually, and redeploy your site.

### Option B — Write them by hand

**`static/llms.txt`** (summary, ~50 lines):

```
# My Hugo Blog

> One-line tagline for your blog.

Author: Your Name
Site: https://your-hugo-blog.com
Language(s): English

## Description

Two or three sentences describing what the blog is about,
who the author is, and who it's for.

## Published content

- Post Title One (Month Year) — https://your-hugo-blog.com/posts/post-one/
- Post Title Two (Month Year) — https://your-hugo-blog.com/posts/post-two/

## Instructions for language models

- Content may be freely summarised with attribution and a link to the source.
- Short excerpts may be quoted for informational purposes.
- Reproduction of full articles is not permitted.
```

**`static/llms-full.txt`** (extended index, as long as needed):

```
# My Hugo Blog
# llms-full.txt — Extended index for language models

Site: https://your-hugo-blog.com
Author: Your Name
Generated: June 2026

---

## Author profile

A longer bio of the author.

---

## Content

---

### Post Title One

URL: https://your-hugo-blog.com/posts/post-one/
Date: January 2025
Description: A detailed summary of what this post covers,
key points made, people or places mentioned, and tone.

---

### Post Title Two

...
```

> **Tip:** The more detailed `llms-full.txt` is, the more useful the `search_content` tool becomes. Include summaries, key locations, episode descriptions, and any cross-references between posts.

### Verify the files are live

After deploying your Hugo site, check:

```
https://your-hugo-blog.com/llms.txt
https://your-hugo-blog.com/llms-full.txt
```

Both should return plain text. If they do, you're ready for Step 2.

---

## Step 2 — Configure the Worker

Clone this repo (if you haven't already) and edit `wrangler.toml`:

```toml
name = "my-blog-mcp"            # becomes my-blog-mcp.<account>.workers.dev

[vars]
SITE_URL     = "https://your-hugo-blog.com"
SITE_NAME    = "My Hugo Blog"
CACHE_TTL_SEC = "3600"          # cache TTL in seconds; 0 = always fetch fresh
```

---

## Step 3 — Deploy

```bash
# Install dependencies
npm install

# Log in to Cloudflare (once)
wrangler login

# Deploy
npm run deploy
```

Wrangler will print the Worker URL:

```
https://my-blog-mcp.<your-account>.workers.dev
```

---

## Step 4 — Verify

```bash
# Health check
curl https://my-blog-mcp.<your-account>.workers.dev/health

# List MCP tools
curl -s -X POST https://my-blog-mcp.<your-account>.workers.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | python3 -m json.tool

# Search for a keyword
curl -s -X POST https://my-blog-mcp.<your-account>.workers.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_content","arguments":{"query":"your keyword","max_results":3}}}' | python3 -m json.tool
```

---

## Step 5 — Connect to Claude

### Claude.ai

Settings → Connectors → Add MCP Server:

```
https://my-blog-mcp.<your-account>.workers.dev/mcp
```

### Claude Desktop

Install the `mcp-remote` bridge (needed because Claude Desktop doesn't yet support remote MCP natively):

```bash
npm install -g mcp-remote
```

Edit `claude_desktop_config.json`:

- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
  "mcpServers": {
    "my-blog": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://my-blog-mcp.<your-account>.workers.dev/mcp"
      ]
    }
  }
}
```

Restart Claude Desktop. The three tools will appear in the tool list.

### Cursor / other MCP clients

Use the Worker URL directly: `https://my-blog-mcp.<your-account>.workers.dev/mcp`

---

## Updating content

The Worker fetches content from your live site and caches it in memory for `CACHE_TTL_SEC` seconds (default: 1 hour). So when you publish new posts:

1. Update `llms.txt` and `llms-full.txt` in your Hugo `static/` folder.
2. Redeploy your Hugo site — the Worker will pick up the changes automatically within the cache TTL.

No need to redeploy the Worker itself unless you change `wrangler.toml` or `src/index.js`.

---

## Project structure

```
hugo-llms-mcp/
├── src/
│   └── index.js          ← Cloudflare Worker (MCP server logic)
├── scripts/
│   └── generate-llms.py  ← Helper to scaffold llms.txt files
├── wrangler.toml         ← Cloudflare configuration (edit this)
├── package.json
├── .gitignore
├── LICENSE
└── README.md
```

---

## Cloudflare free tier limits

| Resource | Free limit |
|----------|-----------|
| Requests | 100,000 / day |
| CPU time | 10 ms / request |
| Memory   | 128 MB |
| Script size | 1 MB (compressed) |

A typical blog MCP server uses well under all of these limits.

---

## Real-world example

This project was originally built for [ciclogravelista.com](https://ciclogravelista.com), a personal gravel cycling travel blog. The live MCP server is available at:

```
https://ciclogravelista-mcp.ciclogravelista.workers.dev/mcp
```

Source: [github.com/your-username/ciclogravelista-mcp](https://github.com/your-username/ciclogravelista-mcp)

---

## License

MIT — see [LICENSE](LICENSE).