-
Couldn't load subscription status.
- Fork 6
Add OAuth user context caching + Refresh external tokens #110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
f474c13 to
31d822c
Compare
7ff502b to
a282c2b
Compare
9bf103d to
4e9b05a
Compare
4e9b05a to
644def6
Compare
- Add thread-safe caching to prevent repeated provider API calls - Cache user context with configurable TTL (default 5 minutes) - Implement automatic cleanup of expired cache entries - Add comprehensive logging for cache hits/misses/cleanup - Maintain backward compatibility with existing middleware interface This addresses the performance issue where every MCP tool execution was making HTTP requests to OAuth providers (Keycloak, Google, etc.) to fetch the same user information repeatedly. Performance improvement: ~95% reduction in provider API calls for typical usage patterns within the cache TTL window.
644def6 to
bed1395
Compare
|
|
||
| except Exception as e: | ||
| logger.error(f"Error refreshing external token: {e}") | ||
| return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| user_context = await self.oauth_handler.get_user_context(external_token) | ||
| # Try to get user context from cache first | ||
| cached_user_context = await self._get_cached_user_context( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Race Condition in OAuth User Context Retrieval
Race condition: The code checks if cached_user_context is None and then calls self.oauth_handler.get_user_context() without holding any lock. Multiple concurrent requests for the same token could all see cached_user_context is None and make duplicate API calls to the OAuth provider, defeating the purpose of the cache. The cache lock (self._cache_lock) is only held when reading/writing the cache, not during the actual API call, so multiple requests can race through this section.
Description
Each tool invocation fetches the user context to pass as a parameter. This currently triggers a call to the AS on every request. In this changeset, a five-minute cache is added to minimize remote AS calls.
The changeset also adds the logic to trigger an external token refresh when the external access token expires. This implies a schema change to the OAuth DB. This doesn't implement a schema migration.
We finally set the MCP access token duration to 365 days while the possibility of refreshing isn't provided by the
mcplib.Type of Change
Testing
uv run pytestuv run ruff check .uv run black --check .uv run mypy .Security Considerations
Breaking Changes
No.
Additional Notes
When calling within cache duration, the cache is used:
When the cache is expired, the value is ignored and a call is issued to the external AS:
Here's the log when calling a tool after more than five minutes (cache expiration) and the keycloak access token has expired in the meantime.
Note
Adds cached user context with configurable TTL, background OAuth cleanup, external token refresh with persisted refresh tokens, extends MXCP token TTL to 1 year, and updates config, docs, and tests.
refresh_external_token()with persistedrefresh_token; map and update external tokens on refresh.auth.cleanup_interval(default 300s).DEFAULT_ACCESS_TOKEN_TTL).src/mxcp/sdk/auth/middleware.py):cache_ttl, default 300s), periodic cleanup, and concurrency-safe refresh.get_user_context, caching the result.keycloak,google,atlassian,salesforce; setrefresh_tokenonExternalUserInfo. GitHub remains non-refresh.offline_access.src/mxcp/sdk/auth/persistence.py):refresh_tokeninaccess_tokens; add column and runtime migration; load/store updated.AuthConfigwithcache_ttlandcleanup_interval; addrefresh_tokentoExternalUserInfo.cache_ttlinto server middleware (src/mxcp/server/interfaces/server/mcp.py).mxcp-config-schema-1.json) to includeauth.cache_ttlandauth.cleanup_interval.docs/guides/authentication.md):examples/keycloak/config.ymland remove inline client.tests/sdk/auth/test_middleware.py).Written by Cursor Bugbot for commit 6d820e4. This will update automatically on new commits. Configure here.