Skip to content

feat(mcp): expose REST APIs as MCP tools from an OpenAPI spec (type: openapi) - #840

Merged
jarvis9443 merged 1 commit into
mainfrom
feat/openapi-mcp-1077
Jul 29, 2026
Merged

feat(mcp): expose REST APIs as MCP tools from an OpenAPI spec (type: openapi)#840
jarvis9443 merged 1 commit into
mainfrom
feat/openapi-mcp-1077

Conversation

@jarvis9443

@jarvis9443 jarvis9443 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What

A registered mcp_server can now be backed by a plain REST API instead of a real MCP upstream. Setting type: openapi plus an OpenAPI 3.x document under spec makes the gateway generate one MCP tool per operation and execute tools/call as an HTTP request against the resource's url (the REST base URL). The gateway-held credential — bearer, api_key (default x-api-key header, overridable via the new api_key_header field), or oauth2 client credentials through the existing token cache — is injected on every outbound request and never exposed to the calling agent.

How

  • aisix-core: McpServer gains type (mcp | openapi, default mcp — existing rows are untouched), spec, and api_key_header; resource JSON schema regenerated.
  • aisix-mcp: new openapi module with an OpenApiBridge implementing the existing McpBridge trait; McpGateway::from_snapshot picks the bridge per type. Because the bridge sits behind the same surface, existing governance — approval gating, per-tool ACLs / MCP policies, per-(key × server) rate limits, guardrails, usage events — applies to generated tools unchanged.
  • Tool generation follows LiteLLM's openapi_to_mcp_generator (sanitized operationId names capped at 128 chars, fallback method_path, path/query params as schema properties, JSON request body as one body property), with deliberate improvements:
    • bounded local $ref resolution (depth 16, 256 expansions, cycle-safe) so referenced schemas keep their shape;
    • non-2xx responses and argument mistakes (e.g. a missing path parameter) return tool-level isError results the agent can react to;
    • operations whose request body has no application/json variant are skipped rather than emitting a tool that cannot succeed;
    • header/cookie parameters are not exposed to the agent (upstream headers are the gateway's to set);
    • path parameter values are rejected on traversal (/, \, ., ..) and percent-encoded.
  • Admin API writes validate strictly via the new aisix_mcp::validate_spec: missing/non-object spec, Swagger 2.0 (with a conversion hint), zero generatable operations, duplicate post-sanitization tool names, and api_key_header coupling all fail with a message naming the problem. Snapshot loading stays permissive: a broken row degrades like an unreachable upstream (tools absent, warning logged) instead of poisoning the snapshot.

Behavior notes

  • Redirects are not followed on generated tool calls, so the gateway-held credential cannot be re-sent to a host the operator never configured.
  • An upstream 401 under oauth2 invalidates the cached token so the next call re-mints (mirrors the MCP connect path).

Tests

  • Unit: generator (names, collisions, $ref/cycles, skips, schemas), URL building/traversal, query/body coercion, strict validate_spec, admin coupling.
  • Crate integration (tests/openapi_tool_roundtrip.rs): real axum REST API + full gateway over Streamable HTTP driven by an rmcp client — list/call, auth injection for both bearer and custom-header api_key, error surfacing, broken-spec degradation next to a healthy server.
  • E2E (tests/e2e/src/cases/mcp-openapi-e2e.test.ts): real aisix binary + etcd + fake ERP REST upstream — generated tool discovery with spec-derived schemas, GET/POST execution with gateway-held auth, non-2xx and missing-param error results, and per-tool ACL enforcement on generated tools.

Fixes api7/AISIX-Cloud#1077 (control-plane exposure ships as a paired AISIX-Cloud PR; docs as a paired api7/docs PR)

…openapi)

A registered mcp_server can now be backed by a plain REST API instead of a
real MCP upstream: 'type: openapi' plus an OpenAPI 3.x document in 'spec'
makes the gateway generate one tool per operation and execute tools/call as
HTTP requests against 'url', with the gateway-held credential injected
(bearer / api_key with an optional api_key_header override / oauth2 client
credentials) and never exposed to the calling agent.

Generation follows LiteLLM's openapi_to_mcp_generator for familiarity:
sanitized operationId tool names (fallback method_path, _2/_3 suffixes on
collisions at runtime), path/query parameters as schema properties, a JSON
request body as a single 'body' property. Beyond the baseline: bounded local
$ref resolution keeps referenced schemas' shape, non-2xx responses and
argument mistakes surface as tool-level isError results, operations whose
body has no application/json variant are skipped instead of emitting a
broken tool, and header/cookie parameters are never exposed to the agent.

The Admin API validates strictly at write time (missing/invalid spec,
Swagger 2.0, zero generatable operations, duplicate sanitized tool names,
api_key_header coupling) via the new aisix_mcp::validate_spec; snapshot
loading stays permissive and degrades a broken row like an unreachable
upstream. Existing governance — approval flow, per-tool ACLs, per-server
rate limits, guardrails — applies unchanged since the openapi bridge sits
behind the same McpBridge surface.

Ref api7/AISIX-Cloud#1077
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 12 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dde9fbd6-38d5-4917-8d9a-c035b6ea0b40

📥 Commits

Reviewing files that changed from the base of the PR and between a259eac and e89ed65.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • Cargo.toml
  • crates/aisix-admin/Cargo.toml
  • crates/aisix-admin/src/mcp_servers_handlers.rs
  • crates/aisix-core/src/lib.rs
  • crates/aisix-core/src/models/mcp_server.rs
  • crates/aisix-core/src/models/mod.rs
  • crates/aisix-core/src/models/schema.rs
  • crates/aisix-mcp/Cargo.toml
  • crates/aisix-mcp/src/bridge.rs
  • crates/aisix-mcp/src/gateway.rs
  • crates/aisix-mcp/src/lib.rs
  • crates/aisix-mcp/src/openapi.rs
  • crates/aisix-mcp/tests/openapi_tool_roundtrip.rs
  • schemas/resources/mcp_server.schema.json
  • tests/e2e/src/cases/mcp-openapi-e2e.test.ts
  • tests/e2e/src/harness/index.ts
  • tests/e2e/src/harness/upstream-rest.ts

Comment @coderabbitai help to get the list of available commands.

@jarvis9443

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jarvis9443
jarvis9443 merged commit 52ee9eb into main Jul 29, 2026
10 checks passed
@jarvis9443
jarvis9443 deleted the feat/openapi-mcp-1077 branch July 29, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant