Experimental profile · v0.1.0-rc1

Preserving Problem Details across OpenAPI→MCP translation

An API can return much more than an error code and a sentence. This project asks whether that machine-readable error meaning survives when an OpenAPI-described operation becomes an MCP tool.

Frozen result: all 11 in-scope cases were classified as LOSS for each of three tested translation architectures. A constructive mapping over the tested official MCP 2026-07-28 client/server path preserved all 11, and a fresh-install RC1 reproduction produced the same preserving result.

What is being preserved?

HTTP status codes are useful, but they do not fully describe an application error. RFC 9457 Problem Details gives an API a standard machine-readable object for carrying the identity of a problem, a particular occurrence, human-facing text, an optional body status, and application-specific extension data.

Those distinctions can matter to software. Two failures may share the same HTTP status but represent different problem types. An instance can identify one occurrence. Nested extensions can carry validation details. The HTTP response might report 502 while the Problem Details body contains status: 503. Human text may be localized while the machine identity remains the same.

If translation keeps only “the call failed,” or places the original object inside diagnostic prose that software must read heuristically, the error has not been preserved in the sense tested here. The profile requires the source semantics to remain deterministically recoverable by a machine without natural-language interpretation.

The rule

No silent loss + no unsupported gain.

A representation may change on the way to MCP. Exact source bytes do not need to survive. What matters is that the semantics exercised by the profile remain machine-addressable and that the translator does not add machine claims the source did not support.

The rule is carrier-neutral. Structured content, metadata, an explicitly typed embedded serialization, or another unambiguous machine carrier can qualify. JSON-looking text in an error message does not qualify merely because a person or an LLM could reconstruct it.

The frozen 12-case profile

The corpus was fixed around distinctions that matter to machine consumers of Problem Details. It checks:

One case uses ordinary application/json rather than application/problem+json and is intentionally outside the profile. The other 11 cases are evaluated by the same frozen carrier-neutral adapter and oracle.

Results

Target / control Preserved Loss Invented N/A FastMCP 3.4.7 0 11 0 1 CNOE openapi-mcp-codegen 0 11 0 1 nihal1294/openapi-to-mcp 0 11 0 1 Constructive reference over MCP 2026-07-28 wire 11 0 0 1 RC1 fresh-install reproduction 11 0 0 1

The three translator targets reached the same bounded verdict pattern, but the loss occurred in different places.

Where the tested translations lost meaning

FastMCP 3.4.7

On the tested official-package path, a 200 JSON success from the generated tool remained available as structured content. The non-2xx Problem Details response was parsed, but the source Problem Details object reached the MCP side only through diagnostic error text, with no accepted machine-addressable carrier for the profile to recover.

CNOE openapi-mcp-codegen

The frozen target was pinned at commit d0d9e1d848c5705d9bfb1f58a82a7e653c9c85c2. Its generated API client retained the upstream non-2xx JSON internally under details. The generated MCP tool then discarded those details and returned a generic structured error before the MCP result boundary.

The generated server uses FastMCP as a runtime dependency, so these are not presented as two completely independent MCP runtimes. The CNOE loss observed here was localized earlier, in generated translation code before that runtime boundary.

nihal1294/openapi-to-mcp

The frozen target was pinned at commit e5fbb3524384f7dd3367cec3b02b7982cddac614. It exposed richer structured error metadata, but the source Problem Details semantics exercised by the profile still could not be recovered through the accepted machine carriers. Structured target errors, by themselves, were therefore not enough.

A non-standard top-level meta.error.retryable=true also appeared in P12. The frozen claim ledger records it as an adjacent finding rather than an oracle INVENTED verdict.

A preserving translation

The constructive reference tested a different question: was the loss unavoidable because the tested MCP carrier could not represent these semantics?

The reference carried the Problem Details object as an explicitly typed application/problem+json embedded MCP resource and kept observed HTTP transport facts separately in namespaced metadata. That preserved, among other distinctions, an observed HTTP 502 alongside a Problem Details body reporting 503. It also avoided inventing retryability when the source supplied no accepted basis for it.

Across an official MCP 2026-07-28 TypeScript client/server stdio path, the same corpus, adapter, and oracle produced 11 PRESERVED, 0 LOSS, 0 INVENTED, and 1 NOT_APPLICABLE. A text-only version of the same Problem Details object remained LOSS, which served as a negative control against treating diagnostic text as machine-addressable preservation.

Fresh-install reproduction

RC1 repeated the constructive path from a fresh exact-lock dependency materialization and rebuild. It began without prior node_modules or compiled output, used a new empty npm cache, started fresh fixture, server, and client processes, negotiated MCP 2026-07-28, and again produced 11 PRESERVED, 0 LOSS, 0 INVENTED, and 1 NOT_APPLICABLE. The text-only demotion control remained LOSS.

The fresh run strengthens reproducibility of that constructive existence result. It is not another sampled translator and does not turn one clean-room reproduction into a cross-platform or multi-laboratory result.

Result

For the frozen profile tested here, semantic loss is not forced by the tested MCP carrier capacity.

The constructive control shows that the exercised RFC 9457 semantics can cross the tested official MCP protocol boundary while remaining machine-addressable. The losses observed in the three translator targets therefore are not explained by an inability of that tested MCP data model and SDK path to carry the same semantics.

Where the profile stops

This is a bounded conformance experiment, not a survey of the entire OpenAPI-to-MCP ecosystem. The 12 cases do not exhaust RFC 9457, the three translator targets are not a statistical sample, and the reference mapping does not make EmbeddedResource the only valid preservation strategy. The experiment does not show that MCP cannot carry structured errors, certify every retry policy, establish downstream user harm or agent misbehavior, or define an accepted MCP, IETF, or industry standard.

Frozen record and reproducibility

The archived release candidate is fixed independently of this website page. Its repository contains the normative experimental profile, frozen corpus and oracle, immutable evidence assets, constructive reference, clean-room provenance, claim ledger, and dependency-free release verifier.

The release can be checked with python3 verify_release.py. The verifier uses only the Python standard library and checks the frozen semantic core, result summaries, clean-room provenance, evidence-derived process topology, ledger count, and public-source manifest.

Version
v0.1.0-rc1
Release commit
07bcc4d7b13402c120fb26d28a35f1af5a271f61
Version DOI
10.5281/zenodo.21911147
All-versions DOI
10.5281/zenodo.21911146
Release ZIP SHA-256
f1a7dbddbeecb1cee1cdc84f34ff89b99c653267a10cfb51ebc8bfdf4df9b158
Status
Experimental release candidate

Source record