How to Configure API Key Authentication for MetaMCP Endpoints

MetaMCP secures its REST-style endpoints using API key authentication configured via the BOOTSTRAP_ENDPOINTS environment variable or UI toggles, validated through the X-API-Key header or query parameters by middleware in apps/backend/src/middleware/api-key-oauth.middleware.ts.

The metatool-ai/metamcp repository implements a flexible authentication system for its Model Context Protocol (MCP) endpoints. This guide explains how to enable and configure API key authentication for MetaMCP endpoints, create keys, and understand the underlying validation logic.

Enabling API Key Authentication for Endpoints

MetaMCP stores authentication settings in the endpoints table, defined by the Zod schema in packages/zod-types/src/endpoints.zod.ts. The boolean column enable_api_key_auth controls whether an endpoint requires API key validation.

Configuration via Environment Variables

During initial deployment, use the BOOTSTRAP_ENDPOINTS JSON array to define endpoints and their authentication settings. The bootstrapEndpoints function in apps/backend/src/lib/bootstrap.service.ts (lines 640-645) translates these fields into database columns:

BOOTSTRAP_ENDPOINTS=[
  {
    "name": "private-api",
    "description": "Requires API key authentication",
    "enable_auth": true,
    "enable_auth_query": true,
    "enable_auth_oauth": false,
    "is_public": false,
    "user_email": "admin@example.com"
  }
]

The mapping works as follows:

  • enable_auth → enable_api_key_auth
  • enable_auth_query → use_query_param_auth
  • enable_auth_oauth → enable_oauth

Configuration via the Frontend UI

For existing deployments, navigate to the endpoint management interface. The React component in apps/frontend/components/edit-endpoint.tsx (line 138) renders a toggle for enableApiKeyAuth. When checked, the form submits enable_api_key_auth: true to the backend API.

Creating and Managing API Keys

API keys are stored in the api_keys table and validated by apiKeysRepository.validateApiKey in apps/backend/src/db/repositories/api-keys.repo.ts.

Bootstrap Configuration

Define keys in the BOOTSTRAP_API_KEYS environment variable:

BOOTSTRAP_API_KEYS=[
  {"name": "Public", "is_public": true},
  {"name": "AdminKey", "is_public": false, "user_email": "admin@example.com"}
]

The bootstrap service generates random keys with the format sk_mt_<64-hex-chars> and inserts them into the database (lines 95-107 in apps/backend/src/lib/bootstrap.service.ts).

Key Validation Logic

The middleware distinguishes between public and private keys:

  • Public keys can only access endpoints where is_public = true
  • Private keys are linked to a specific user via user_id and can access that user's private endpoints

The checkApiKeyAccess function in apps/backend/src/middleware/api-key-oauth.middleware.ts (lines 73-85) enforces these rules.

How the Authentication Middleware Works

The core logic resides in apps/backend/src/middleware/api-key-oauth.middleware.ts, specifically the authenticateApiKey function (lines 80-115).

Token Extraction

The extractAuthToken function (lines 49-52) checks for credentials in this order:

  1. X-API-Key header (always checked)
  2. Query parameters (api_key or apikey) — only if endpoint.use_query_param_auth is true

Authentication Flow

The middleware implements a decision tree with four branches:

  1. No authentication required — Both enable_api_key_auth and enable_oauth are false. The middleware calls next() immediately.
  2. API key only — Validates the key via apiKeysRepository.validateApiKey and checks access with checkApiKeyAccess.
  3. OAuth only — Validates bearer tokens via validateOAuthToken.
  4. Both enabled — Attempts OAuth validation first (if the token looks like an OAuth token), otherwise falls back to API key validation.

If validation fails, the middleware returns structured JSON errors (invalid_api_key, invalid_token, etc.) and respects rate limiting via authRateLimiter.

Making Authenticated Requests

Once configured, clients can authenticate using the generated keys.

Using the X-API-Key Header

curl -H "X-API-Key: sk_mt_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" \
     https://meta-mcp.example.com/api/v1/private-api/health

Using Query Parameters

If the endpoint has use_query_param_auth enabled (set via enable_auth_query: true in bootstrap or the UI):

curl "https://meta-mcp.example.com/api/v1/private-api/health?api_key=sk_mt_0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"

Troubleshooting Common Issues

Symptom Likely Cause Fix
401 invalid_api_key The endpoint has enable_api_key_auth set to false, or you're using query parameters but use_query_param_auth is false. Enable enable_auth: true (bootstrap) or check the Enable API-key authentication toggle in the UI. For query params, also enable enable_auth_query: true.
403 Access denied You're using a public API key to access a private endpoint, or a private key owned by a different user than the endpoint owner. Create a private key linked to the endpoint owner's email in BOOTSTRAP_API_KEYS, or ensure the endpoint is_public: true if using public keys.
429 Rate limit Multiple failed authentication attempts triggered the authRateLimiter. Wait for the rate limit window to reset, or verify your key value matches exactly (check for trailing whitespace or copy-paste errors).

Summary

  • Enable API key authentication by setting enable_api_key_auth: true via the BOOTSTRAP_ENDPOINTS environment variable or the Enable API-key authentication toggle in the UI (apps/frontend/components/edit-endpoint.tsx).
  • Create keys through BOOTSTRAP_API_KEYS (generating sk_mt_<64-hex> format) or the admin interface, distinguishing between public and private keys.
  • Configure query parameter support by setting use_query_param_auth: true (mapped from enable_auth_query in bootstrap) to allow ?api_key= in URLs.
  • Validate requests using the X-API-Key header or query parameters, processed by authenticateApiKey in apps/backend/src/middleware/api-key-oauth.middleware.ts.
  • Enforce access control through checkApiKeyAccess, ensuring public keys access only public endpoints and private keys match endpoint ownership.

Frequently Asked Questions

How do I enable query parameter authentication for MetaMCP endpoints?

Set enable_auth_query: true in your BOOTSTRAP_ENDPOINTS JSON configuration, which maps to the use_query_param_auth database column. Alternatively, enable the corresponding toggle in the endpoint editing UI. This allows clients to pass the API key via ?api_key= or ?apikey= query strings instead of the X-API-Key header.

What is the difference between public and private API keys in MetaMCP?

Public keys (is_public: true) are not linked to a specific user and can only access endpoints marked as public (is_public: true). Private keys are associated with a user via the user_id column and can access that specific user's private endpoints. The checkApiKeyAccess function in apps/backend/src/middleware/api-key-oauth.middleware.ts enforces these restrictions, returning 403 errors for unauthorized access attempts.

Can I use both API key and OAuth authentication on the same MetaMCP endpoint?

Yes. When both enable_api_key_auth and enable_oauth are set to true for an endpoint, the middleware attempts OAuth validation first if the token resembles an OAuth token (starts with mcp_token_). If OAuth validation fails or the token format indicates an API key, it falls back to API key validation via apiKeysRepository.validateApiKey. This allows flexible authentication strategies for different client types.

Where are API keys stored and how are they validated in MetaMCP?

API keys are stored in the api_keys table with columns for key (the token string), user_id (nullable for public keys), is_active, and metadata. Validation occurs in apps/backend/src/db/repositories/api-keys.repo.ts via the validateApiKey method, which checks if the key exists, is active, and matches the provided token. The middleware then uses checkApiKeyAccess to verify the key has permission to access the specific endpoint based on public/private status and ownership.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →