Introduction
Every B2B SaaS company today faces the same request: “Can I connect your platform to my AI agent?” Your customers want to use Claude Desktop or Cursor to interact with their data—leads in your CRM, tickets in your HelpDesk, or infrastructure in your Cloud Dashboard. But exposing your B2B API directly to an LLM client is dangerous. You cannot ask customers to paste high-privilege API keys into third-party tools. You need a Secure Bridge. In this guide, we will build a production-ready Model Context Protocol (MCP) server for “Nexus” (our fictional B2B CRM). We will implement:- OAuth 2.1 for secure customer login (using Google as our Identity Provider).
- Multi-Tenant Isolation to ensure Customer A never sees Customer B’s data.
- Scoped Token Propagation to reuse your existing API permissions.
The Identity Flow
In our implementation, when a user wants to connect Claude to Nexus:- They authenticate via Google OAuth (leveraging your company’s existing SSO)
- Your MCP server verifies the user’s identity with your Nexus backend and receives an API token
- This Nexus token is encrypted and stored in your database for subsequent API calls
The Architecture: The “Bridge” Pattern
We aren’t rewriting our SaaS security. We are leveraging it. The MCP Server acts as a proxy that translates “Natural Language Intent” (from Claude) into “Scoped API Calls” (to your Backend).Why this works for Enterprise
- Zero Database Access: The MCP server has no direct DB credentials. It can only do what the specific logged-in user can do via your backend API.
- User-Scoped Tokens: Each MCP session is tied to a specific user’s backend token, ensuring proper data isolation.
- Token Rotation: If the user is removed from your system, their backend token becomes invalid on the next API call.
- No Shared Secrets: Users never handle API keys. It’s a pure OAuth flow with encrypted token storage.
- SSO Integration: By using Google OAuth, you leverage existing identity infrastructure (including MFA, conditional access policies, etc.).
- Encrypted Storage: Backend tokens are encrypted (AES-256-GCM) before storage and only decrypted at request time.
Understanding the Two OAuth Flows
It’s important to understand there are two separate OAuth flows happening: Flow 1: Claude ↔ Your MCP Server- Claude acts as the OAuth client
- Your MCP server is the authorization server
- Issues an “MCP Token” that Claude includes in every request
- This token is just a session identifier—it has no backend permissions
- Your MCP server acts as the OAuth client for Google
- Google provides user identity (email, name)
- Your MCP server verifies the user with your Nexus backend (
/auth/verify) - Nexus backend returns a scoped API token for that user
- This token has real permissions and can access customer data
Implementation: The “Scoped Token” Strategy
The secret sauce is how we handle the Scoped Token. We don’t want the user to log in for every single question. We need a way to persist their identity securely during the conversation. We will use a Encryption-at-Rest strategy within our session management.The Request Lifecycle: From Claude to Your API
Before we write tools, let’s understand the complete validation chain that happens on every request: This multi-layer validation ensures:- Layer 1 (MCP Token): Proves the user authenticated with your MCP server
- Layer 2 (Expiration Check): Prevents stale sessions
- Layer 3 (Decryption): Validates token integrity
- Layer 4 (Context Isolation): Prevents token leakage to LLM
- Layer 5 (Backend Validation): Your Nexus API enforces user permissions
The Engine Room - Writing Secure Tools
Now that we have a secure session, how do we use it? A naive developer might pass theapi_token as an argument to every tool:
get_leads(api_token: str, search_term: str).
Do not do this.
- It leaks the token into the LLM conversation history (security risk).
- It confuses the model (why does it need to know about tokens?).
- It’s brittle.
Step 1: The Context Manager
First, we define a thread-safe (and async-safe) storage for our user data. This acts as a “teleportation tunnel” from our Middleware directly to our Tools.Step 2: The “Dumb” Tool Principle
Now we write the MCP tool. Notice how clean it is. There is no authentication logic visible here. It retrieves credentials from context and makes API calls.Step 3: Key Implementation Details
Token Storage in Database
Instead of session storage, tokens are persisted in MongoDB for durability:token_repository.py
MCP Server Setup with Authentication
Here’s how to wire everything together:mcp_server.py
The Final Request Flows
User Experience
How does this look to the end user?
Configuration
They add your MCP server to theirclaude_desktop_config.json:
First-Time Setup
- They open Claude Desktop and try to use a Nexus command
- Claude redirects them to your MCP server’s OAuth flow
- They’re redirected to Google Sign-In (using their company email)
- After Google authentication, they’re redirected back to Claude
- Your MCP server exchanges the Google identity for a Nexus API token
The Magic
Once logged in, they just type. No more authentication needed for the session. User:“Show me the latest leads for Pepsi.”Claude:
(Calls
search_leads)
MCP Server:(Decrypts token → Injects into Header → Calls API) Claude:
“Here are the 3 latest leads for Pepsi…”
Handling Edge Cases & Security Considerations
What happens when tokens expire?
When the Nexus API token expires (typically after 1 hour), the next request will fail with a 401. Your tool should handle this gracefully:What if a user’s permissions change?
Since you’re using scoped tokens from your Nexus backend, permission changes are automatically enforced:- User is removed from your system: The Nexus API will return 401 on the next request
- User’s role is downgraded: The API only returns data the new role permits
- User’s access is revoked: The backend verification endpoint will fail on next login
Preventing Token Leakage to LLM
Critical: Never let the token appear in:- Function parameters:
get_leads(api_token: str) - Tool descriptions visible to the LLM
- Error messages returned to Claude
- Logs that might be sent to Claude for debugging
Rate Limiting & Abuse Prevention
Since each MCP token maps to a real user, apply rate limits in your authentication backend:Conclusion
We have moved beyond “Toy MCP Servers.” By combining Google OAuth for identity, Database-Backed Token Storage, Context Propagation for state isolation, and Scoped Tokens for access control, we’ve built a system that is:- Secure: No shared API keys. Users authenticate via their company SSO.
- Private: User-scoped tokens ensure proper data isolation. Multi-layer validation prevents data leakage.
- Auditable: Every API call is tied to a real user identity for compliance.
- Usable: The end user just chats; the rigorous security happens transparently.
Key Takeaways
- Use your existing identity provider (Google, Okta, etc.) instead of building custom auth
- Never store unencrypted backend tokens in your database - always use AES-256-GCM encryption
- Leverage context variables to keep auth invisible to tools and LLMs
- Validate at multiple layers: MCP token → Expiration → Decryption → Backend API
- Design for expiration: Tokens should be short-lived (24 hours) and re-authenticatable
- Use Starlette’s AuthenticationMiddleware for clean separation of auth logic from business logic