fix: MCP tool calls return 404 when ZO_BASE_URI is set (#13844)

Fixes #13845

## What changed

The MCP shared HTTP client (used to execute tool calls against the local
REST API) now includes `ZO_BASE_URI` in its base URL:
`http://localhost:{port}{base_uri}` instead of
`http://localhost:{port}`.

## Why

When `ZO_BASE_URI` is set (e.g. `/abc`), all HTTP routes are mounted
under that prefix. The MCP endpoint itself was reachable (`POST
/abc/api/default/mcp` → 200), but every tool execution failed: the
internal client sent requests to the unprefixed path and got a 404.

```
INFO rmcp_openapi::http_client: Final URL: http://localhost:5080/api/default/streams
INFO config::axum::middlewares::access_log: 127.0.0.1 "GET /api/default/streams HTTP/1.1" 404 ...
```

## Notes for reviewers

- `cfg.common.base_uri` is already normalized at config load to have no
trailing slash (empty when unset), so the empty-prefix behavior is
unchanged.
- The join semantics are safe for path-prefixed base URLs:
rmcp-openapi's `with_base_url` appends a trailing slash and `build_url`
strips the tool path's leading slash before `Url::join`, covered by the
crate's `test_build_url_with_base_url_containing_path`. So `/abc` +
`/api/{org}/streams` → `/abc/api/{org}/streams`.
- The other `localhost:5080` occurrence in `tools.rs` is a test-only
mock client; the OAuth protected-resource metadata handler already
includes `base_uri`.
- `cargo check -p openobserve-mcp` and `cargo test -p openobserve-mcp`
pass.
This commit is contained in:
Hengfei Yang
2026-08-17 11:44:34 +00:00
committed by GitHub
parent 9d76505882
commit 6ca0eec107
+6 -2
View File
@@ -360,8 +360,12 @@ pub fn init_mcp_tools(api: &OpenApi) -> Result<()> {
let spec = rmcp_openapi::Spec::from_value(api_json)?;
let zo_config = config::get_config();
let base_url = url::Url::parse(&format!("http://localhost:{}", zo_config.http.port))
.map_err(|e| anyhow::anyhow!("Invalid base URL: {e}"))?;
// Include ZO_BASE_URI so tool calls hit the routes actually mounted under it
let base_url = url::Url::parse(&format!(
"http://localhost:{}{}",
zo_config.http.port, zo_config.common.base_uri
))
.map_err(|e| anyhow::anyhow!("Invalid base URL: {e}"))?;
// Set default headers including x-o2-mcp for MCP-initiated calls
let mut default_headers = reqwest::header::HeaderMap::new();