Recursive AI

Interop

All onemodelcontext docs

OneModelContext is checked against other implementations of the protocol, run as black boxes: installed from their published releases at pinned versions and driven through their command lines, their wire behaviour and small programs in this directory written from each SDK's published documentation. Their files are never opened or copied.

What a run covers

DirectionOraclesTransportsEras
Their client → our serverTypeScript SDK client, Python SDK client, official C# SDK client, Inspector CLIstdio, Streamable HTTP (ASP.NET Core host; the built-in listener in the full matrix)each era the oracle can speak: Python auto/legacy (and a 2026-07-28 pin in the full matrix), Inspector modern/legacy, TypeScript and C# SDK as they negotiate
Our client → their serverTypeScript, Python and C# SDK fixture servers; the TypeScript SDK's HTTP+SSE serverstdio, Streamable HTTP, HTTP+SSE--era auto, forced legacy, and forced modern in the full matrix (a legacy-only server must answer with a typed error naming both sides' eras)
Our client → published serversserver-everything, mcp-server-time (reduced); plus server-filesystem and server-memory (full)stdioas above

Checks per pairing (connect records the negotiated version): tools list, a text call, an image call, resources list and read, prompts list and get, an unknown tool (error), progress, cancellation (the call is abandoned and the connection still works), and an elicitation round (server asks, client answers). The Inspector and the published servers get the subset those tools can drive. A check a given SDK cannot perform in an era is a result, not an omission: the row shows what it did on the wire.

Running

Terminal
export INTEROP_CACHE=/some/directory/outside/the/repository
interop/install.sh                                  # Node (user-local if missing), the npm packages, a uv virtual environment
interop/run.sh --out results --matrix reduced       # one pairing per kind
interop/run.sh --out results --matrix full          # every pairing above
interop/run.sh --out results --only ours__py-server # cases whose id contains the text

run.sh builds the three .NET drivers (output outside the repository: set ArtifactsPath, or it uses $INTEROP_WORK/artifacts), starts each server on loopback, runs each client with a timeout and stops only the processes it started. Ports come from INTEROP_PORT_BASE (default 49300) upward; our servers pick port 0 and print the one they got. It writes results.md, results.json, and per case cases/ID.jsonl (one line per check), ID.err, ID.exit and the server logs. Case ids read client__server__transport__era.

Nothing here runs in continuous integration; it is run at milestones.

Pins

OracleVersionSource
@modelcontextprotocol/sdk (TypeScript)1.32.2npm
@modelcontextprotocol/inspector2.14.0npm
mcp (Python)2.3.0PyPI
ModelContextProtocol, ModelContextProtocol.AspNetCore (C#)2.4.0NuGet, this directory's cs/ project only
@modelcontextprotocol/server-everything2.2.1npm
@modelcontextprotocol/server-filesystem2.2.0npm
@modelcontextprotocol/server-memory2.1.0npm
mcp-server-time2026.11.4PyPI
zod (the TypeScript server's schemas)3.25.76npm
Node22.22.1official tarball when node is not on PATH
Python3.13uv

Layout

  • ours/Server, ours/Client: our fixture server (stdio, ASP.NET Core, built-in listener) and our probe client.
  • ts/, py/, cs/: a probe client and a fixture server on each reference SDK. The fixture is the same everywhere: tools echo, image, slow (progress), wait (until cancelled), confirm (elicitation), the resource mem://hello and the prompt greet.
  • inspector.sh: the Inspector CLI probes; report.mjs: results table.

Notes on observed behaviour

  • The official C# SDK server over HTTP asks the client for input only in its stateful mode (Stateless = false), which negotiates a legacy revision; stateless it answers elicitation with a tool error. The fixture server runs stateful.
  • A server that does not declare a capability is not asked for that list by the generic probe.
  • Python SDK ctx.elicit is a server-to-client request and exists only on legacy sessions; the fixture asks through the SDK's resolver, which works in both eras.

Model Context Protocol® is a registered trademark of LF Projects, LLC. OneModelContext is an independent project and is not affiliated with or endorsed by LF Projects, LLC or the Model Context Protocol project.