apache / apache/polaris-tools

FastMCP HTTP/SSE transport does not forward incoming request headers (e.g. Authorization) to the Polaris backend

Open
#197 6 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
33
Forks
46
Avg merge
1d 4m
Merged PRs (30d)
2

Description

When the MCP server is running in `http` or `sse` transport mode, incoming HTTP headers from the client request are **never extracted or forwarded** to the backend Polaris REST API. This makes it impossible to deploy the MCP server behind an authenticating reverse proxy (e.g. OAuth2 Proxy) and have the proxy-injected `Authorization` header passed through to Polaris.

### Use Case Scenario

```
Client → OAuth2 Proxy → Polaris MCP Server (http transport) → Polaris Server (external IDP)
```

1. The MCP server is deployed **without its own auth** (`POLARIS_CLIENT_ID` / `POLARIS_CLIENT_SECRET` are not set; the Polaris server has client credentials disabled).
2. An authenticating reverse proxy (e.g. [OAuth2 Proxy](https://oauth2-proxy.github.io/oauth2-proxy/)) sits in front of the MCP server.
3. The proxy handles the OAuth2/OIDC redirect flow with the external Identity Provider and injects an `Authorization: Bearer ` header into every request forwarded to the MCP server.
4. The MCP server should forward that `Authorization` header to the backend Polaris server, which validates the token against the same external IDP.

**This flow currently does not work** because the MCP server never reads headers from the incoming HTTP request.

### Current Behavior

The auth resolution in `server.py` (`_resolve_authorization_provider`) only considers:

1. **Static tokens** from env vars (`POLARIS_API_TOKEN`, `POLARIS_BEARER_TOKEN`, `POLARIS_TOKEN`)
2. **OAuth2 Client Credentials** from env vars (`POLARIS_CLIENT_ID` + `POLARIS_CLIENT_SECRET`)
3. **Realm-specific credentials** from `POLARIS_REALM_*` env vars

If none of these are set, the `AuthorizationProvider` resolves to `none()` — no `Authorization` header is added to outbound requests, and the incoming HTTP-layer `Authorization` header is silently dropped.

The `headers` parameter on each tool function (e.g. `polaris_iceberg_table`) only accepts headers passed **as MCP tool arguments by the LLM client**, not headers from the HTTP transport layer.

---

We should be able to use the `get_http_headers` from fast mcp in `RestTool::call()`.

Contributor guide

No contributing guide indexed for this repository

Research direction

Trace the HTTP and SSE request paths in server.py and the RestTool::call() entry point, starting with FastMCP's get_http_headers behavior. Check how _resolve_authorization_provider currently selects credentials and how outbound Polaris REST requests receive headers. Done means an incoming Authorization header is preserved for backend calls in HTTP/SSE mode without breaking the existing token and client-credential paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, typescript
Domain
api, authentication, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.