Skip to content

How to Connect Claude to SaaS APIs via MCP (Zero Data Retention)

Learn how to connect Claude to external SaaS APIs using a stateless, zero-data-retention MCP server architecture to pass enterprise InfoSec and SOC 2 reviews.

Riya Sethi Riya Sethi · · 14 min read
How to Connect Claude to SaaS APIs via MCP (Zero Data Retention)

If you need Claude to read Salesforce contacts, update Jira tickets, or push HubSpot deals - and you have an enterprise InfoSec review waiting on the other side of that decision - the architecture you pick matters significantly more than the integration code you write. The short answer: you must connect Claude to external SaaS APIs through a stateless Model Context Protocol (MCP) server that processes payloads entirely in-memory and never persists customer data to a third-party database. Everything else in this post is the critical implementation detail behind that sentence.

When an AI agent reads regulated data, that data flows through your infrastructure. If your integration layer caches that payload, your SOC 2 scope expands, your GDPR liabilities multiply, and procurement teams will flag your application as a critical vendor risk. Most teams get stuck because default integration platforms cache API responses for performance, logging, or replay. That works fine for internal tooling. It fails hard when your buyer's InfoSec team sees a subprocessor with a copy of their CRM data sitting in someone else's database.

This guide breaks down exactly how to connect Claude to any third-party SaaS API using a stateless, zero-data-retention MCP server architecture. We will cover how to dynamically generate tools from API schemas, handle the JSON-RPC protocol, manage OAuth token lifecycles securely, properly propagate rate limits back to the LLM, and pass enterprise scrutiny—all without ever writing your customers' regulated data to a disk.

The InfoSec Wall: Why Native LLM Connectors Fail Enterprise Security

Native AI connectors and legacy integration platforms are built on a fundamental assumption: data should be synchronized, stored, and indexed. That architecture is actively hostile to enterprise AI deployments. Native connectors solve the demo. They rarely solve production.

Claude's built-in Slack connector, for example, gives you search_messages and post_message. It does not give you channel administration, user group management, or file APIs. When your customer asks for anything beyond the happy path, you either fork into custom integration code or hand them a workaround. Both paths burn engineering time.

The deeper problem is data governance. Most integration middleware caches responses to speed up subsequent calls or to power features like search and sync. That cache is now a subprocessor holding regulated data - PII, financial records, HR data - which pulls it directly into your SOC 2 audit scope and your GDPR Article 28 obligations. The security posture questionnaire your enterprise buyer sends will ask exactly where that data lives, how long it is retained, and who has access. If the honest answer is "some of it is cached in our integration vendor's database," the deal slows down or dies.

The deployment readiness gap is severe. A 2026 Deloitte study highlighted that while 96% of organizations are running AI agents in production, only 21% have a mature governance model to manage them. Security teams are reacting accordingly. AvePoint's 2026 State of AI report found that nearly 90% of organizations experienced a generative AI-related security breach in the past year, driven entirely by adoption outpacing governance. Enterprise procurement has noticed. Reviews that used to take three weeks now take twelve, and vendors that cannot answer basic data flow questions get eliminated in the first pass.

Regulatory pressure is compounding the problem. The EU AI Act's transparency obligations for AI systems that interact with people became enforceable in August 2026. If your Claude-powered feature touches EU users and your integration layer stores their data in a US-based caching database before passing it to Claude, you are actively violating data residency requirements and overlapping obligations under GDPR and the AI Act, as we detail in our guide to EU data residency and GDPR compliance for MCP servers. Furthermore, AI agents need real-time data to make accurate decisions. Querying a cached database that syncs every 15 minutes guarantees hallucinations based on outdated state.

To pass InfoSec reviews, your MCP architecture must shift from a stateful synchronization model to a stateless proxy model. For a deeper look at how retention policies drive procurement outcomes, see our breakdown on How Do MCP Servers Handle Data Retention and Security for AI Agents?.

What is Zero Data Retention in MCP Architecture?

Zero data retention (ZDR) in an MCP context means your server operates entirely in-memory. It acts as a strict protocol translator and stateless proxy between the MCP client (Claude) and the upstream SaaS API (e.g., Salesforce, Jira, HubSpot).

