How to Handle Bearer Token Authentication for Remote MCP Servers in MetaMCP
MetaMCP supports bearer token authentication for remote MCP servers through either OAuth access tokens or static bearer tokens configured in the database, automatically injecting them into HTTP headers during transport initialization.
MetaMCP is an open-source platform that unifies access to multiple Model Context Protocol (MCP) servers. When integrating remote MCP servers that require authentication, understanding how to configure and manage bearer token authentication ensures secure API communication without exposing credentials in client-side code.
Authentication Architecture Overview
MetaMCP implements a dual-strategy authentication system that prioritizes OAuth tokens while providing static bearer tokens as a fallback mechanism.
The platform supports two distinct authentication methods:
- OAuth access tokens – Generated through the MetaMCP OAuth flow and stored in
serverParams.oauth_tokens?.access_token. These are automatically added to theAuthorization: Bearer …header when the client initializes. - Static bearer tokens – Entered by users or stored in the database via
serverParams.bearerToken. These serve as a fallback when OAuth tokens are unavailable and can be injected manually through UI hooks.
Configuring Static Bearer Tokens in the Database
Static bearer tokens are persisted in the PostgreSQL database schema defined in apps/backend/src/db/schema.ts. The bearer_token column stores optional authentication credentials for each MCP server definition.
// apps/backend/src/db/schema.ts
bearerToken: text("bearer_token"),
When servers are queried through the MetaMCP backend, the getMcpServers function in apps/backend/src/lib/metamcp/fetch-metamcp.ts includes the bearer token in the ServerParameters object:
// apps/backend/src/lib/metamcp/fetch-metamcp.ts
bearerToken: server.bearerToken,
This ensures that static tokens are available during client initialization while maintaining separation between database storage and transport logic.
Implementing Token Injection in Backend Transports
The MetaMCP backend handles bearer token injection automatically during transport creation. Both SSE and STREAMABLE_HTTP transports in apps/backend/src/lib/metamcp/client.ts implement identical authentication logic.
The client creation process prioritizes OAuth tokens while falling back to static bearer tokens:
// apps/backend/src/lib/metamcp/client.ts (lines 84-94)
const headers: Record<string, string> = {
...(serverParams.headers || {}),
};
const authToken =
serverParams.oauth_tokens?.access_token || serverParams.bearerToken;
if (authToken) {
headers["Authorization"] = `Bearer ${authToken}`;
}
The same pattern applies to STREAMABLE_HTTP transport initialization (lines 115-124), ensuring consistent authentication behavior across transport types. This implementation allows seamless switching between OAuth and static authentication without requiring code changes in consuming applications.
Frontend Token Management with React Hooks
For frontend applications requiring manual token injection, MetaMCP provides the useConnection hook in apps/frontend/hooks/useConnection.ts. This hook supports explicit bearer token configuration alongside OAuth flows.
The hook resolves authentication tokens using a priority-based approach:
// apps/frontend/hooks/useConnection.ts (lines 55-73)
const token =
bearerToken || (await authProvider.tokens())?.access_token;
if (token) {
const authHeaderName = headerName || "Authorization";
if (authHeaderName.toLowerCase() !== "authorization") {
headers[authHeaderName] = token;
headers["x-custom-auth-header"] = authHeaderName;
} else {
headers[authHeaderName] = `Bearer ${token}`;
}
}
This implementation supports custom header names for non-standard authentication schemes while maintaining RFC 6750 compliance for standard Bearer token usage.
Complete Implementation Examples
Database Configuration Example
Configure a remote MCP server with a static bearer token using Drizzle ORM:
// Example using Drizzle ORM
await db
.insert(mcpServersTable)
.values({
uuid: "123e4567-e89b-12d3-a456-426614174000",
name: "Remote SSE Server",
type: "SSE",
url: "https://remote-mcp.example.com/events",
bearerToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", // <-- static token
headers: {}, // optional extra headers
});
Frontend Hook Usage
Implement bearer token authentication in a React component:
import { useConnection } from "@/hooks/useConnection";
function RemoteMcpConnector() {
const { connectionStatus } = useConnection({
mcpServerUuid: "123e4567-e89b-12d3-a456-426614174000",
transportType: "SSE",
url: "https://remote-mcp.example.com/events",
command: "",
args: "",
env: {},
// Provide a static token that will be used instead of OAuth
bearerToken: "my‑static‑bearer‑token",
// Optional custom header name
headerName: "X‑My‑Auth",
isMetaMCP: false,
enabled: true,
});
return <div>Status: {connectionStatus}</div>;
}
Server-Side Client Creation
Create an authenticated MCP client on the backend:
import { createMetaMcpClient } from "@/lib/metamcp/client";
import { getMcpServers } from "@/lib/metamcp/fetch-metamcp";
async function connectToRemote(uuid: string) {
const servers = await getMcpServers(uuid);
const serverParams = servers[uuid];
// The function automatically chooses OAuth or bearer token.
const { client, transport } = createMetaMcpClient(serverParams);
// `client` can now be used to issue MCP requests.
await client.initialize(transport!);
}
Summary
- MetaMCP supports dual authentication strategies: OAuth access tokens take precedence over static bearer tokens stored in the database.
- Static tokens are persisted in the
bearer_tokencolumn defined inapps/backend/src/db/schema.tsand retrieved viagetMcpServersinapps/backend/src/lib/metamcp/fetch-metamcp.ts. - Automatic header injection occurs in
apps/backend/src/lib/metamcp/client.ts, where the transport layer checksserverParams.oauth_tokens?.access_tokenbefore falling back toserverParams.bearerToken. - Frontend flexibility is provided by the
useConnectionhook inapps/frontend/hooks/useConnection.ts, supporting custom header names and explicit token overrides. - Both SSE and STREAMABLE_HTTP transports implement identical authentication logic, ensuring consistent behavior across connection types.
Frequently Asked Questions
Can I use both OAuth and static bearer tokens simultaneously?
No, MetaMCP implements a priority-based fallback system rather than combining tokens. According to the logic in apps/backend/src/lib/metamcp/client.ts, the system first checks for serverParams.oauth_tokens?.access_token and only falls back to serverParams.bearerToken if the OAuth token is undefined or empty. This ensures that OAuth tokens take precedence when available, while static tokens provide a reliable backup for servers that don't support OAuth flows.
How do I configure a custom authentication header name?
You can specify a custom header name through the useConnection hook in apps/frontend/hooks/useConnection.ts. Pass the headerName parameter (e.g., X-API-Key), and the hook will use that header instead of the standard Authorization header. When a custom header is specified, the hook also sets the x-custom-auth-header metadata header to inform the backend of the custom field name, allowing for flexible authentication schemes beyond standard Bearer tokens.
Where are bearer tokens stored securely in MetaMCP?
Static bearer tokens are stored in the PostgreSQL database in the bearer_token column, defined in apps/backend/src/db/schema.ts as a text field. The tokens are retrieved server-side via the getMcpServers function in apps/backend/src/lib/metamcp/fetch-metamcp.ts and injected into transport headers before any client-side exposure. This architecture ensures that sensitive tokens remain on the backend unless explicitly provided through the frontend hook for specific use cases.
What transport types support bearer token authentication?
MetaMCP supports bearer token authentication across both SSE (Server-Sent Events) and STREAMABLE_HTTP transports, as implemented in apps/backend/src/lib/metamcp/client.ts. The authentication logic at lines 84-94 (SSE) and lines 115-124 (STREAMABLE_HTTP) follows identical patterns, checking for OAuth tokens before falling back to static bearer tokens. This ensures consistent authentication behavior regardless of whether your remote MCP server uses event streams or standard HTTP request-response patterns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →