Skip to main content

The problem nobody’s talking about

You have an OpenAPI spec. You want to expose it as MCP tools. You search npm, find a library that promises “OpenAPI to MCP in 5 minutes,” paste your configuration, and boom—you’re done. Except you just created a security nightmare. Here’s what’s happening behind the scenes in most OpenAPI-to-MCP libraries:
  1. Your JWT tokens are exposed in tool input schemas, visible to every MCP client
  2. Headers are mixed between requests, leaking credentials across different API calls
  3. Your traffic routes through someone else’s cloud, sending customer tokens outside your infrastructure
  4. No validation of security configurations, leaving you vulnerable without warnings
Let me show you exactly what I mean.

Exhibit A: The credential exposure problem

Most OpenAPI-to-MCP libraries take the “easy” approach: if your OpenAPI spec has security requirements, they add those fields to the tool’s input schema.
// What most libraries generate
{
  name: "createUser",
  inputSchema: {
    type: "object",
    properties: {
      name: { type: "string" },
      email: { type: "string" },
      authorization: { type: "string" }, // ⚠️ EXPOSED!
      apiKey: { type: "string" }          // ⚠️ EXPOSED!
    }
  }
}
Why is this bad?
  1. Logging disasters: Your MCP client logs every tool call. Now you’re logging JWTs, API keys, and OAuth tokens.
  2. Client-side exposure: AI agents see these fields. Some might cache or transmit them insecurely.
  3. Developer confusion: Your API consumers think they need to manually provide auth for every call.
  4. Compliance violations: GDPR, SOC2, and PCI-DSS don’t care that “the library made you do it.”
// What gets logged in your MCP client
{
  "tool": "createUser",
  "arguments": {
    "name": "John Doe",
    "email": "[email protected]",
    "authorization": "Bearer eyJhbGciOiJIUzI1NiIs..." // 🚨 LEAKED
  }
}
Every call. Every log entry. Every error trace. Your JWTs, sitting in plain text.

Exhibit B: The header mixing catastrophe

Some libraries try to be “clever” and manage authentication for you. But they don’t isolate requests properly:
// Pseudocode of what happens in many libraries
const globalHeaders = new Headers();

function callAPI(tool, input) {
  // Set auth for this user
  globalHeaders.set('authorization', input.token);

  // Make request
  return fetch(tool.url, { headers: globalHeaders });

  // ⚠️ Header never cleared!
  // Next request to a different API uses the same headers!
}
The result?
  • User A calls GitHub API → sets authorization: Bearer github_token_123
  • User B calls Slack API → still has User A’s GitHub token in headers
  • User B’s Slack request now has both their Slack token AND User A’s GitHub token
This isn’t theoretical. I’ve seen this exact bug in production systems processing millions of requests.
// What actually gets sent to Slack
POST https://api.slack.com/messages
Headers:
  authorization: Bearer github_token_123  // ⚠️ Wrong API!
  x-slack-token: Bearer slack_token_456   // ✅ Correct

// Slack rejects it. GitHub token leaks to Slack's logs.

Exhibit C: The infrastructure control problem

Here’s the architectural decision that catches teams off-guard: Self-hosted libraries that convert OpenAPI to MCP run in your infrastructure. Your data stays in your VPC. You control the execution environment. Cloud-based converters route your API traffic through external infrastructure. Your requests, responses, and authentication tokens pass through someone else’s systems.
Self-Hosted (Your Infrastructure):
  MCP Client → Your Server → Your APIs ✅

Cloud-Based (External Infrastructure):
  MCP Client → Their Cloud → Your APIs ⚠️
The critical questions:
  1. Where does authentication happen? In your infrastructure or theirs?
  2. Who has access to tokens? Just you, or the service provider too?
  3. What’s their security posture? SOC2? ISO 27001? GDPR-compliant?
  4. What’s in their logs? Are customer tokens being logged externally?
  5. Can you audit traffic? Do you have visibility into what’s being proxied?
