Authenticate to an MCP server with OAuth 2.1
Psych gives the official MCP Python SDK a scope-isolated token store, resolved client secrets, an egress check, and the host application's browser callback. The SDK handles...
Psych gives the official MCP Python SDK a scope-isolated token store, resolved client secrets, an egress check, and the host application's browser callback. The SDK handles protected-resource and authorization-server discovery, PKCE, token exchange, refresh, and scope step-up.
Registered client credentials
psych_runtime.McpServer(
name="records",
url="https://mcp.example.com/records",
oauth=psych_runtime.McpOAuth(
grant="client_credentials",
preregistered_client_id="psych-service",
client_secret_credential="records-oauth-secret",
issuer="https://auth.example.com",
),
)client_secret_credential is a secret name resolved through the configured
SecretResolver. It is never the secret value. Set issuer to the
authorization server that registered the client. This is the recommended
machine-to-machine configuration and uses the SDK's
ClientCredentialsOAuthProvider.
Authorization code
psych_runtime.McpServer(
name="calendar",
url="https://mcp.example.com/calendar",
oauth=psych_runtime.McpOAuth(
grant="authorization_code",
preregistered_client_id="psych-local",
redirect_uris=("http://127.0.0.1:8080/oauth/callback",),
),
)Authorization code requires an AuthorizationRedirectPort. Psych owns no HTTP
server and opens no browser, so the host application presents the SDK's
authorization URL and returns the callback. The SDK creates and validates PKCE,
exchanges the code, refreshes tokens, and handles insufficient_scope step-up.
Wire the OAuth adapter
from psych_runtime.tools.mcp import McpPool
from psych_runtime.tools.oauth import OAuthClient
oauth = OAuthClient(transport=oauth_transport, redirect=redirect_port)
pool = McpPool(transport=mcp_transport, secrets=secrets, oauth=oauth)Construct one OAuthClient per process. Its stores are keyed by tenant,
principal, resource, and grant identity. A token refresh never changes the MCP
pool key. McpPool.evict_server clears the connection and its stored OAuth
state together.
Compatibility configurations
Client credentials obtained through dynamic client registration or a Client ID Metadata Document use Psych's compatibility flow because the SDK's client credentials provider requires an already registered client ID and secret. MCP protocol traffic still runs through the official SDK.
Code execution changes nothing here
A sandboxed program calling an MCP tool uses the pooled connection this Scope already holds, with the authorization that connection already carries. The exchange, the refresh and the retry all happen on the host.
No token, refresh token, client secret, transport object or authenticated URL crosses into the sandbox. A program sends a tool name and JSON arguments and receives a result; it has no way to ask for a credential and nothing to ask.
Rules
- Put only secret names in a Spec.
- Use authorization code when access represents a person.
- Use registered client credentials plus an explicit issuer for service access.
- Keep the token store isolated by
Scope; never pool by URL alone. - Treat
AuthorizationRedirectPortas a host application boundary. https://only, except loopback. The resource URI, the metadata URL a 401 challenge names, the authorization servers a resource document lists and every endpoint an authorization server advertises must behttps://. A plainhttp://anywhere in that chain isInvalidCanonicalUriorDiscoveryError, never a request carrying a token.localhostand loopback addresses are exempt for development servers and test stubs.- Dynamic Client Registration asks for
token_endpoint_auth_method="none"by default (ClientIdentityConfig.token_endpoint_auth_method), registering a public client and discarding any secret the server returns anyway. A server-side deployment that can keep a secret setsclient_secret_basicand the issued secret is then used at the token endpoint. - Discovery documents are bounded. Everything read through
HttpTransport.requestis refused past 16 MiB; seepsych-multitenancy.
Connect MCP servers
An McpServer in a Spec is data. The tools it contributes are discovered from the server, never declared in the Spec.
Work with other agents over A2A
Psych speaks A2A v1.0 (April 2026, Linux Foundation). It ships the protocol and the mapping, and no server, because A2A is a transport and Psych owns none. The routes live in...