jaegertracing / jaegertracing/jaeger

AI gateway: announced turn-scoped MCP URL has no tenant header, so every tool call 401s under multi-tenancy

Open
#9,155 2 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
23.2k
Forks
3.1k
Avg merge
1d 8h
Merged PRs (30d)
93

Description

### What happened?

The AI gateway announces its turn-scoped MCP endpoint to the sidecar with an empty header list:

```go
Http: &acp.McpServerHttpInline{
Type: "http",
Name: mcpServerName,
Url: h.mcpBaseURL + h.basePath + routeMCPPrefix + mcpRouteID + "/",
Headers: []acp.HttpHeader{},
},
```

But that endpoint is served through `mcptools.WrapHTTP`, which wraps the MCP handler in `tenancy.ExtractTenantHTTPHandler`. With multi-tenancy enabled that handler rejects any request without a tenant header:

```go
tenant := r.Header.Get(tc.Header)
if tenant == "" {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("missing tenant header"))
return
}
```

So when `tenancy.enabled: true`, the gateway announces a URL that returns `401 missing tenant header` on every call. The sidecar has no way to supply the header, because the announcement is the only thing that tells it how to dial. Every agent tool call fails for the whole turn.

This is the failure mode the base-URL design explicitly tries to avoid — announcing an address that cannot be used — arrived at from a different direction.

### Steps to reproduce

1. Run jaeger-query with multi-tenancy enabled and the AI gateway configured (`ai.agent_url` + `ai.enable_mcp`, with `ai.mcp_base_url` resolvable).
2. Start a chat turn with a sidecar that advertises `mcpCapabilities.http`.
3. The sidecar dials the announced `/api/ai/mcp//` and gets 401.

### Expected behavior

Either the announced endpoint is dialable under multi-tenancy, or nothing is announced so the turn degrades to no tools rather than failing every call.

### Possible fix

**Propagate the tenant header.** `tenancy.Manager` exposes `Enabled` and `Header`, and `tenancy.GetTenant(ctx)` recovers the tenant the chat request arrived with (`initRouter` already wraps the gateway in `ExtractTenantHTTPHandler`), so the value is available at announce time. `acp.McpServerHttpInline.Headers` exists for exactly this. Requires threading the tenancy manager into `chatEndpoint` and passing the request context into `announceMCP`. Worth deciding deliberately, since it hands the tenant identity to the sidecar to replay back.

### Additional context

Found while reviewing #9009, which is what makes the endpoint reachable in the first place — the endpoint has been dormant until now, so this could not have been hit before. Part of the RFC 0008 tool-routing work (#8890).

Contributor guide

Open the contributing guide

Research direction

Start at chatEndpoint and announceMCP, then trace initRouter's tenancy.ExtractTenantHTTPHandler and the mcptools.WrapHTTP path that serves the announced URL. Decide whether to propagate tenancy.GetTenant(ctx) through the announcement or suppress it when unusable; done means the announced endpoint works under multi-tenancy or the turn safely exposes no tools.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.