davsclaus opened a new pull request, #29284: URL: https://github.com/apache/camel/pull/29284
Fixes [CAMEL-26359](https://issues.apache.org/jira/browse/CAMEL-26359). ## What was wrong The MCP streamable HTTP transport says a server must validate the `Origin` header, and answer HTTP 403 when it is present and not valid (the body may be a JSON-RPC error response without an `id`). The Vert.x engine of `camel-mcp-server` (Camel Main and Camel JBang) did not look at `Origin` at all. The platform-http CORS handler only adds response headers and does not refuse anything. ## What changed This implements the proposal in the JIRA for the Camel Main engine: - Every request on the MCP endpoint (`POST`, the SSE `GET` and `DELETE`) goes through an origin check first. On `POST` it runs before the body is read. - A request **without** an `Origin` header is served as today (MCP clients run as a process and send none). - A request **with** an `Origin` header is served only when the origin is allowed. Anything else gets HTTP 403 with `{"jsonrpc":"2.0","error":{"code":-32600,"message":"Origin not allowed"}}`, and no tool or resource route is called. - New option `camel.server.mcp-allowed-origins`: a comma-separated list of origins. Each entry is an exact origin or ends with `:*` for any port. When not set, only loopback origins are allowed: `localhost`, `127.0.0.1` and `[::1]`, over `http` or `https`, any port. - The matching is the `DefaultServerTransportSecurityValidator` of the MCP Java SDK 2.1.0 (the same check its servlet transport offers), wired in as a Vert.x handler. The check is independent of the CORS configuration. - Plumbing: `HttpServerConfigurationProperties.mcpAllowedOrigins` (camel-main) -> `McpServerConfiguration.allowedOrigins` -> `McpServerInfo.allowedOrigins()` -> `VertxMcpStreamableServerTransportProvider`. `McpServerInfo` keeps its previous 10-argument constructor. An engine that does not consume the serving configuration (Spring Boot, Quarkus) logs a WARN when the option is set, as for the path option. - `JbangDevMcpServer` uses the same engine, so it gets the loopback default. ## Tests - `VertxMcpOriginTest` (new): no `Origin`; loopback origins (`http://localhost`, `:6274`, `https://localhost:8443`, `127.0.0.1`, `[::1]`); rejected origins (`http://app.example.com`, `https://localhost.example.com`, `http://127.0.0.2:8080`, `null`) with the 403 JSON-RPC body and no session; configured origins replacing the default (exact and `:*`); a `tools/call` from a rejected origin does not call the tool; the SSE `GET` and `DELETE` are checked. - `McpServerMainPropertiesTest.testMcpAllowedOriginsFromProperties` (new): the option set through `camel.server.mcp-allowed-origins` on Camel Main. - `McpServerBridgeTest`: the option is parsed (trimmed, trailing `/` dropped, empty entries skipped) and passed to the engine; not set means the engine default. - The new HTTP tests failed before the fix (8 failures, 1 error with the `src/main` changes of camel-mcp-server reverted). - camel-mcp-server: 74 tests + 19 ITs pass; camel-mcp-server-api: 37 tests pass. ## Docs and generated files - `mcp-server.adoc`: the option in the options table, a line in the protocol section, and a new "Origins and binding" section (allowed origins, CORS, binding to `127.0.0.1`, stdio not affected). - 4.24 upgrade guide: entry under `camel-mcp-server`, since a browser-based client served from a non-loopback origin now gets 403 until it is listed. - Regenerated camel-main (configurer, metadata JSON, `main.adoc`) and the catalog copies (`main.adoc`, `mcp-server.adoc`, `camel-main-configuration-metadata.json`). ## Not changed - Spring Boot and Quarkus engines: separate parity ticket CAMEL-26360. - The `Host` header is not checked; the JIRA proposal covers `Origin` only. - Stdio mode has no HTTP and is not affected. ## Related PR #29186 (CAMEL-26358, official MCP conformance suite) lists `dns-rebinding-protection` in its `expected-failures.yaml`. That scenario sends `Origin: http://evil.example.com` and expects a 4xx, then a loopback origin and expects 2xx. With this change it should pass, so whichever PR merges second needs to drop that entry (its stale-baseline check would otherwise fail under `-Poc`). The suite runs only with `-Poc`, so normal CI is not affected. _Claude Code on behalf of Claus Ibsen (davsclaus)_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
