Back to blog
El agente del portal resolviendo una pregunta: primero llama a search_collections, luego a get_chunks_by_ids, y responde citando las fuentes recuperadas

An agentic RAG served as thirteen MCP tools

LabMCPAgentsApplied AI

When you connect a model to your data, the first attempt is always the same: stuff the context into the prompt. A dump of the documentation, the latest table rows, the summary you generated last night. It works with a small corpus and stops working as soon as it grows, because context is finite and because the model doesn't know what it's missing.

The alternative is not to give it content, but the ability to go find it. That's an MCP server: a process that exposes tools — named functions with typed arguments and a description — so the agent decides which one to call and with what. The protocol standardizes it; the interesting part is not the protocol, but what you decide to expose.

A tool is not an endpoint

The difference looks like a nuance and it isn't. An endpoint is called by a program that already knows what it wants; a tool is chosen by a model based on its description. That changes the design: the name matters, the description matters, and the arguments have to be obvious to someone who hasn't read your code.

It also changes what you do NOT expose. Giving direct access to the database seems like the most flexible option, and it's precisely what works worst.

A well-defined tool is a decision made in advance: this is the order in which things are searched, this is the limit, this is how sources are cited. The model doesn't have to reinvent it on every call.

The portal's thirteen

The Zetesis Portal MCP server exposes thirteen tools over the indexed content. They are not thirteen ways of doing the same thing: they cover three distinct moments of a query.

MomentTools
Getting orientedlist_retrieval_profiles, get_taxonomy_tree, get_filter_criteria, get_collection_stats
Searchingsearch_collections, get_post_summaries, get_book_toc
Readingget_chunks_by_ids, get_chunks_by_parent
Synthesizingsummarize_document, extract_claims, compare_perspectives, synthesize_comparison
The thirteen tools, grouped by what they're for.

The getting-oriented group is the most underestimated one. An agent that starts by asking what taxonomies exist hits the mark far more often than one that fires off a blind search, because it can filter by author instead of putting the author's name in the query — which never appears in a corpus of verbatim quotes, because nobody cites themselves by their last name.

  1. list_retrieval_profileswhat I can read
  2. get_taxonomy_treehow filtering works
  3. search_collectionsconcept, not words
  4. get_chunks_by_idsthe full text
  5. extract_claimswith its source
The usual journey of a question.

What search_collections does under the hood

Of the thirteen, the most used one is search, and it's worth knowing what it does because it has three modes and they fail in different places.

The lexical one searches for the words you wrote. It's exact and explainable: if a result shows up, you know why. Its limit is that it joins terms with AND — a four-word query requires all four in the same fragment — and it knows nothing about synonyms.

The semantic one searches by meaning through embeddings. It finds what you meant even if not a single word matches, and in return it doesn't distinguish well between similar and correct.

ModeGets it right whenFails when
LexicalYou know the exact termThe query is long or there are synonyms
SemanticYou describe the ideaYou have to tell similar things apart
HybridYou don't know which of the two cases it isYou have to explain why something came up
They fail in different places, which is exactly why they're combined.

The result count lies in vector mode

It's the trap that has bitten me most often. In the vector modes, recall is not set by the page you request: the engine retrieves a fixed number of neighbors and paginates over them. The total it returns is bounded by that number, not by what's in the corpus.

So asking the agent “how much content do I have on this?” in semantic mode returns something that looks like data and isn't. To actually count, you have to repeat the query in lexical mode and look at that total.

This is also what separates a tool from an endpoint: the description of search_collections has to teach the model to query by concept and filter by taxonomy, because an agent that puts the author's name in the query text finds nothing — in a corpus of quotes nobody names themselves by their last name.

The weight between the lexical and semantic parts in hybrid mode I set by intuition and manual testing, not by measurement. I know it works better than either one alone; I don't know what the optimum is or whether it changes with the corpus.

Why the semantic mode fails silently

There is a concrete reason behind vector mode leaving out things that are there, and it's not the corpus: it's geometric. In high-dimensional spaces, points appear that end up close to almost everything else. They're called hubs.

A generic entry ends up placed in the middle of the cloud and wins comparisons it shouldn't win, not because it fits better, but because it's close to everything. If the agent sorts by cosine and keeps the top results, the long tail never shows up.

The usual correction penalizes points that are neighbors of too many things. It reorders well, but it distorts the scale, so its number stops meaning anything on its own: to decide whether a result is reliable you have to look at the raw similarity, not the corrected one.

And confidence is no use for that either. A softmax over the finalists measures how much the first one stands out over the rest, not whether the first one is good. Five bad, similar candidates give low confidence; five bad ones where one stands out give high confidence. Neither tells you whether you got it right.

Chunking without losing the header

A long document doesn't fit in a single embedding call, and the way you reassemble it changes what the tool returns. Averaging the chunks equally treats the first page the same as the signature list at the end.

With decreasing weight — the first chunk weighs more than the second, and so on — the resulting vector looks more like what the document says it is. The header of a set of minutes tells you far more about its nature than its last page.

Profiles: what each agent can read

A tool server without scope control is a security problem with good documentation. On the portal, each agent is assigned retrieval profiles that define the hard scope of what it can read: which collections, which authors, which folders.

The detail that matters is the direction. The filters the agent passes on each call can only narrow within that scope, never widen it. If it asks for an author its profile doesn't cover, the request doesn't fail silently or return extra results: the filter is discarded and the response carries a notice explaining why. The agent can correct; what it can't do is step outside.

Same server, different scope

On top of that, search tokens are issued per user and carry their own profiles. Two people from different organizations point at the same server and see different corpora, without deploying anything per client.

That opens a possibility I hadn't foreseen at the start: any external MCP client — Claude Desktop, Cursor — can query the portal with those credentials. Search stops living only inside the website and moves to where people already work.

The same pattern, another domain

In Konect, the MCP server doesn't expose documents but search, facets, aggregations, and charts over analyzed conversations. An embedded chat uses them to answer questions about the data. The entire domain changes and the shape stays: tools with a defined scope instead of a dump into the prompt.

And in agentic development consulting they are custom-built servers against Loki, Grafana, or GitHub. The agent lives inside the system, with the same tools I would have.

What's still open

Thirteen tools are already enough for the model to pick the wrong one. I have no measure of how often it grabs the wrong one, and that's the next thing I want to instrument: not the quality of the answer, but the quality of the choice.

I'm also not sure where the ceiling is. I suspect the limit is not how many tools you expose but how much they overlap, and I don't know how to measure that yet.

Zetesis-Labs/PayloadAgents

Payload plugins and agent runtime, published as @zetesis/ packages. The MCP server lives here.

TypeScript

Keep reading