# Is MCP enough for shared context between AI agents?

> No. In specification revision 2025-11-25, an MCP Resource declares nine fields and not one of them records which source is authoritative, which version is current, or which of two contradictory resources wins. A ride-sharing marketplace found out what that absence costs when an agent filtered on a valid word and returned nothing.

_Insights · 2026-07-13_

**MCP is enough to reach every source in your company and not enough to make any two of them agree.** Open the Model Context Protocol's normative schema at revision 2025-11-25 and read the Resource type: nine fields, two required, `uri` and `name`, and seven optional, `title`, `description`, `icons`, `mimeType`, `annotations`, `size`, and `_meta`. Not one of them records where the resource sits in your company's pecking order, which version it is, or which of two contradictory resources wins. I was inside a ride-sharing marketplace in late 2025, hired to sit in the day to day of its engineering organization and find what would break under an investor's due diligence, and the thing I found was not in the code. An agent filtered on a word every human in the company understood, the database matched nothing, no error was raised, and users stopped seeing the rides they had booked.

Where I stood bounds what I can tell you. I was not on the AI rollout, and I did not write or review the code in this story. Noticing things was the entire assignment, and this is what it turned up. The company stays anonymous. One product detail carries the rest: a ride was one of its central entities, and product, marketing, technical diagrams, and code each called it something else.

## MCP's Resource type declares nine fields and not one of them says which source is right