When a request arrives, the server authenticates the call, fetches the necessary OAuth tokens, translates the MCP tool invocation into a standard HTTP REST request, and proxies it to the vendor. When the vendor responds, the server translates the JSON payload back into an MCP-compliant response and streams it to the client. The payload is never written to disk, never stored in an object storage bucket, and never cached in a long-lived log file containing customer data.

A ZDR MCP server holds only what it needs to route the next request:

  • Connection metadata: which integration, which tenant, which OAuth scopes are active.
  • Encrypted credentials: OAuth refresh tokens, API keys, encrypted at rest.
  • Audit metadata: request IDs, timestamps, tool names - never request or response bodies.

Everything else lives for the duration of a single HTTP request and disappears. This is the architectural property that lets you truthfully answer "no" when an enterprise buyer asks whether your integration subprocessor stores their data, which is essential for building SOC 2 and GDPR compliant AI agents. Because the data only exists in ephemeral memory during the lifecycle of the HTTP request, there is nothing for attackers to exfiltrate and no stale data to manage.

sequenceDiagram
    participant Claude as Claude Desktop (MCP Client)
    participant MCP as Stateless MCP Server (Zero Retention Proxy)
    participant Vault as Credential Vault (Keys Only)
    participant SaaS as Upstream SaaS API (e.g., Salesforce)
    Claude->>MCP: JSON-RPC tools/call over HTTP
    MCP->>Vault: Fetch OAuth token
    Vault-->>MCP: Short-lived access token
    MCP->>SaaS: HTTP REST Request
    SaaS-->>MCP: JSON Response payload (in-memory)
    MCP-->>Claude: Transformed MCP result
    Note over MCP: No payload persisted to database

How to Connect Claude to SaaS APIs Using an MCP Server Without Caching Data

The pattern has three moving parts: a cryptographically signed URL that scopes the server to one tenant's connection, a dynamic tool generator that turns the SaaS API surface into MCP tools, and a stateless JSON-RPC handler that executes calls without touching persistent storage. Building a stateless MCP server requires handling the JSON-RPC 2.0 protocol over HTTP. The MCP specification defines a standard handshake and a set of methods that the client uses to discover and execute tools.

Step 1: Provision a Scoped MCP Server per Connected Account

Each MCP server is bound to a single integrated account - one tenant's Salesforce, one tenant's HubSpot - a core principle when architecting a multi-tenant MCP server for enterprise B2B SaaS. The URL itself carries the authorization: a random hex token, HMAC-hashed on the server side and looked up against a short list of allowed tools and an optional expiry.

POST /integrated-account/{id}/mcp
Content-Type: application/json
 
{
  "name": "Acme Corp - HubSpot (read-only)",
  "config": {
    "methods": ["read"],
    "tags": ["crm", "sales"],
    "require_api_token_auth": true
  },
  "expires_at": "2026-09-30T00:00:00Z"
}

The response returns a unique, cryptographically secure URL of the form https://api.yourdomain.com/mcp/a1b2c3d4e5f6.... That URL is the only client-side configuration Claude needs. Because the token maps to one specific integrated account, there is no risk of cross-tenant leakage even if the URL is somehow shared - the worst case is scoped to that one connection, which can be revoked with a single API call.

To add this to Claude, open Settings → Connectors → Add custom connector, paste the MCP server URL, and save. Claude will immediately run the MCP initialize handshake. For ChatGPT, the flow is the equivalent under Settings → Apps → Advanced settings, with Developer mode enabled.

Step 2: The Protocol Handshake

When Claude connects to your MCP server, it sends an initialize request. Your server must respond with its protocol version and capabilities. Since we are building a tool-execution proxy, we only need to declare support for the tools capability.

// Example MCP initialize response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {}
    },
    "serverInfo": {
      "name": "Stateless SaaS Proxy",
      "version": "1.0.0"
    }
  }
}

Step 3: Tool Discovery and the Flat Input Namespace

Claude will immediately follow up with a tools/list request. Your server must return a list of available API endpoints formatted as MCP tools. Each tool requires a name, description, and an inputSchema (a valid JSON Schema defining the arguments).