When cloud routing becomes a compliance problem:
  • Regulated industries (banking, healthcare): Customer tokens can’t leave your infrastructure
  • Data sovereignty: EU customer data routing through non-EU servers
  • Enterprise contracts: “All customer data must remain within our VPC”
  • Audit requirements: Need complete visibility into where tokens traveled
Important distinction: Enterprise-grade identity platforms (like Frontegg’s AgentLink) are purpose-built for secure token management with SOC2/ISO compliance, audit trails, and enterprise SLAs. Generic OpenAPI-to-MCP converter tools typically aren’t.
Bottom line: If you’re building internal tools or need maximum control, self-hosted is the safest choice. If you use a cloud service, ensure it’s a compliant identity platform, not just a conversion utility.

Exhibit D: The “it works on my machine” security

Here’s another pattern I see constantly:
// Developer's local setup
OpenapiToMCP({
  spec: './api.yaml',
  auth: {
    apiKey: process.env.DEV_API_KEY, // ✅ Works locally
  },
});
Looks fine, right? Developer tests it, it works, they ship it. Production disaster:
// Production reality
OpenapiToMCP({
  spec: 'https://api.prod.com/openapi.yaml',
  auth: {
    apiKey: process.env.DEV_API_KEY, // ⚠️ Wrong key!
  },
});
Problems:
  1. No validation: Library doesn’t check if auth config matches spec requirements
  2. Silent failures: Requests fail with generic 401s, no hint why
  3. Mixed environments: Dev keys in prod, prod keys in dev
  4. Multi-provider chaos: GitHub token used for Slack API, no errors, just failures
Most libraries give you zero visibility into security configuration correctness.

The actual cost

Let me make this concrete with a real-world scenario: Company: SaaS platform with 50,000 customers APIs: GitHub, Slack, Stripe, internal APIs MCP Tools: 200+ endpoints exposed via OpenAPI specs What happened:
  1. Used popular OpenAPI-to-MCP library
  2. Didn’t realize it exposed auth in input schemas
  3. MCP client logs included customer OAuth tokens for 6 months
  4. Security audit discovered it during SOC2 compliance review
The damage:
  • $500K+ cost: Forensic analysis, customer notification, legal fees
  • 3 weeks downtime: Full security review, credential rotation
  • Lost customers: 12 enterprise customers left immediately
  • Regulatory fines: GDPR violations for EU customers
  • Reputation damage: Security blog posts, HN discussion, vendor trust loss
All because they chose the wrong OpenAPI-to-MCP library.

How FrontMCP solves this

FrontMCP’s OpenAPI adapter was built from day one with security as the foundation, not an afterthought.

1. Authentication never exposed to clients

import { OpenapiAdapter } from '@frontmcp/adapters';

OpenapiAdapter.init({
  name: 'my-api',
  spec: myOpenApiSpec,
  baseUrl: 'https://api.example.com',

  // ✅ Auth provider mapper - LOW RISK
  authProviderMapper: {
    GitHubAuth: (ctx) => ctx.authInfo.user?.githubToken,
    SlackAuth: (ctx) => ctx.authInfo.user?.slackToken,
  },

  // ✅ Auth resolved from server-side context
  // ✅ Never exposed in tool input schemas
  // ✅ Never logged by MCP clients
});
Generated tool:
{
  name: "createUser",
  inputSchema: {
    type: "object",
    properties: {
      name: { type: "string" },
      email: { type: "string" }
      // ✅ No auth fields!
    }
  }
}
Auth is resolved server-side from the request context. Clients never see it.

2. Request isolation + multi-provider authentication

Each request gets fresh headers with the correct auth provider—no global state, no mixing:
OpenapiAdapter.init({
  name: 'multi-api',
  spec: combinedSpec,
  baseUrl: 'https://api.example.com',

  authProviderMapper: {
    GitHubAuth: (ctx) => ctx.authInfo.user?.githubToken,
    SlackAuth: (ctx) => ctx.authInfo.user?.slackToken,
    StripeAuth: (ctx) => ctx.authInfo.user?.stripeKey,
  },
});

