feat(binding-mcp-openapi): implement mcp_openapi proxy binding#1891
Open
jfallows wants to merge 7 commits into
Open
feat(binding-mcp-openapi): implement mcp_openapi proxy binding#1891jfallows wants to merge 7 commits into
jfallows wants to merge 7 commits into
Conversation
Add the mcp_openapi proxy binding, a composite config-generation-only
binding that compiles OpenAPI specs read from catalogs into mcp_http
binding configuration. For each routed operation it generates the
mcp_http options.tools/resources, input/body/output schemas, and route
with clauses (:method/:scheme/:authority/:path with ${args.}/${params.}
interpolation), wiring a single generated namespace whose mcp_http0
routes exit sys:http_client.
The binding adds no protocol hot-path code: a 1:1 mcp->mcp relay forwards
frames into the generated mcp_http0 binding, which provides all runtime
behavior. Reuses binding-openapi's OpenapiParser and views for spec
parsing (exporting its internal.view package).
Closes #1673
…e IT Make the generated mcp_http route exit a configuration property (zilla.binding.mcp.openapi.http.client.exit, default sys:http_client) threaded through the factory into the composite generator, so an IT can redirect it to a k3po-backed binding. Add McpOpenapiProxyIT exercising the full pipeline end-to-end through a live engine: mcp tools/call -> generated mcp_http -> external http0, asserting the derived HTTP request and the projected tool result. Align the create.pr mcp scripts with mcp_http's actual no-summary output (content text is the compact projected JSON). Revert the exports of binding-openapi internal.view added earlier; reuse those views the same way binding-openapi-asyncapi does (classpath compile with the existing opens), no export required.
Add live-engine and peer ITs for resources/read (${params.x} capture from
the resource uri template) and for tools/list and resources/list answered
from the generated mcp_http config, covering the resource and discovery
paths end-to-end.
Make the generated tool input schema deterministic by emitting requestBody
properties in sorted order (the OpenAPI view's property map is unordered),
so tools/list output is stable across runs.
Add create.pr.10k (fragmented request body exercising DATA/WINDOW relay through the bridge), create.pr.aborted (ABORT propagation), and create.pr.error (upstream 422 surfaced as an isError tool result) across the mcp and http streams, with peer ITs and live-engine ITs, to meet the required protocol coverage (flow control, abortive close, protocol error).
Add generator unit tests for the remaining wired paths: tool schemas.output override, query-parameter interpolation into the generated :path, and aggregation of multiple specs into a single composite namespace with per-tool input subjects.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1673
Summary
Implements the
mcp_openapi · proxybinding: a composite, config-generation-only binding that reads OpenAPI specs from catalogs and compiles each routed operation intomcp_http(#1675) configuration. It adds zero protocol hot-path code — alltools/*andresources/*behavior and response projection are provided by the generatedmcp_http. This lets an MCP agent invoke any OpenAPI-described REST API as MCP tools/resources, configured entirely inzilla.yaml, with a single spec parse.Accepts
mcp, produceshttp. Modeled on the existingbinding-openapi(client) composite.How it works
EngineContext.attachComposite) holding an inlinecatalog0+ onemcp_http0binding whose routesexitthe configured HTTP client. Because the exit's:authority/:schemecome from each spec'sservers, all routed operations across all specs aggregate into that one namespace.McpOpenapiProxyFactoryrelaysmcpframes straight into the generatedmcp_http0— no per-operation dispatch, no new.idl.tool/resource): flattened<tool>-inputschema (path/query params ∪ requestBody properties,_bodysuffix on collisions, union ofrequired),<tool>-bodyprojection,<tool>-output(full success-response schema, overridable viaoptions.tools.<tool>.schemas.output), and routewith.headers(:method/:scheme/:authority/:pathwith${args.…}for tools and${params.…}for resources, query params appended to:path).Configurable exit
The generated
mcp_httproute exit is the engine propertyzilla.binding.mcp.openapi.http.client.exit(defaultsys:http_client), so deployments can target the global system HTTP client and ITs can redirect it to a test endpoint.Reuse
Reuses
binding-openapi'sOpenapiParserandOpenapi*Viewmodel for spec parsing rather than re-implementing it — the same waybinding-openapi-asyncapialready consumes those views (classpath compilation + the existingopens; no newexports). Follow-ups #1889 / #1890 propose hoisting the OpenAPI/AsyncAPI model/view/parser APIs into dedicatedruntime/common-*modules to formalize this reuse.Testing
Test-first, mirroring
binding-mcp-http. All green; full reactorclean installpasses (only the Docker-image packaging step is skipped — it requires a Docker daemon unavailable in CI-less local runs).SchemaTest(valid + invalid configs) and peer.rptITs (McpServerIT,HttpClientIT).McpOpenapiProxyIT, driving the generated composite through a real engine): tool call, resource read (${params.…}capture),tools/list+resources/listdiscovery, flow control (~10 KB fragmented body), abort propagation, and upstream-error (isError) passthrough._bodycollision, deterministic property order,:scheme/:authority/:pathderivation,schemas.outputoverride, query-parameter interpolation, and multi-spec aggregation.Notes
runtime/binding-mcp-openapiandspecs/binding-mcp-openapi.spec, registered in the runtime/specs/root poms.binding-openapibehavior; the only edit there was reverting a strayinternal.viewexport so view reuse matches thebinding-openapi-asyncapiprecedent.https://claude.ai/code/session_013Li1mTsigtRqijhbtm4Xp5
Generated by Claude Code