Here is everything the Model Context Protocol tells an agent about a resource. The specification is [explicit](https://modelcontextprotocol.io/specification/2025-11-25/basic) that its TypeScript schema, not its prose pages, is "the source of truth for all protocol messages and structures", and in [that schema at revision 2025-11-25](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-11-25/schema.ts) a `Resource` declares nine fields once you resolve what it inherits: six on the type itself, plus `name` and `title` from `BaseMetadata` and `icons` from `Icons`. Two are required, `uri` and `name`. Seven are optional: `title`, `description`, `icons`, `mimeType`, `annotations`, `size`, and `_meta`. Now find, in that list, the field that tells an agent whether `trip`, `offer`, or `carona` is the word the database will actually match. There is no such field, and its absence is not an oversight. The specification's own [architecture overview](https://modelcontextprotocol.io/docs/learn/architecture) says MCP "focuses solely on the protocol for context exchange" and that it "does not dictate how AI applications use LLMs or manage the provided context".

The closest the protocol comes to ranking a source is `priority`, a number from 0.0 to 1.0 that a server declares about its own resource, where the spec says a value of 1 means "most important". The closest it comes to freshness is `lastModified`, an ISO 8601 timestamp recording when the resource last changed, which is a fact about bytes rather than about truth. Both of those live in the resource's optional annotations, which a server writes about itself and nothing verifies. The specification's own view of self-description is easiest to see one type over. Under [the Tool type](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) it carries a warning in normative language: clients "MUST consider tool annotations to be untrusted unless they come from trusted servers". That warning is scoped to tools, so it says nothing about `priority` directly. What it shows is the protocol's posture in its own normative voice: when a server describes itself, the specification's instinct is to tell the client not to believe it.

None of this is a flaw in MCP. It is a protocol doing its job and declining one that was never its own. The trouble starts when a company reads reachability as readiness, connects nine sources to an agent, and assumes something in the pipe is deciding which of them is right. Usually the assumption lands on retrieval, which ranks passages by similarity and leaves authority where it found it: [MCP and RAG sit at different layers, and neither is the layer that decides](/en/blog/comparisons/mcp-vs-rag-for-agent-context).

## Why an AI agent returns an empty result with no error: the word was valid, the entity was not

Tony Hoare's null had one redeeming property. It crashed. Introducing his [QCon London 2009 talk](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/), Hoare called the 1965 null reference his "billion-dollar mistake": he had set out to make every use of a reference "absolutely safe, with checking performed automatically by the compiler", could not resist adding null anyway, and it went on to cause "innumerable errors, vulnerabilities, and system crashes". A crash is a gift. It stops the program, names a line, and points at itself. What the marketplace shipped in December 2025 did the opposite. Call it a semantic null: a result that is structurally valid and semantically empty, where the query ran, the types checked, zero rows came back, and nothing in the system knew the word was wrong.

The vocabulary had grown by function, the way it does everywhere:

| Artifact or layer | Term in use | What the team meant |
| --- | --- | --- |
| Technical diagrams | `trip` | A registered ride |
| Internal product language | `offer` | The same ride entity, internal only, never shown in the app or the website |
| Marketing campaigns | `carona` | The word customers actually used |
| Application code | `trips` | The table, the relationships, the entities, the variables, the methods |

Humans crossed those words without effort. In conversation the equivalence was obvious. Then one method filtered on the string `offer` where the executable contract defined `trips`. The filter accepted the string, ran normally, matched no records, and returned nothing. Nothing crashed. No error was raised.

Most of the product kept working, which is what made it survivable and what made it invisible. Users could still book rides, and the broader screens still queried `trips`. The defect sat in exactly one filter, the one selecting a user's scheduled rides for their personalized view and the notifications built on it. A release that was almost entirely correct hid the records that mattered most to the person looking for them. The support queue is where it surfaced: overnight, the top complaint at a company whose usual top complaint was ride cancellations became people saying they could not find their rides.

This is why a semantic incident survives ordinary checks. A response-only test passes. The type checker accepts the string. Error-only monitoring classifies the request as healthy, because it was. Unless a test asserts that a user with scheduled `trips` cannot receive an empty collection when another artifact says `offer`, nothing in the pipeline is looking for the failure at all.

## A newer MCP revision will not decide meaning, because meaning is knowledge held at the endpoints

The obvious objection to a field count is that field counts change. Someone will add an authority field in a later revision, and then what? Then nothing, and the reason is forty years old. In 1984, in [ACM Transactions on Computer Systems](https://web.mit.edu/Saltzer/www/publications/endtoend/endtoend.pdf), Saltzer, Reed and Clark gave the principle its name: "The function in question can completely and correctly be implemented only with the knowledge and help of the application standing at the end points of the communication system."

They were arguing about reliability. Error checks, encryption, duplicate messages. They never wrote a word about meaning, and I am extending their argument rather than quoting it at you. But look at what their own duplicate example turns on. The network cannot suppress an application's duplicate messages, they write, because those duplicates "look like different messages to the communication system", so suppression "must be accomplished by the application itself with knowledge of how to detect its own duplicates". What counts as the same message is a definition the application holds and the protocol cannot see. A definitional fact is already doing load-bearing work inside their reliability argument. That is the shape of the thing, and it holds for vocabulary too. Whether `offer` and `trips` are one entity is knowledge that lives in your company, in the heads of the people who let the words drift apart. It was never in the wire, and no revision puts it there.

Access is not agreement. A protocol makes every authorized source reachable without making any two of them mean the same thing, which is the protocol-level statement of the same law that makes an AI stack [split-brain by birth](/en/blog/insights/why-ai-makes-software-delivery-slower).

## Authority belongs to a fact, not to a tool, and provenance never tells you which one wins

Provenance records where a fact came from and how it changed; it never records that the fact wins. The W3C's [PROV access and query note (2013)](https://www.w3.org/TR/prov-aq/) draws that line in its own voice: "A provenance record is not of itself guaranteed to be authoritative or correct. Trust in provenance records must be determined separately from trust in the original resource." That separation is the whole problem in two sentences, because an agent reaching four sources needs the judgment and not the record.

The marketplace had no such judgment written down anywhere. Nothing said that code owned the operational identifier, that product owned the intended behavior, that marketing owned the customer-facing word, and that marketing vocabulary must never be copied into a data filter. So nothing objected when an internal product word became one. Authority of that kind cannot be granted to a tool once and for all, because it does not sit at the grain of a tool. For a single ride, at a single moment, the deployed schema governs `trips`, an approved product decision governs what the feature should do, and marketing governs `carona`. Three sources, all authoritative, none of them the system of record.

Data management has known this for decades, which is worth saying plainly rather than pretending we found it. Master data management assigns authority per field rather than per system, and its hard part has always been deciding which field from which source to trust; that is what survivorship rules are. What the discipline never had to solve is prose. Survivorship arbitrates typed values inside a schema, and there is no trust score you can compute between a sentence in a product document and a column definition. The grain was right all along. Nobody built it for the words.

## The failure was written by an agent, reviewed by an agent, and merged past a human who could not keep up

The filter was not a human mistake in the way that phrase usually lands. The feature that contained it was built by a coding agent. The code review was done by another AI. The human review failed the way human review fails now, drowned in a volume of code no person was going to read at that rate. Two agents, both with access to the product documents, the designs, and the codebase, and neither with any record of what the company had agreed the words meant. Neither one was wrong locally. The writing agent used a word that was true in product language. The reviewing agent saw code that did what it said. The failure lived between them, in a place neither had been given.

That gap is the measured one. [Faros AI's 2026 telemetry](https://pages.faros.ai/hubfs/AI_Engineering_Report_2026_The_Acceleration_Whiplash_Faros.pdf) across 22,000 developers reports bugs per developer up 54 percent and 31 percent more pull requests merging with no review at all. The human arbiter is leaving the path at exactly the moment the protocol declines to arbitrate.

A 2026 preprint has the cleanest version of this I know, and it comes with a caveat I would rather state than bury: [Dillon and Varanasi](https://arxiv.org/abs/2605.08112) tested a coding agent against 41 team decisions in one repository, and they build the context tool they were testing. Set their headline aside and read one row of their table. The repository held two audit functions, and a SOC-2 rule made exactly one of them mandatory for exports. The function was right there in the code. The rule was not written anywhere the agent could reach. Told to make sure the action was logged, the agent went looking, found an audit function, and used the wrong one, a distinction the authors say requires knowing why the right one exists. It could read both functions. What it could not read was which one the team had settled on, and no amount of reading the code would have told it, because the answer was never in the code. Their own conclusion is the honest form of it: retrieval makes compliance possible, and the structured workflow is what makes it reliable.

## Map every accepted alias to one governed entity before an agent can filter on it

Eric Evans wrote the pattern for this, and most teams remember only half of it. The famous half is the ubiquitous language: in the [Domain-Driven Design Reference (2015)](https://www.domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf) he asks a team to exercise that language relentlessly in all communication and in the code, and to use the same language in diagrams, writing, and especially speech, within a bounded context. The half teams forget is what he asks for at the borders. Where genuinely different models meet, his Context Map makes the translation at their points of contact explicit, "outlining explicit translation for any communication". The marketplace had neither safeguard in this workflow, so `offer` walked into the executable `trips` contract with nothing standing at the border.

Marketing should not have to write `trips`. That is the point people miss when they hear this and reach for a glossary project. Product should keep describing an offer, marketing should keep speaking the customer's language, and engineering should keep a stable contract. What has to exist is a record, readable by machines, that says these are the same entity, that `trips` is the one the database will answer to, and that the others are never allowed near a query. That record belongs in a governed [context layer](/en/blog/guides/context-layer-for-ai-agents) between the systems of work and the agents, which is what [LoomSignal](/en#pricing) is, self-hosted, for teams whose internals are not going to a cloud vendor.

Then the test that would have caught this becomes trivial to write: a user with scheduled `trips` must never receive an empty collection, whatever word the calling artifact used.

The marketplace found the filter and shipped the fix in three hours. That is the part I keep returning to. Once someone knew where to look, a large platform with a lot of features took an afternoon to reproduce and repair a one-word defect. The three hours were never the cost. The cost was everything before them, when the code was running exactly as written, the monitoring was green, the review had passed, and the only system in the company that knew something was wrong was a queue of people typing that they could not find their rides.

Go open the Resource type in your own stack. Nine fields. None of them is the one you needed.

---
Source: https://loomsignal.io/en/blog/insights/is-mcp-enough-for-shared-context
