Scope
Implement both OAuth 2.1 grant types per RFC 6749 and MCP 2.1 spec:
- Authorization Code + PKCE (RFC 7636): For user-delegated access (interactive, requires browser)
- Client Credentials (RFC 6749 §4.4): For machine-to-machine access (non-interactive, no user consent)
Haystack MCP Integration Details
OAuthConfig Design:
- Add
oauth_config: Optional[OAuthConfig] field to StreamableHttpServerInfo and SSEServerInfo
OAuthConfig must support to_dict()/from_dict() for serialization (using Haystack's Secret handling)
- Token storage should be configurable (
InMemoryTokenStorage or FileTokenStorage)
- Default to
FileTokenStorage for persistence across tool instances
Flow Selection Logic:
- Auto-detect grant type based on configuration:
- If
client_secret is provided AND no redirect_uri → use Client Credentials
- Otherwise → use Authorization Code + PKCE (default)
- Allow explicit
grant_type parameter for manual override
- Validate that Client Credentials flow doesn't require
redirect_uri
Token Injection:
- OAuth tokens should be injected into
server_info.headers["Authorization"] (takes precedence over token field)
- This ensures compatibility with existing
StreamableHttpClient and SSEClient header handling
- Token should be cached and reused across tool invocations
Integration with Connection Lifecycle:
- OAuth should be checked in
ensure_oauth(server_info) function
- Called from:
MCPTool.__init__() if eager_connect=True
MCPTool.warm_up() if eager_connect=False
MCPToolset._connect_and_load_tools() (always, before connection)
- OAuth flow should be synchronous (blocking) since it's called from sync context
- Use
AsyncExecutor for any async OAuth operations if needed
Requirements
References
Scope
Implement both OAuth 2.1 grant types per RFC 6749 and MCP 2.1 spec:
Haystack MCP Integration Details
OAuthConfig Design:
oauth_config: Optional[OAuthConfig]field toStreamableHttpServerInfoandSSEServerInfoOAuthConfigmust supportto_dict()/from_dict()for serialization (using Haystack'sSecrethandling)InMemoryTokenStorageorFileTokenStorage)FileTokenStoragefor persistence across tool instancesFlow Selection Logic:
client_secretis provided AND noredirect_uri→ use Client Credentialsgrant_typeparameter for manual overrideredirect_uriToken Injection:
server_info.headers["Authorization"](takes precedence overtokenfield)StreamableHttpClientandSSEClientheader handlingIntegration with Connection Lifecycle:
ensure_oauth(server_info)functionMCPTool.__init__()ifeager_connect=TrueMCPTool.warm_up()ifeager_connect=FalseMCPToolset._connect_and_load_tools()(always, before connection)AsyncExecutorfor any async OAuth operations if neededRequirements
OAuthConfigdataclass with:client_idandclient_secret(optional,Secret-compatible)redirect_uri(for Authorization Code flow, default:http://localhost:8080/callback)grant_type(optional, auto-detected if not specified)scopes(optional list)token_storage(default:FileTokenStorage)on_authorization_urlcallback hook (for customizing auth URL presentation)authorization_server_url(optional, for skipping discovery)authorization_endpointandtoken_endpoint(optional, for manual configuration)response_type=code,code_challenge,code_challenge_method=S256)code_verifier)access_token,refresh_token,expires_inresourceparameter in token request (per MCP spec)client_idandclient_secrettoken_endpointwithgrant_type=client_credentialsresourceparameter in token request (per MCP spec)TokenStorageabstract base classInMemoryTokenStorage(tokens lost on process exit)FileTokenStorage(persist to~/.mcp/tokens/with secure permissions)ensure_oauth(server_info: MCPServerInfo)function:oauth_configis present and transport is HTTPserver_info.headers["Authorization"]OAuthConfigtoStreamableHttpServerInfoandSSEServerInfo:oauth_config: Optional[OAuthConfig] = Nonefieldto_dict()/from_dict()to handleOAuthConfigserializationSecretobjects inOAuthConfigare properly serializedReferences