Here is where the architecture gets tricky. REST APIs separate parameters into path variables, query strings, and JSON request bodies. MCP does not. The MCP protocol forces all arguments into a single, flat JSON object. Your MCP server must merge the upstream API's query schema and body schema into a single inputSchema for Claude. On tools/list, Claude receives an array of tool definitions generated on the fly from your integration's resource definitions. Each tool looks like this:

{
  "name": "list_all_hub_spot_contacts",
  "description": "List HubSpot contacts with pagination support.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "limit": { "type": "string" },
      "next_cursor": { "type": "string" },
      "filter": { "type": "object" }
    }
  }
}

Step 4: Stateless Tool Execution

When Claude decides to act, it sends a tools/call request. Your proxy receives the tool name and the flat arguments object. When Claude calls the tool, your proxy must unpack that flat object, routing the correct arguments to the URL query string and the rest to the HTTP request body based on the original API definition.

Info

Architectural Rule: Do not implement custom business logic in the proxy layer. The proxy's only job is to map the flat MCP arguments back to the upstream API's expected format, attach the OAuth token, execute the request, and return the raw result.

Here is a conceptual look at how a stateless proxy handler processes an execution request:

async function handleToolCall(request) {
  const { name, arguments: args } = request.params;
  
  // 1. Look up the API endpoint mapping for this tool
  const endpoint = resolveEndpoint(name);
  
  // 2. Split the flat MCP arguments into query and body parameters
  const queryParams = extractQueryParams(args, endpoint.querySchema);
  const bodyParams = extractBodyParams(args, endpoint.bodySchema);
  
  // 3. Fetch the OAuth token (keys only, no data storage)
  const accessToken = await getAccessToken(request.accountId);
  
  // 4. Execute the proxy request statelessly
  const response = await fetch(`${endpoint.baseUrl}${endpoint.path}?${new URLSearchParams(queryParams)}`, {
    method: endpoint.httpMethod,
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: endpoint.httpMethod !== 'GET' ? JSON.stringify(bodyParams) : undefined
  });
  
  const data = await response.json();
  
  // 5. Return the result directly to Claude without caching
  return {
    jsonrpc: "2.0",
    id: request.id,
    result: {
      content: [{
        type: "text",
        text: JSON.stringify(data)
      }]
    }
  };
}

This execution path processes the entire payload in-memory. The data is garbage-collected by the runtime as soon as the HTTP request completes. For a complete guide on building this JSON-RPC layer, read our How to Build MCP Servers for AI Agents: 2026 Hands-On Architecture Guide.

Handling Authentication and Token Lifecycles

You cannot hand raw OAuth tokens to an LLM. Ever. Not only is it a massive security risk (one prompt injection can exfiltrate it), but LLMs cannot execute the OAuth refresh flow when a token expires. The MCP server must handle authentication on behalf of the agent.

The correct pattern is a two-layer credential model:

  1. MCP URL token: a random hex string that authenticates the MCP client to your server. It is HMAC-hashed before storage so raw values are never persisted.
  2. Upstream OAuth credentials: encrypted refresh tokens held in a credential vault, exchanged for short-lived access tokens at request time.

When a request hits that cryptographic URL, the proxy extracts the token from the URL path, validates the HMAC hash, and resolves the hashed token to a specific integrated account ID (e.g., "Customer A's Salesforce instance"). The proxy then retrieves the short-lived OAuth access token for that specific account from your secure vault. The platform schedules work ahead of token expiry, refreshing OAuth tokens shortly before they expire so the AI agent never experiences an authentication failure or blocks on a token exchange during peak traffic.

For higher-security environments, you can implement conditional API token authentication via require_api_token_auth. Even if an attacker discovers the cryptographic MCP URL in logs or config files, the server can be configured to require a valid API bearer token in the headers, ensuring only authenticated users within your application can invoke the tools.

Warning

Treat MCP URLs like passwords. Rotate them on any suspected exposure, and use short expires_at values (hours or days, not months) for contractor or automation use cases. An alarm-based cleanup handler will delete the token and its lookup entries when the expiry fires, and the URL will start returning 401 immediately after.