// Each tool uses the right provider automatically:
// github_createRepo() → GitHubAuth → ctx.authInfo.user.githubToken
// slack_postMessage() → SlackAuth → ctx.authInfo.user.slackToken
// stripe_createCharge() → StripeAuth → ctx.authInfo.user.stripeKey
FrontMCP validates configuration at startup and creates isolated headers per-request—no cross-contamination possible.

3. Security validation with risk scoring

FrontMCP validates your security configuration and warns you:
const validation = validateSecurityConfiguration(tools, options);

console.log(validation);
// {
//   valid: true,
//   securityRiskScore: 'low',
//   missingMappings: [],
//   warnings: [
//     'INFO: Using authProviderMapper - LOW security risk',
//     'Authentication resolved from user context'
//   ]
// }
Risk levels:
RiskConfigurationWhat it means
LOWauthProviderMapper, securityResolverAuth from context, not exposed
MEDIUM ⚠️staticAuth, additionalHeadersStatic credentials (acceptable for server-to-server)
HIGH 🚨includeSecurityInInput: trueAuth exposed to clients (NOT RECOMMENDED)
Missing mappings detected:
// ❌ This fails at startup
OpenapiAdapter.init({
  spec: multiProviderSpec, // Has GitHubAuth, SlackAuth, StripeAuth
  authProviderMapper: {
    GitHubAuth: (ctx) => ctx.authInfo.user?.githubToken,
    // Missing SlackAuth and StripeAuth!
  },
});

// Error: Missing auth provider mappings for security schemes: SlackAuth, StripeAuth
// Solutions:
//   1. Add authProviderMapper: { 'SlackAuth': (ctx) => ctx.authInfo.user?.slackToken }
//   2. Add securityResolver: (tool, ctx) => ({ jwt: ctx.authInfo.token })
//   3. Add staticAuth: { jwt: process.env.API_TOKEN }
You know immediately if your security config is wrong. No silent failures in production.

4. Defense-in-depth security protections

