Skip to main content
Glama
raholsn

blog-mcp

by raholsn
README.md
# Rasmus's blog MCP server

Search and read [Rasmus Olsson's blog](https://www.rasmusolsson.dev) from an MCP
client. The server runs locally over **stdio** and downloads published articles
from `https://www.rasmusolsson.dev/articles.json` over HTTPS. Article data is not
bundled in the npm package, and no model API key is needed.

## Connect Claude Code

Requires Node.js 22.14 or newer and Claude Code. Once the package is published:

```sh
claude mcp add --transport stdio --scope user rasmus-blog \
  -- npx -y @raholsn/blog-mcp@latest
```

Open Claude Code and use `/mcp` to check the connection. Try:

> Find Rasmus's articles about parallel agents, then read the most relevant post.

The client starts and stops the server process. `@latest` resolves the current
published release when launched; a specific version can be used instead for a
fixed installation. There is no HTTP listener on the user's computer.

## Tools

| Tool | Inputs | Result |
|---|---|---|
| `list_articles` | Optional `tag`, `limit`, `offset` | Newest posts first, optionally filtered by an exact case-insensitive tag |
| `search_articles` | `query`, optional `limit`, `offset` | Keyword matches, with title and tag matches ranked higher |
| `get_article` | `slug` | Full article Markdown and its canonical URL |

List and search results include metadata and excerpts, not full content. Both
return `total` and `nextOffset` for pagination. The default page size is 10; the
maximum is 50. Search is case-insensitive and requires every whitespace-separated
query word to occur in the title, tags or content. It is basic keyword search,
not semantic search.

All tools are read-only. No credentials, filesystem access or arbitrary commands
are exposed as tools. The article text is source material, not instructions to
the client. Relative Markdown links resolve against the blog website.

## Feed and caching

The blog's static build publishes this shape:

```json
{
  "schemaVersion": 1,
  "articles": [{
    "slug": "example",
    "title": "Example article",
    "date": "2026-08-01",
    "tags": ["AI"],
    "url": "https://www.rasmusolsson.dev/posts/example/",
    "excerpt": "A short description.",
    "content": "The full Markdown article."
  }]
}
```

`updated` is an optional string. Slugs must be unique. The feed is validated on
load and cached in memory for five minutes. Concurrent requests share a download.
After expiry, a failed refresh is reported as a tool error rather than silently
serving stale data. Downloads time out after ten seconds and are limited to 10 MB.

The blog's normal deployments update the content independently of npm releases.
Set `BLOG_FEED_URL` to override the feed for development. HTTPS is required, except
for HTTP on localhost. A new process starts with an empty cache.

## Develop and test

```sh
npm ci
npm test
npm pack --dry-run
```

Tests cover caching and refresh failures, validation, search ranking, registry
release decisions and a real MCP client talking to the server over stdio.

To connect a development build:

```sh
npm run build
claude mcp add --transport stdio --scope user rasmus-blog \
  -- node /absolute/path/to/blog-mcp/dist/index.js
```

Only compiled JavaScript and npm's standard package metadata/README are shipped.
Diagnostic logs go to stderr; stdout is reserved for MCP protocol messages.

See the [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp) for
additional client configuration options.

TDQS

A4.7/5.0

Scored across 3 tools

Disambiguation5/5

Each tool serves a distinct purpose: listing all articles, searching by keywords, and retrieving full content by slug. The descriptions clearly differentiate list from search, and both reference get_article for full reading, so an agent should not confuse them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: list_articles, search_articles, get_article. The pattern is predictable and makes the action and resource clear for each tool.

Tool Count5/5

Three tools is well-scoped for a read-only blog server. List, search, and get cover the essential discovery and retrieval workflow without unnecessary bloat or missing core functionality.

Completeness5/5

For a blog reading domain, the lifecycle is complete: discover articles via list or search, then read full content via get. There are no obvious gaps like missing tag browsing or full-text retrieval, as the existing tools handle these through filters and links.

Maintenance

ActivityMaintained
ResponsivenessNo issues