For a broader look at managed OAuth handling in the MCP context, see Managed MCP for Claude: Full SaaS API Access Without the Security Headaches.

Managing Rate Limits and 429 Errors

When connecting AI agents to external APIs, rate limits are the most common cause of silent failures. This is where a lot of integration platforms quietly do the wrong thing. A naive MCP server attempts to absorb rate limits by intercepting HTTP 429 responses, implementing automatic retries, and applying its own exponential backoff inside the proxy layer.

This is an architectural anti-pattern.

If your proxy absorbs the rate limit, sleeps the thread for 60 seconds, and pretends nothing happened, the MCP client (Claude) will time out, assume the server is dead, and drop the context. Your agent is silently sitting on a stalled request while the LLM's tool-call timeout fires.

The correct pattern for a compliant zero-data-retention proxy is transparency, not absorption. When an upstream API returns a 429 (Too Many Requests), the proxy must pass it straight back to the caller. The proxy normalizes upstream rate limit information into standardized headers per the IETF specification:

HTTP/1.1 429 Too Many Requests
ratelimit-limit: 100
ratelimit-remaining: 0
ratelimit-reset: 12
Content-Type: application/json
 
{
  "error": "rate_limit_exceeded",
  "upstream": "hubspot"
}

Those three headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) give the calling agent everything it needs to make its own backoff decision. The caller (the AI agent or the orchestration framework) is responsible for reading the ratelimit-reset header, pausing its own execution, and retrying later.

This matters for two critical reasons. First, it keeps the proxy stateless: no in-memory backoff timers, no per-tenant token buckets, and no queue that could hold onto a payload longer than a single request. Second, it puts control in the right place. The agent framework knows whether the current tool call is user-facing (retry fast) or a background job (retry with wide jitter). The proxy does not. Do not claim your proxy automatically retries or absorbs rate limit errors - forcing the LLM to handle its own backoff is the only way to maintain a stable, predictable system state.

Dynamic Tool Generation vs. Hardcoded Endpoints

Writing individual custom wrapper code for every SaaS endpoint is a massive engineering write-off and a maintenance dead end. The Slack Web API has over 200 methods. Salesforce has thousands of standard objects and unbounded custom objects. Multiply that by every integration your product supports, and you will spend your entire quarter maintaining tool descriptions.

The correct approach is dynamic tool generation. Your MCP server should derive its tool definitions directly from two sources that already exist:

  1. Resource definitions: what endpoints the integration exposes (list, get, create, update, delete, plus custom methods like search or download).
  2. Documentation records: human-readable descriptions and OpenAPI/JSON Schema definitions for each resource method.

When Claude requests tools/list, the server iterates over the available API methods and generates descriptive, snake_case tool names on the fly:

  • GET /crm/contacts becomes list_all_hub_spot_contacts
  • POST /crm/contacts becomes create_a_hub_spot_contact
  • GET /crm/contacts/{id} becomes get_single_salesforce_opportunity_by_id
  • PUT /tickets/{id} becomes update_a_zendesk_ticket_by_id

The server parses the upstream YAML or JSON schemas and converts them into the flat inputSchema required by MCP. Required properties are collected from nested schemas and moved into the standard JSON Schema required array so Claude's function-calling layer enforces them.

Injecting Pagination Instructions

LLMs are notoriously bad at handling pagination cursors. When generating tools for list methods, your server should automatically inject limit and next_cursor properties into the schema. Crucially, you must append explicit instructions to the description of the next_cursor field:

"The cursor to fetch the next set of records. Always send back exactly the cursor value you received without decoding, modifying, or parsing it."

Tag Scoping and Curation

A resource only becomes an MCP tool if it has a corresponding documentation entry. That documentation gate acts as a curation mechanism - only well-described endpoints are exposed to LLMs, which reduces hallucinated tool calls and makes the tool list intelligible to the model. Tags provide the last layer of scoping. When you provision the MCP server, you can restrict it to specific tags. For example, if you configure the server to only expose tools tagged support (like tickets or ticket_comments), only those tools are visible to Claude. This is how you build a support-desk agent that literally cannot create or delete CRM records - those destructive tools are simply not in its schema at all.

