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_authenable_auth_query→use_query_param_authenable_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_idand 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:
X-API-Keyheader (always checked)- Query parameters (
api_keyorapikey) — only ifendpoint.use_query_param_authistrue
Authentication Flow
The middleware implements a decision tree with four branches:
- No authentication required — Both
enable_api_key_authandenable_oautharefalse. The middleware callsnext()immediately. - API key only — Validates the key via
apiKeysRepository.validateApiKeyand checks access withcheckApiKeyAccess. - OAuth only — Validates bearer tokens via
validateOAuthToken. - 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: truevia theBOOTSTRAP_ENDPOINTSenvironment variable or the Enable API-key authentication toggle in the UI (apps/frontend/components/edit-endpoint.tsx). - Create keys through
BOOTSTRAP_API_KEYS(generatingsk_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 fromenable_auth_queryin bootstrap) to allow?api_key=in URLs. - Validate requests using the
X-API-Keyheader or query parameters, processed byauthenticateApiKeyinapps/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →