ADR 0048 — Framework-owned native MCP registration
- Status: Superseded by ADR 0057. It extends the transport parity of ADR 0014, the stable operation identity of ADR 0022, and per-call isolation from ADR 0045
- Date: 2026-08-07
Context
Contract tools run through stitchkit’s input/output validation, lifecycle,
isolated request context and observability hooks. Native MCP tools exist because
some operations must return MCP content blocks directly, but the existing
nativeTools(server, auth) callback exposes only raw SDK registration. A raw
callback cannot acquire those framework guarantees, regardless of whether it is
invoked before or after contract mounting.
Forcing multimodal operations into JSON contracts would corrupt their result model. A second standalone mount helper would create two framework-owned native paths and make configuration parity optional.
Decision
nativeTools receives one NativeMcpRegistrar and the resolved build identity.
The registrar exposes:
registerTool(definition)— the canonical protected path;rawServer— the explicitly named SDK escape hatch, with no stitchkit lifecycle, validation, per-call context or tool hooks.
A native definition owns its MCP schema and one OperationIdentity
(serviceName, action, scope, semantic method and metadata). Contract
MethodDef extends the same path-free identity; only HTTP methods own path.
Tool lifecycle and observability consume OperationIdentity, so no fake HTTP
route is invented for a native operation.
Framework registration uses the same schema preparation profile as contract
tools and the same execution envelope. Successful native results remain MCP
results: text/image/audio/resource blocks and _meta pass through untouched.
When an output schema is declared, only structuredContent is parsed by it and
the parsed payload replaces that field; other MCP result fields are preserved.
The SDK still parses advertised input before invoking the callback. An SDK-level
InvalidParams rejection therefore cannot enter stitchkit hooks; this boundary
is documented rather than represented as audited.
Consequences
- Native multimodal tools can receive the same RBAC, audit and per-call isolation guarantees as contract tools.
- Raw registration remains possible, but opting out is visible in code.
nativeToolsis a breaking callback-shape change in 0.37.0; there is no alias or server-like compatibility wrapper.OperationIdentitybecomes the public endpoint type for tool hooks andToolLifecycle. Existing contract callbacks still receive all prior fields at runtime; code that assumed every tool endpoint has an HTTPpathmust narrow toMethodDef.- Stateful HTTP, stateless HTTP and stdio share the same server builder, so the registrar cannot drift by transport.