nevzheng opened a new issue, #12530:
URL: https://github.com/apache/gravitino/issues/12530

   ### Version
   
   `main branch`
   
   ### Describe what's wrong
   
   The Gravitino MCP server accepts a Bearer token via `--token` / 
`GRAVITINO_TOKEN` and freezes it at process start. The token has a TTL set by 
the identity provider. Once it expires, every MCP tool call that reaches 
Gravitino returns HTTP 401 and stays 401 until a human pastes a new token and 
restarts the MCP process. There is no way for the MCP server to obtain or 
refresh a token itself.
   
   Gravitino already validates OAuth JWTs, and the Java/Python clients already 
perform `client_credentials` against the same IdP. The MCP server is the only 
client in this flow that cannot fetch or refresh a service token, so 
long-running MCP sessions (e.g. Cursor) break on token expiry with no 
self-service recovery.
   
   ### Error message and/or stacktrace
   
   No crash. Symptom is repeated Gravitino 401s from MCP tool calls after the 
configured Bearer's TTL elapses:
   
   ```
   HTTP 401 Unauthorized  (from Gravitino on every tool call after token expiry)
   ```
   
   Recovery today requires manually replacing `--token` / `GRAVITINO_TOKEN` and 
restarting the MCP process.
   
   ### How to reproduce
   
   1. Start the Gravitino MCP server with `--token <jwt>` (or 
`GRAVITINO_TOKEN=<jwt>`), where the JWT has a short `exp` (e.g. 60–120s).
   2. From an MCP client (Cursor stdio, or HTTP without an incoming 
`Authorization`), call any tool that hits Gravitino. Observe it works until 
`exp`.
   3. Wait past `exp`. Call the same tool again. Gravitino returns 401 and 
continues to return 401 for every subsequent call.
   4. The MCP server never re-fetches or refreshes the token; only a restart 
with a new `--token` recovers it.
   
   ### Additional context
   
   Proposed direction (for the PR): give the MCP server an OAuth 
`client_credentials` service-identity path alongside the existing `--token`. 
Hop-2 Authorization precedence would be: incoming HTTP `Authorization` (forward 
as-is) > `--token` / `GRAVITINO_TOKEN` (static, wins over OAuth) > OAuth 
`client_credentials` (fetched, cached, refreshed) > anonymous. Token POST uses 
`client_secret_post` (form body), matching the Java/Python clients. Cache with 
early-expiry skew; fall back to JWT `exp` when the IdP omits `expires_in`; one 
retry on Gravitino 401. Gravitino remains the authenticator/authorizer; MCP 
only attaches `Authorization`. No identity provider is added.
   
   Nevin
   Sent from my 🤖 (Cursor)


-- 
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