{
  "uid": "cogitave.learn.native-mcp-interface.the-mcp-surface",
  "kind": "moduleUnit",
  "href": "/modules/native-mcp-interface/the-mcp-surface/",
  "title": "Why MCP is the native surface",
  "summary": "",
  "type": null,
  "products": [],
  "roles": [],
  "levels": [],
  "subjects": [],
  "headings": [
    "Why native, not adapted",
    "The protocol baseline",
    "What this buys, and what it costs",
    "What a pinned revision is for"
  ],
  "source": "## Why native, not adapted\n\nWhen an org decides how to serve its canonical model to humans and agents, it is\nreally choosing among three shapes of query surface. Cogitave weighed exactly\nthese in [ADR-0003](../../../../core/docs/decisions/0003-mcp-native.md): (1)\n**MCP-native** - tools and resources are the canonical surface, REST/GraphQL/`llms.txt`\nare generated; (2) REST/GraphQL-native with an MCP adapter bolted on; (3) a\nproprietary agent RPC. Cogitave is an agent company, and agents are the primary\nconsumers of company knowledge, so option 2 would make them second-class - \"the\nopposite of the company thesis,\" in the ADR's own words - and option 3 forfeits\necosystem and standardization for no real gain. The stated decision drivers\nwere: an agent-first AI maturity target (Level 4 - agent-first with human\noversight), one model and one query so humans and agents cannot drift onto\ndifferent data, standardized tool/resource semantics with subscriptions and\nchange notifications, and a spec Cogitave can author against with a clear upgrade\npath. The chosen outcome is option 1. The transferable point is the question,\nnot Cogitave's particular answer: if agents are first-class consumers of your\nknowledge, an adapter in front of a human-first API quietly makes them\nsecond-class.\n\n## The protocol baseline\n\n[mcp-interface.md §1](../../../../core/docs/mcp-interface.md#1-protocol-baseline)\npins the concrete contract Cogitave's Core server commits to - and it doubles as\na checklist of the decisions any native MCP surface has to make:\n\n- **Spec revision 2025-11-25**, pinned deliberately and still what Core ships\n  against. `2026-07-28` has since been **released** and is tracked for upgrade.\n  It is not a point release: it removed the session and the `initialize`\n  handshake outright, in favour of self-contained requests that carry their own\n  protocol version and capabilities. See [what a pinned revision is\n  for](#what-a-pinned-revision-is-for) below.\n- **Two transports**: stdio for local agents (namzu kernel, CI) and Streamable\n  HTTP for edge/remote callers - no legacy HTTP+SSE. An invalid `Origin` gets\n  HTTP 403; GET-stream polling and resumption use event IDs.\n- **JSON-RPC 2.0** over a stateful session, with capability negotiation\n  happening once, at `initialize`. This is the part `2026-07-28` replaced, and\n  it is the clearest illustration of why the revision is pinned rather than\n  followed.\n- **JSON Schema 2020-12** for every tool's input and output - the same dialect\n  the property graph schema itself uses, so a tool's structured content and the\n  model validate identically.\n- **Capabilities advertised**: `tools` (with `listChanged`), `resources`\n  (`subscribe` + `listChanged`), `logging`, `completions`, plus tool/resource\n  icons exposed as metadata.\n- **Errors as data, not protocol failures**: a tool input-validation failure\n  comes back as a **tool execution error** (`isError: true`) rather than a\n  JSON-RPC protocol error - SEP-1303 - so the calling model can read the\n  failure and self-correct instead of the call simply breaking.\n\n## What this buys, and what it costs\n\nPer the ADR's own consequences: subscriptions give live invalidation instead of\npolling, agents and humans literally cannot drift onto different data, and the\ndesign aligns with the\n[ai-agent-engineering standard](../../../../standards/docs/standards/ai-agent-engineering.md)'s\nrequirement that every capability go over MCP with a repo-committed\n`.mcp.json`. The ADR is equally honest about the risks: MCP itself is\nfast-moving - hence pinning a revision instead of floating on it - and a tool\nsurface is an attack surface, which is why the graph-query tool covered in the\nnext unit is deliberately read-only and bounded rather than a general query\nescape hatch.\n\n> [!TIP]\n> When you evaluate any MCP surface, ask ADR-0003's own question back: is this\n> tool/resource set the canonical thing itself, or an adapter in front of\n> something else? Cogitave's answer for Core is the former.\n\n## What a pinned revision is for\n\nThe site you are reading this on has its own MCP endpoint, and it runs\n**`2026-07-28`** - a different revision from the one Core pins. That is not an\ninconsistency anyone forgot to fix; it is what pinning is for, and it is worth\nsitting with, because it is the situation you will actually be in.\n\n`2026-07-28` did not add a feature to the protocol above. It removed the spine\nof it. There is no `initialize`, so there is no session, so capability\nnegotiation cannot happen \"once, at the start\" - every request carries its own\nprotocol version and capabilities, and the server is forbidden from inferring\nanything from a previous one. A server built for the older shape does not get\nthere by upgrading a dependency.\n\nSo a revision is pinned, and the difference between two surfaces becomes a\nvisible, dated fact rather than an accident discovered when a client breaks.\nEach surface upgrades when its own constraints allow: a documentation endpoint\nserving a static corpus has almost nothing to lose by moving early, while a\nserver holding subscriptions and live invalidation has considerably more to\nwork through.\n\nThe transferable point is not which revision is \"right\". It is that a\nfast-moving protocol is a **dependency with a version**, and the two honest\npositions are to pin it and say which pin you are on, or to float and accept\nthat your callers find out when something stops working. \"We use MCP\" is not a\nstatement of compatibility with anything.\n",
  "partOf": "cogitave.learn.native-mcp-interface",
  "durationInMinutes": 7,
  "quiz": null
}