This example shows how to use the MCP SDK and Cross-App Access (XAA) to authenticate a user once via OIDC, then connect to multiple MCP servers — each with its own resource-specific access token. The authentication is achieved through the Authorization Code Flow with PKCE, where the user is redirected to the XAA Playground IDP login page. After the user authenticates, the SDK's withCrossAppAccess() middleware handles Token Exchange and JWT Bearer grants to obtain access tokens for each MCP server.
This code sample demonstrates:
- Authenticating with the XAA Playground IDP using OIDC + PKCE
- Using Cross-App Access (XAA) to connect to multiple MCP servers with a single login
- Routing Claude AI tool calls to the correct MCP server
- Interactive chat with Claude using tools from multiple MCP servers
Before running this sample, you will need the following:
- Node.js 18+
- Client Credentials from a XAA Playground application registration:
- Client ID
- Client Secret
- An Anthropic API key for Claude AI
git clone https://github.com/okta-samples/mcp-client-cli.git
cd mcp-client-cliCopy .env.sample to .env and update it with the values from your application's configuration:
cp .env.sample .envIDP_URL=https://idp.xaa.dev
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
ANTHROPIC_API_KEY=sk-ant-api03-your-key-here
Register at the XAA Playground to obtain your client credentials. The playground provides:
- Client ID and Client Secret for authenticating with the IDP
- Pre-configured MCP servers (QRTY MCP Server and Todo0 MCP Server) ready for Cross-App Access
Install dependencies:
npm installBuild and start the application:
npm run build
npm startThe CLI will:
- Open your browser for IDP login at the XAA Playground
- Exchange the authorization code for an ID Token
- Connect to each configured MCP server using Cross-App Access (XAA)
- Start an interactive chat session with Claude AI
You can ask Claude to use tools from any connected server. For example:
- "What tools do you have?" — lists tools from all servers
- "Show my todos" — routes to the Todo0 MCP Server
- "Create a QR code for https://example.com" — routes to the QRTY MCP Server
Type quit to exit.
The key integration point is the withCrossAppAccess() middleware from the MCP SDK:
const xaaMiddleware = withCrossAppAccess({
idpUrl: IDP_URL,
idToken,
idpClientId: CLIENT_ID,
idpClientSecret: CLIENT_SECRET,
mcpAuthorisationServerUrl: serverConfig.authServerUrl,
mcpResourceUrl: serverConfig.audience,
mcpClientId: CLIENT_ID,
mcpClientSecret: CLIENT_SECRET,
scope: serverConfig.scopes,
});
const enhancedFetch = applyMiddlewares(xaaMiddleware)(fetch);This middleware automatically handles:
- Token Exchange at the IDP — exchanges the ID Token for an ID-JAG (Identity JWT Authorization Grant)
- JWT Bearer Grant at the MCP Authorization Server — exchanges the ID-JAG for a resource-specific access token
- XAA Playground
- MCP SDK Documentation
- Cross-App Access (XAA) Specification
- Authorization Code Flow with PKCE
Please visit our Okta Developer Forums.