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]

Reply via email to