Deploying Your Compliant MCP Server to Production

The production readiness bar for an MCP server is different from a standard API. You are exposing tool execution to an autonomous agent that can make decisions about which tools to call. Your architecture has to assume the LLM will occasionally misbehave, and your infrastructure has to make that safe. The shift toward MCP is structural and permanent. An independent census by MCP Manager indexed over 17,400 MCP servers, with SDK downloads hitting 97 million per month by March 2026 - a 970x increase in just 18 months.

A production-ready zero-data-retention MCP deployment must have these properties:

Property Requirement
Data retention No request or response bodies persisted. Metadata only (request IDs, tool names, timestamps).
Credential isolation OAuth tokens encrypted at rest, refreshed ahead of expiry, never exposed to the LLM.
Tool scoping Per-connection URL with method and tag filters, expiry, and revocation.
Rate limit transparency Upstream 429 responses passed through with IETF-standard headers.
Audit trail Every tool call logged with request ID and tool name, without payload data.
Failure isolation One tenant's rate limit or API failure never blocks another tenant.

Building this yourself is a serious engineering effort. You will spend months on OAuth edge cases (token refresh races, revocation cascades, scope drift), tool description curation, JSON Schema normalization across dozens of upstream APIs, fighting through InfoSec audits, and building the transport layer itself. Then you get to do it again every time a vendor changes their API.

The managed path skips that entirely. A managed MCP platform like Truto provides a pure zero-data-retention architecture out of the box. It exposes a stateless MCP endpoint per connected account, dynamically generates tools from hundreds of SaaS APIs, normalizes authentication, refreshes OAuth tokens ahead of expiry, and passes rate limit errors through to the caller with normalized headers. Payloads are processed entirely in-memory, not stored. That is the architecture InfoSec teams sign off on instantly.

Tip

When you draft your data flow diagram for the InfoSec review, mark the MCP proxy as a transit-only subprocessor - it handles data in flight but does not persist it. Include the specific fields you do retain (connection ID, encrypted refresh token, audit metadata) and note the retention period for each. Reviewers respect precise answers.

Where to Go From Here

The deployment pattern is stable now. MCP has consolidated into the default agent-to-API protocol, and the architectural questions are settled: stateless proxy, cryptographic per-tenant URLs, dynamic tool generation, transparent rate limit propagation, and absolutely no payload retention.

Your choice is no longer whether to support the Model Context Protocol, but how to architect your infrastructure. The question left is whether you build that architecture or adopt it. If your team has the bandwidth to own an integration platform, the patterns in this post give you a working blueprint. If your priority is shipping AI features that survive enterprise procurement and pass SOC 2 audits, a managed zero-data-retention MCP layer is the shorter path.

FAQ

How do I connect Claude to a SaaS API without caching customer data?
Use a stateless MCP server that processes JSON-RPC requests entirely in-memory and forwards the underlying API call to the SaaS system without writing the payload to any database. The server should retain only connection metadata and encrypted credentials, never request or response bodies.
What is a zero data retention MCP server?
It is an MCP server that acts as a transit-only proxy: it accepts a tool call from an AI agent, executes the upstream API request, transforms the response, and returns it, all without persisting the payload. Only routing metadata like connection IDs, encrypted OAuth tokens, and audit records are retained.
How does an MCP server handle rate limits without breaking statelessness?
The proxy should not retry or throttle. When the upstream API returns HTTP 429, the MCP server passes that response directly to the caller along with normalized IETF-standard headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The calling agent decides how to back off, keeping the proxy stateless.
Can Claude see the OAuth token used to call the SaaS API?
No. In a correct implementation, the MCP server holds encrypted OAuth credentials in a vault, refreshes access tokens ahead of expiry, and uses them server-side when executing the upstream call. Claude only sees the tool result, never the underlying credential.
How are MCP tools generated for each SaaS integration?
Tools are derived dynamically from the integration's resource definitions and documentation records at request time. A resource only becomes a tool if it has a documentation entry, which acts as a quality gate. JSON Schemas for query and body parameters are pulled from the same documentation and exposed to Claude via the MCP tools/list method.

More from our Blog