As of this week, this site is also an MCP server. If you use Claude, Claude Code, Cursor or any compatible client, you can connect it and ask your assistant about the posts: summarize one, find the section where I explain PPO clipping, or tell you which demos are running. The server only returns text from the blog, always with the original URL so you can check it.

The question I asked myself when I published it was an uncomfortable one: if almost everything had been ready for weeks, why did it take me so long?

This post is the honest answer. And as in previous posts, I built it together with a coding assistant, with a spec written first and a log that records every decision and every mistake.

The idea dates back to September

On September 16 I published Agentic Racing. In the introduction I wrote that I was deep into communication between agents: MCP, A2A, and how far you can take the idea of agents that coordinate. That demo’s strategist already was that: something that reasons and sends short instructions to something that reacts.

An MCP server for my own blog was the obvious next step. A standard channel through which any agent could read what I write, without scraping and without making things up.

I never lost sight of it. But I didn’t build it.

The pieces were already there

When I finally sat down to design it, almost nothing was new:

  • The content. Every post, in English and Spanish, already lived as markdown with metadata: title, tags, date and translation. It only had to be packaged into an index during the build.
  • Demos with human approval. Since June, every demo on the site is requested through a form and I approve each request by email. The MCP could reuse that same flow without bypassing anyone.
  • The RAG lesson. In the RAG chatbot over my blog I learned that a guarantee can’t live inside a prompt. A server that only returns text from the corpus, and generates nothing, applies that idea by design.
  • The analytics. The site already recorded its own events, so counting how many calls the MCP gets meant adding one event type.

What was missing wasn’t code. What was missing was sitting down to decide what it should be.

Why it took so long: the demos came first

Between September and November, the calendar filled itself:

  • Agentic Racing didn’t end when I published it. The post covers eight failed attempts to train the driver with reinforcement learning and seven runs of the strategist experiment. In early October I was still correcting training figures, and I last updated it on October 10.
  • That failure turned into a whole series: eight posts of Reinforcement Learning from scratch, using Agentic Racing as the lab, published between October 2 and 13.
  • In between came the trip planner, the dreaming agent and the Harness² demo, which also brought a production bug: the environment was being destroyed in the middle of a long run.

Every demo was something a person could try with one button. The MCP, on the other hand, was a new door to things that already existed. There was always something more visible to do first. It wasn’t an explicit decision, it was the sum of many small ones.

What made it ship in one night

On November 10 I finished and approved the spec. Not a list of ideas: a document with the architecture, the environment’s constraints, every tool with its contract, the usage limits, a security checklist and the open decisions resolved before writing a single line of code: the URL, whether the assistant could request demos, the default language, whether the index would be public, and whether the server would go into the official MCP registry. Along with the spec came a phased plan, each phase with its own condition for moving on to the next.

With that, the coding assistant did the implementation in a single run, with almost no input from me (I only approved a couple of things in the chat), leaving a log of what it did, what it decided and what was left for me: credentials, configuration and testing with a real client. That same night the server was answering in production.

Two things about that run seem the most valuable to me:

  • The search tests were written before the search engine. Thirty queries, written by reading the posts, each with the post it should find. That way nobody could tune the search engine while looking at the exam.
  • Before touching the demo flow, tests were written that pin down how it works today. Only then was the function the MCP reuses extracted.

The lesson is almost embarrassingly simple: the delay was never in the code. It was in not having written the spec.

The constraints shaped the design

The usualMy versionWhy
Official MCP SDKMy own JSON-RPC dispatcher, about 1,000 linesThe SDK expects an async web server, and the site’s API is serverless functions that only answer HTTP. The surface is small.
Semantic search with embeddingsLexical BM25F over an index generated at build timeThe RAG chatbot’s vector database only exists while a demo is active. The MCP can’t depend on it.
Stateful sessions and streamingStateless HTTP, one JSON response per requestIt fits functions that live as long as a request does.
A dedicated subdomain behind a proxyThe site’s own URL, /api/mcpThe proxy was built, with its tests, and then I parked it: it added a component, a secret and a network hop without contributing anything.
Letting the assistant request demosThe tool exists, but it’s switched offFirst I want to see a week or two of real traffic. When it’s turned on, requests will still land in my email.

