This is the most opinionated part of the build. Most MCP tutorials start with API keys or OAuth 2.0. I skipped all of that. The server at mcp.javatask.dev is completely public.

In the previous parts of this series, we focused on “passive” signals: llms.txt files, clean Markdown mirrors, and semantic HTML. These are essential — they tell an AI agent where to look and what the structure is. But today, we’re moving from passive to active by building an MCP (Model Context Protocol) server. Instead of an agent reading a 10MB llms-full.txt file, it can now call a tool to “search for articles about Bedrock.”

Friction Kills AI Agent Adoption

Friction kills adoption for AI agents. The key argument is simple: AI agents don’t have user accounts.

If an AI agent needs to find a solution to a problem and hits an OAuth wall, it will take the path of least resistance — another source that’s easier to access. Requiring OAuth is a conversion funnel that AI agents cannot complete. My blog content is already public. There is no PII, no private data, and no write operations anywhere. Making the MCP server public is simply aligning the API interface with the content’s nature.

If you want your knowledge to be part of the AI’s reasoning loop, public content must have a public API. The target audience is agents, and agents don’t fill out registration forms.

Markdown-as-an-API Optimizes for the Context Window

The server exposes three tools — the complete “API surface” of the blog:

list_articles — Browse the catalog. Supports filtering by tags or series. “What has Andrii written about serverless?” Returns metadata without the full body.

get_article — The deep dive. Pass a slug, get back the raw Markdown content with full citation metadata. Clean, unformatted, ready for an LLM’s context window.

search_articles — Full-text search across titles, descriptions, tags, and body content. The most-used tool in practice.

Each tool returns clean Markdown with citation metadata, optimised for LLM context window consumption rather than human rendering.

A Serverless Architecture Scales with Agentic Demand

Claude.ai / Gemini CLI / IDE
    ↓ MCP tool call (HTTP POST)
API Gateway (HTTP API, 5 rps / 20 burst)
    ↓
Lambda (Node 22, ARM64, 256 MB, 10 reserved concurrency)
    ↓
Express.js + MCP SDK (Streamable HTTP transport)
    ↓
content-index.json (embedded in Lambda bundle)

Why Express on Lambda? MCP over HTTP uses Streamable HTTP transport — standard POST requests for tool calls. Lambda handles this perfectly: zero cost when idle, instant scale when an agent starts searching. The ARM64 runtime at 256 MB keeps costs negligible even under load.

Layered Rate Limiting Negates the Need for Auth

Public doesn’t mean unprotected. Three defense layers prevent abuse:

  1. API Gateway throttling — 5 requests per second, 20 burst. Handles volumetric attacks at the edge before Lambda is even invoked.
  2. Lambda reserved concurrency — Capped at 10. Even if 100 requests arrive simultaneously, only 10 Lambda instances run. The rest get a 429.
  3. Express in-app rate limiting — 30 requests per 60 seconds per IP address. Enough for any real interactive session, but effective against automated loops.

My blog content being scraped 30 times per minute by a legitimate AI session is fine. My Lambda bill being destroyed by a runaway script is not. These three layers together make the attack surface cost-prohibitive without adding friction for legitimate users.

The Worst Case Costs $26. I Can Live With That.

The philosophical argument for a public API on public content is nice. The financial argument is better.

Here is what it actually costs to run this MCP server when a bot hammers it at the full API Gateway rate limit — 5 requests per second, every second, for 31 days straight:

ServiceCalculationCost
API Gateway HTTP API13,392,000 req × $1.00/M$13.39
Lambda invocations13,392,000 req × $0.20/M$2.68
Lambda duration334,800 GB-s × $0.0000133334$4.46
Data transfer out(67 GB − 10 GB free) × $0.09/GB$5.13
Route53Hosted zone + queries~$0.60
Worst case total~$26

That is the absolute ceiling — a single bot, running flat-out, hitting every rate limit without triggering a Lambda concurrency rejection, for an entire month. In practice, three things prevent this from happening simultaneously: API Gateway caps throughput at 5 rps, Lambda reserved concurrency at 10 caps burst handling, and the per-IP Express limiter drops repeat offenders after 30 requests in 60 seconds.

The realistic scenarios look like this:

  • Normal operation (~10,000 requests/day): under $1/month, excluding Route53
  • Moderate abuse (1 rps sustained): ~$5/month
  • Absolute worst case (5 rps, 31 days non-stop): ~$26/month

I would spend more than $26 in engineering time designing, implementing, testing, and maintaining an authentication system. The rate limiting already exists as an operational necessity — not as a security gate. Adding auth on top would cost more to build than the worst-case attack saves.

Public content. Public API. The math agrees.

In-Memory Indexing Beats Database Latency

The Lambda doesn’t call a database or crawl the filesystem. Instead, the content is pre-indexed.

When I run my Hugo build, a custom script (scripts/build-mcp-content.mjs) traverses content/blog/, parses the YAML frontmatter, strips markdown syntax from the body, and generates a single optimized content-index.json. This file is committed to the repo and bundled directly into the Lambda deployment package.

The result: search is just a local filter over a JSON array in memory. No network calls, no cold-start database connections, no latency spikes. The entire article corpus loads with the Lambda instance and stays warm.

Standard Discovery Protocols Make Tools Universally Findable

To make it easy for anyone to use, I’ve implemented the .well-known/mcp.json discovery file:

{
  "mcpServers": {
    "javatask-dev": {
      "url": "https://mcp.javatask.dev/mcp",
      "description": "javatask.dev blog — AWS, serverless, cloud architecture"
    }
  }
}

This file is served as a static asset by Hugo at /.well-known/mcp.json. Agents that support MCP auto-discovery can find the server without any manual configuration.

Proof of the Thesis: Four Steps to Connection

The test of the no-auth decision is how long it takes to connect.

If you use Claude.ai, you can add this blog as a remote tool right now:

  1. Open Claude.ai settings
  2. Navigate to the “Integrations” or “MCP Servers” section
  3. Add a new remote MCP server
  4. Set the URL to: https://mcp.javatask.dev/mcp

No registration form. No API key rotation schedule. No developer portal.

Now you can ask Claude: “Search javatask.dev for articles about AWS Bedrock and summarize the key security takeaways.” Claude will call the Lambda, search the content index, retrieve the relevant Markdown, and give you a grounded answer based on my actual writing.

Conclusion

This series has been about one thing: respecting the new reader.

In 2026, your readers aren’t just humans scrolling on iPhones. They are agents summarizing, synthesizing, and integrating your knowledge into larger workflows. By layering passive GEO signals (Parts 1–5) with an active MCP server (Part 6), the blog becomes more than a destination — it becomes a service.

The full stack: a static Hugo site on AWS for under $2/month, with Lighthouse 100 performance, a complete GEO layer for AI discoverability, and a public serverless MCP server that any AI agent can query.

That’s what “Building a Blog That AI Can Read” looks like in practice.