Beyond authentication, FrontMCP protects against common attack vectors:
ProtectionWhat it prevents
SSRF PreventionBlocks dangerous protocols (file://, javascript:, data:) in server URLs
Header InjectionRejects control characters (\r, \n, \x00) that could inject headers
Prototype PollutionBlocks reserved JS keys (__proto__, constructor) in input transforms
Integer OverflowContent-Length validated with isFinite() to prevent size bypass
Query Param CollisionDetects conflicts between security and user input parameters
These protections are automatic—you don’t need to configure anything. See openapi.executor.ts for implementation details.

5. Runs on YOUR infrastructure

// FrontMCP runs entirely in your Node.js process
import { FrontMcp, App } from '@frontmcp/sdk';
import { OpenapiAdapter } from '@frontmcp/adapters';

@FrontMcp({
  id: 'my-server',
  apps: [MyApp],
  http: { port: 3000 },
})
class MyServer {}

// ✅ Your infrastructure
// ✅ Your VPC
// ✅ Your logs
// ✅ Your compliance boundary
// ✅ Your control
No external dependencies. No cloud routing. No data leaving your infrastructure.

6. Headers and body mapping for tenant isolation

OpenapiAdapter.init({
  name: 'saas-api',
  spec: apiSpec,
  baseUrl: 'https://api.example.com',

  headersMapper: (ctx, headers) => {
    const authInfo = ctx.authInfo;

    // ✅ Add tenant ID from user context
    if (authInfo.user?.tenantId) {
      headers.set('x-tenant-id', authInfo.user.tenantId);
    }

    // ✅ Add user authorization
    if (authInfo.token) {
      headers.set('authorization', `Bearer ${authInfo.token}`);
    }

    // ✅ Add trace ID for observability
    headers.set('x-trace-id', ctx.traceContext.traceId);

    return headers;
  },

  bodyMapper: (ctx, body) => {
    const authInfo = ctx.authInfo;

    // ✅ Inject user context into all mutations
    return {
      ...body,
      tenantId: authInfo.user?.tenantId,
      userId: authInfo.user?.id,
    };
  },
});
Result:
  • Tenant isolation guaranteed
  • User context injected server-side
  • Hidden from MCP clients
  • Impossible to forge or bypass

Core security principles

FrontMCP’s OpenAPI adapter is built on five security principles:
  1. Least Exposure — Auth never exposed to MCP clients
  2. Isolation — Fresh headers per request, no global state
  3. Validation — Config validated at startup, not runtime
  4. Transparency — Risk levels explicit (LOW/MEDIUM/HIGH)
  5. Control — Runs in your infrastructure, no external routing

Migration guide: From insecure to secure

If you’re using another OpenAPI-to-MCP library, here’s how to migrate:

Step 1: Audit your current setup

# Search for exposed credentials
grep -r "authorization.*type.*string" ./generated-tools/
grep -r "apiKey.*type.*string" ./generated-tools/

# Check logs for leaked tokens
grep -r "Bearer " ./logs/
grep -r "api.*key" ./logs/

Step 2: Install FrontMCP

npm install @frontmcp/sdk @frontmcp/adapters

Step 3: Replace your adapter

import { openapiToMCP } from 'insecure-lib';

const tools = await openapiToMCP({
  spec: './api.yaml',
  auth: {
    apiKey: process.env.API_KEY,
  },
});

Step 4: Rotate credentials

# After migration, rotate all exposed credentials
# - Revoke old API keys
# - Regenerate OAuth tokens
# - Update environment variables
# - Clear logs with exposed credentials

Step 5: Validate security

import { validateSecurityConfiguration } from '@frontmcp/adapters/openapi';

const validation = validateSecurityConfiguration(tools, options);

console.log(`Risk Score: ${validation.securityRiskScore}`);
console.log(`Valid: ${validation.valid}`);
console.log(`Warnings: ${validation.warnings.join('\n')}`);

The comprehensive test suite

We take security seriously. FrontMCP’s OpenAPI adapter has 193 comprehensive tests covering:
  • ✅ All authentication strategies
  • ✅ Request isolation
  • ✅ Multi-provider scenarios
  • ✅ Security validation
  • ✅ Missing mappings detection
  • ✅ Headers and body mapping
  • ✅ Defense-in-depth protections (SSRF, header injection, prototype pollution)
  • ✅ Error handling
  • ✅ Edge cases
npm test

# Test Suites: 7 passed, 7 total
# Tests:       193 passed, 193 total
Every security feature is tested. Every edge case is covered. View the test suite →

Conclusion: Security isn’t optional

If you’re using OpenAPI-to-MCP tools in production, ask yourself:
  1. ❓ Are my JWT tokens exposed in tool input schemas?
  2. ❓ Are headers being mixed between different API requests?
  3. ❓ Is my traffic routing through someone else’s cloud?
  4. ❓ Is my security configuration validated at startup?
  5. ❓ Do I have visibility into security risk levels?
If you answered “I don’t know” to any of these, you have a problem. FrontMCP’s OpenAPI adapter gives you:
  • Zero credential exposure — Auth resolved from context, never exposed
  • Request isolation — Fresh headers per request, no mixing
  • Multi-provider support — Map each security scheme to the right auth provider
  • Validation at startup — Know immediately if config is wrong
  • Risk scoring — Understand your security posture
  • Your infrastructure — No external dependencies, no cloud routing
Security isn’t optional. Choose the right tool.

Get started with FrontMCP


Don’t let your OpenAPI-to-MCP integration become a security nightmare.

Choose FrontMCP. Choose security.