What it doesn’t do, on purpose: the server doesn’t generate answers with a model of its own. It retrieves text and the client’s model synthesizes it. I don’t pay for tokens, and whatever the server returns always comes from the blog.

But it has to be said: the guarantee is weaker than the RAG chatbot’s. The server controls what text it hands over, not what the assistant on the other end does with it.

What broke (or almost did)

  • The plan contradicted itself. It asked to detect Spanish with at least two typical words of the language, but its own test case, “aprendizaje por refuerzo”, has only one: “por”. The spec won, since it asked to compare languages instead of counting words.
  • Portuguese was detected as Spanish. “Como funciona o aprendizado por reforço” came out Spanish because of “como” and “por”. Strong Portuguese signals and a minimal French list were added, only so they wouldn’t be confused.
  • “C#” vanished during tokenization. Now C#, C++ and .NET are turned into regular words before the text is split.
  • The description for the official MCP registry was 127 characters long, and the maximum is 100. It was caught by validating against the schema before publishing, not after.
  • A test script without jq sent an empty body, and the server answered with a 415 error that explained nothing. Now the script requires jq and says what’s missing.

The measurement

Search was evaluated with those 30 queries over the blog’s real index, 10 of each kind. A hit means the expected post shows up in the top 5 (recall@5). MRR also rewards it showing up near the top.

Query typeExamplerecall@5MRR
Using the post’s words”PPO clipping policy update”1.000.95
In the other language”algoritmo de Levenshtein en JavaScript” → an English post0.800.72
Paraphrase”copying what a teacher does instead of trial and error”0.400.28

The paraphrase gap is real and expected: BM25 searches for words, not meanings. “How do agents remember things over time” didn’t find the dreaming agent post, which is precisely about memory. My favorite failure: “an AI that rewrites its own prompts and a grader that approves everything” describes the Harness² post exactly, and the first result was a sudoku solver in C#. The post says “judge”, not “grader”, and talks about improving instructions, not rewriting prompts. It tells the same story in other words.

The search engine wasn’t tuned by looking at those queries. With the spec’s weights, the queries using the post’s words scored 1.00 on the first run, so there was nothing to tune, and the paraphrases were left as the baseline.

On top of that, the server has 134 automated tests, and they all pass. Building the index takes about 300 ms and each search about 3.5 ms, measured during the run over the real index.

The honest limitation: it’s 30 queries, and the assistant wrote them by reading the posts, not real readers. The tests run against the code and the blog’s index, not against the production server. And there isn’t enough traffic yet to talk about usage.

What I’d do differently

Write the spec in September. I didn’t need two free months: I needed to sit down and decide. Everything that came after was fast because the decisions had already been made.

What’s next

The spec already holds the experiment for the next post: does an assistant with this lexical MCP answer questions about my blog as well as my RAG chatbot with semantic search? The same questions against both, measuring whether every claim comes from the text, whether it cites correctly, and whether it says “I don’t know” when it should. I suspect the interesting part will be in the failures: a large model can make up for lexical search by rephrasing the query several times, and a small one can’t.

What I take away

The urgent beats the important without you noticing. I never decided to postpone the MCP. There was simply always a more visible demo.

The bottleneck was the decision, not the code. With the decisions resolved in writing, the implementation took one night.

Writing the exam before the solution forces you to be honest. The 0.40 for paraphrases isn’t a pretty number, but it’s real, and it’s exactly what the next experiment will measure.


If you want to try it, alexisalulema.com/mcp has the instructions for each client. In Claude Code it’s one line:

claude mcp add --transport http alexisalulema https://alexisalulema.com/api/mcp

Ask it to summarize the RL series or to tell you which post talks about the judge that always said yes. And if a paraphrase finds nothing, now you know why.

Almost two months waiting. One night building it.