# Endpoints
Source: https://docs.metamcp.com/en/concepts/endpoints
Create public endpoints that expose namespaces as accessible MCP servers
A **MetaMCP Endpoint** is a public interface that exposes a namespace as an accessible MCP server. Endpoints handle authentication and provide URLs that MCP clients can connect to.
## What are Endpoints?
Endpoints serve as the bridge between your internal namespaces and external MCP clients:
* **Expose namespaces** as public MCP servers
* **Handle authentication** via API keys
* **Support multiple transports** (SSE, Streamable HTTP, OpenAPI)
```
https://your-metamcp.com/metamcp/my-endpoint/sse
https://your-metamcp.com/metamcp/my-endpoint/mcp
https://your-metamcp.com/metamcp/my-endpoint/api
https://your-metamcp.com/metamcp/my-endpoint/api/openapi.json
```
## Endpoint Management
### Available Actions
From the endpoints dashboard, you can:
* **Edit** endpoint settings
* **Copy URLs** for different transport types
* **View** the associated namespace
* **Delete** endpoints
### URL Formats
Each endpoint provides multiple URL formats:
* **SSE**: `/metamcp/{name}/sse`
* **Streamable HTTP**: `/metamcp/{name}/mcp`
* **OpenAPI**: `/metamcp/{name}/api`
* **OpenAPI Schema**: `/metamcp/{name}/api/openapi.json`
## Next Steps
Generate API keys for secure endpoint access
Learn about organizing MCP servers into namespaces
Connect your endpoints to MCP clients
Manage the MCP servers within your namespaces
# Inspector
Source: https://docs.metamcp.com/en/concepts/inspector
Debug and inspect MCP servers and MetaMCP endpoints with the built-in inspector
The **MetaMCP Inspector** is a built-in tool that allows you to easily test and debug your managed MCP servers and MetaMCP endpoints. It offers functionality similar to the official MCP Inspector, providing a convenient way to validate your connections and server behavior.
## Next Steps
Learn how to configure and debug MCP servers
Common issues and solutions for MetaMCP
Test your configurations with actual MCP clients
Set up production monitoring and alerting
# MCP Servers
Source: https://docs.metamcp.com/en/concepts/mcp-servers
Learn how to configure and manage MCP server instances in MetaMCP
A **MCP Server** is a configuration that tells MetaMCP how to start and manage a Model Context Protocol server. These servers provide tools, resources, and prompts that can be aggregated and exposed through MetaMCP endpoints.
## What is a MCP Server?
MCP Servers are the building blocks of MetaMCP. Each server configuration defines:
* **How to start the server** (command, arguments, environment)
* **What type of server it is** (STDIO, SSE, Streamable HTTP)
* **Authentication requirements** (if any)
* **Resource dependencies** (Python packages, Node modules, etc.)
```json theme={null}
{
"name": "HackerNews",
"type": "STDIO",
"command": "uvx",
"args": ["mcp-hn"],
"description": "Access HackerNews stories and comments"
}
```
## Server Types
MetaMCP supports three types of MCP servers:
**Most common type** - Communicates via standard input/output streams
```json theme={null}
{
"type": "STDIO",
"command": "uvx",
"args": ["mcp-server-package"],
"env": {
"API_KEY": "your-api-key"
}
}
```
**Use cases:**
* Python packages installed via `uvx`
* Node.js packages via `npx`
* Custom executable scripts
**Server-Sent Events** - Communicates via SSE (Server-Sent Events)
```json theme={null}
{
"type": "SSE",
"url": "https://api.example.com/sse",
"bearerToken": "your-bearer-token",
"headers": {
"X-Custom-Header": "value"
}
}
```
You can leave bearerToken as blank if the server uses OAuth.
**HTTP-based streaming** - Streamable HTTP is now the standard for remote MCP
```json theme={null}
{
"type": "STREAMABLE_HTTP",
"url": "https://api.example.com/mcp",
"bearerToken": "your-bearer-token",
"headers": {
"X-Custom-Header": "value"
}
}
```
You can leave bearerToken as blank if the server uses OAuth.
## Configuration Options
### Basic Configuration
```json Required Fields theme={null}
{
"name": "unique-server-name",
"type": "STDIO|SSE|STREAMABLE_HTTP",
"command": "command-to-run", // STDIO only
"args": ["arg1", "arg2"], // STDIO only
"url": "https://...", // SSE/STREAMABLE_HTTP only
}
```
```json Optional Fields theme={null}
{
"description": "Human-readable description",
"env": {
"KEY": "value"
},
"bearerToken": "auth-token", // SSE/STREAMABLE_HTTP only
"headers": { // SSE/STREAMABLE_HTTP only
"X-Custom-Header": "value"
}
}
```
### Environment Variables
Pass environment variables to STDIO servers:
```json theme={null}
{
"name": "TimeServer",
"type": "STDIO",
"command": "uvx",
"args": ["mcp-server-time", "--local-timezone=America/New_York"],
"env": {
"TZ": "America/New_York"
}
}
```
#### Environment Variable Interpolation
Use `${ENV_VAR}` syntax to reference environment variables at runtime:
```json theme={null}
{
"name": "ExampleServer",
"type": "STDIO",
"command": "uvx",
"args": ["mcp-example"],
"env": {
"API_KEY": "${API_KEY}",
"DEBUG": "true"
}
}
```
**Benefits:**
* **Secure**: API keys and secrets aren't hardcoded in configs
* **Flexible**: Values resolved from container environment
* **Backward compatible**: Raw values still work as before
**How it works:**
* `${VAR_NAME}` gets replaced with `process.env.VAR_NAME` at runtime
* Missing variables log a warning but don't crash the server
* Secrets are automatically redacted in logs
### Authentication
For servers requiring authentication:
```json STDIO with API Keys theme={null}
{
"env": {
"API_KEY": "your-secret-key"
}
}
```
```json Remote with Bearer Token theme={null}
{
"bearerToken": "your-bearer-token"
}
```
### Custom Headers
Add custom HTTP headers to **SSE and Streamable HTTP servers**:
```json theme={null}
{
"type": "SSE",
"url": "https://api.example.com/sse",
"headers": {
"X-API-Key": "your-api-key",
"X-API-Version": "v2",
"Organization-ID": "org-123"
}
}
```
Useful when your server requires:
* Multiple authentication headers (API keys + bearer tokens)
* Gateway or proxy authentication
* Organization-specific headers
## Managing MCP Servers
### Adding Servers
1. **Navigate** to MCP Servers in the MetaMCP dashboard
2. **Click** "Add Server"
3. **Configure** the server details
4. **Test** the configuration
5. **Save** to make it available for namespaces
### Bulk Import/Export
MetaMCP supports bulk import and export of MCP server configurations for easy migration and backup.
#### Exporting Servers
Export all your configured MCP servers to a JSON file:
1. **Navigate** to MCP Servers in the dashboard
2. **Click** "Export JSON" button
3. **Choose** to either download the file or copy to clipboard
```json theme={null}
{
"mcpServers": {
"HackerNews": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-hn"],
"description": "Access HackerNews stories and comments"
},
"TimeServer": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-server-time"],
"env": {
"TZ": "America/New_York"
},
"description": "Time and timezone utilities"
},
"RemoteAPI": {
"type": "streamable_http",
"url": "https://api.example.com/mcp",
"bearerToken": "your-bearer-token",
"headers": {
"X-API-Version": "v2"
},
"description": "Remote MCP server via HTTP"
}
}
}
```
#### Importing Servers
Import multiple MCP servers from a JSON configuration:
1. **Navigate** to MCP Servers in the dashboard
2. **Click** "Import JSON" button
3. **Paste** or type your JSON configuration
4. **Click** "Import" to add the servers
```json STDIO Server Format theme={null}
{
"mcpServers": {
"ServerName": {
"type": "stdio",
"command": "uvx",
"args": ["package-name"],
"env": {
"API_KEY": "your-key"
},
"description": "Optional description"
}
}
}
```
```json SSE Server Format theme={null}
{
"mcpServers": {
"ServerName": {
"type": "sse",
"url": "https://api.example.com/sse",
"bearerToken": "your-token",
"headers": {
"X-Custom-Header": "value"
},
"description": "Optional description"
}
}
}
```
```json Streamable HTTP Format theme={null}
{
"mcpServers": {
"ServerName": {
"type": "streamable_http",
"url": "https://api.example.com/mcp",
"bearerToken": "your-token",
"headers": {
"X-Custom-Header": "value"
},
"description": "Optional description"
}
}
}
```
**Type Values (Case-Insensitive):**
* `"stdio"`, `"STDIO"`, `"std"` → STDIO
* `"sse"`, `"SSE"` → SSE
* `"streamable_http"`, `"STREAMABLE_HTTP"`, `"streamablehttp"`, `"http"` → STREAMABLE\_HTTP
**Import Behavior:**
* Servers with existing names will be **updated** with new configuration
* New servers will be **created**
* Invalid configurations will be **skipped** with error messages
* The import process shows success/failure counts
Use bulk import/export for:
* **Environment migration** (dev → staging → production)
* **Team collaboration** (sharing server configurations)
* **Backup and restore** (configuration backups)
* **Quick setup** (deploying multiple servers at once)
### Idle Session Management
MetaMCP pre-allocates idle sessions for better performance:
* **Default**: 1 idle session per server
* **Configurable**: Adjust based on usage patterns
* **Auto-scaling**: Sessions created on demand
* **Cleanup**: Idle sessions recycled after timeout
## Custom Dockerfile for Dependencies
If your MCP servers require additional dependencies beyond `uvx` or `npx`, you can customize the MetaMCP Dockerfile:
```dockerfile theme={null}
FROM metamcp:latest
# Install Python dependencies
RUN pip install requests beautifulsoup4
# Install system packages
RUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js packages globally
RUN npm install -g some-mcp-package
```
Custom dependencies increase the Docker image size and startup time. Consider using lightweight alternatives when possible.
## Troubleshooting
**Common causes:**
* Missing dependencies (install via custom Dockerfile)
* Incorrect command or arguments
* Environment variables not set
* Network connectivity issues (for SSE/Streamable HTTP)
**Debug steps:**
1. Check server logs in MetaMCP dashboard
2. Test command manually in terminal
3. Verify environment variables
4. Check network connectivity
**Optimization strategies:**
* Increase idle session count for frequently used servers
* Use local servers instead of remote when possible
* Pre-install dependencies in custom Docker image
* Configure appropriate timeout values
**Common problems:**
* Expired API keys or bearer tokens
* Incorrect environment variable names
* Missing required headers
* Rate limiting from external APIs
**Solutions:**
1. Refresh API keys/tokens
2. Check server documentation for required auth
3. Implement proper error handling
4. Add retry logic with backoff
## Next Steps
Group your MCP servers into organized namespaces
Create public endpoints to access your servers
Transform and filter MCP requests and responses
Connect your configured servers to MCP clients
# Middleware
Source: https://docs.metamcp.com/en/concepts/middleware
Transform MCP requests and responses with pluggable middleware
**Middleware** in MetaMCP allows you to intercept and transform MCP requests and responses at the namespace level. This powerful feature enables you to add functionality like filtering, logging, validation, and security without modifying individual MCP servers.
## (Middleware is still under active development)
# Namespaces
Source: https://docs.metamcp.com/en/concepts/namespaces
Group MCP servers and manage tools with unified endpoints
A **Namespace** in MetaMCP is a logical grouping of MCP servers that allows you to organize multiple servers into a single unified MCP endpoint.
## What are Namespaces?
Namespaces allow you to:
* **Group multiple MCP servers** into a unified collection
* **Create a single MCP endpoint** that aggregates tools from all servers
* **Enable/disable individual servers** within the namespace
* **Control tool visibility** by enabling/disabling specific tools
* **Support both private and public** namespace access
## How Namespaces Work
When you create a namespace:
1. **Select MCP servers** to include in the namespace
2. **Tools are automatically discovered** from all active servers
3. **Tools are prefixed** with server names (e.g., `ServerName__toolName`)
4. **Create public endpoints** to expose the namespace externally
## Creating a Namespace
1. **Navigate** to Namespaces in the MetaMCP dashboard
2. **Click** "Create Namespace"
3. **Configure** basic details:
* **Name**: Unique identifier for your namespace
* **Description**: Optional description of the namespace purpose
* **Ownership**: Private (your use) or Public (organization-wide)
4. **Select MCP servers** to include in the namespace
5. **Save** the namespace
### Ownership Types
* **Private Namespace**: Only accessible by the creator
* **Public Namespace**: Accessible by entire organization
**Note**: Public namespaces can only contain public MCP servers.
## Managing Servers and Tools
### Server Management
* **View server status** in the namespace servers table
* **Enable/disable servers** individually using the status toggle
* **Add or remove servers** by editing the namespace
* **Monitor server health** and connectivity
### Tool Management
* **Automatic discovery**: Tools are discovered from all active servers
* **Tool prefixing**: Tools are prefixed with server names to avoid conflicts
* **Status control**: Enable/disable individual tools per namespace
* **Tool overrides**: Customize tool name, title, and description for each namespace
* **Tool filtering**: Inactive tools are automatically filtered from listings
### Tool Naming Convention
Tools follow the pattern: `{ServerName}__{originalToolName}`. When chaining
MetaMCP gateways, `originalToolName` can itself contain nested prefixes (for
example, `OuterServer__InnerServer__my_tool`).
Example: A `search` tool from "WebSearch" server becomes `WebSearch__search`
## Public Access
To expose a namespace externally:
1. **Create an endpoint** that points to your namespace
2. **Configure authentication** (API key recommended)
3. **Share the endpoint URL** with external users
The endpoint provides:
* **MCP access**: Standard MCP protocol support
* **REST API**: HTTP endpoints for each tool
* **OpenAPI documentation**: Auto-generated API documentation
## Example
A development namespace containing filesystem and git servers:
```json theme={null}
{
"name": "development-tools",
"description": "Essential development tools",
"servers": [
{
"name": "filesystem",
"status": "ACTIVE",
"tools": ["read_file", "write_file", "list_directory"]
},
{
"name": "git-helper",
"status": "ACTIVE",
"tools": ["git_status", "git_commit", "git_diff"]
}
]
}
```
Available tools through the namespace:
* `filesystem__read_file`
* `filesystem__write_file`
* `filesystem__list_directory`
* `git-helper__git_status`
* `git-helper__git_commit`
* `git-helper__git_diff`
## Next Steps
Expose your namespace through public endpoints
Learn about configuring MCP servers
Connect your namespace to MCP clients
Test and debug your namespace tools
# null
Source: https://docs.metamcp.com/en/deployment/custom-deployment
This guide walks you through deploying MetaMCP on a DigitalOcean VPS running Ubuntu from scratch, as an example.
## Prerequisites
* A DigitalOcean account
* A domain name pointing to your VPS
* Basic knowledge of Linux command line
## System Requirements
MetaMCP requires at least **2GB-4GB of memory** for optimal performance. The larger the instance, the better the performance due to MCP server pre-allocation and Docker operations.
**Recommended DigitalOcean Droplet:**
* **Basic/Regular**: 2GB RAM, 1 vCPU, 50GB SSD (\$12/month)
* **Better Performance**: 4GB RAM, 2 vCPU, 80GB SSD (\$24/month)
## Step 1: Create and Configure Your VPS
### 1.1 Create a Droplet
1. Log into your DigitalOcean account
2. Click "Create" → "Droplets"
3. Choose **Ubuntu 22.04 LTS** as the OS
4. Select a plan with at least 2GB RAM
5. Choose a datacenter region close to your users
6. Add your SSH key for secure access
7. Create the droplet
### 1.2 Initial Server Setup
Connect to your server via SSH:
```bash theme={null}
ssh root@your_server_ip
```
Update the system:
```bash theme={null}
apt update && apt upgrade -y
```
Install essential packages:
```bash theme={null}
apt install -y curl wget git ufw nginx certbot python3-certbot-nginx
```
Configure firewall:
```bash theme={null}
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
```
Create a non-root user (optional but recommended):
```bash theme={null}
adduser metamcp
usermod -aG sudo metamcp
# Switch to the new user
su - metamcp
```
## Step 2: Install Docker and Docker Compose
### 2.1 Install Docker
First, update your package index and install prerequisites:
```bash theme={null}
sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
```
Add Docker's official GPG key and repository:
```bash theme={null}
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
```
Install Docker CE:
```bash theme={null}
sudo apt update
sudo apt install -y docker-ce
```
Verify Docker is running:
```bash theme={null}
sudo systemctl status docker
```
### 2.2 Install Docker Compose
Download and install Docker Compose:
```bash theme={null}
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```
### 2.3 Configure Docker User (Optional)
To run Docker commands without `sudo`:
```bash theme={null}
sudo usermod -aG docker $USER
```
Log out and back in for group changes to take effect, or run:
```bash theme={null}
newgrp docker
```
## Step 3: Deploy MetaMCP
### 3.1 Clone the Repository
```bash theme={null}
cd /opt
sudo git clone https://github.com/metatool-ai/metamcp.git
sudo chown -R $USER:$USER metamcp
cd metamcp
```
### 3.2 Configure Environment
```bash theme={null}
cp example.env .env
```
Edit the `.env` file with your domain and settings:
```bash theme={null}
nano .env
```
**⚠️ IMPORTANT SECURITY NOTE**: Because this is a production environment, make sure you modify `POSTGRES_PASSWORD` and `BETTER_AUTH_SECRET` from their default values. Also ensure you use HTTPS. A typical way to generate secure secrets is:
```bash theme={null}
openssl rand -hex 32 | base64
```
Key configurations to update:
```env theme={null}
# Your domain URL (MUST use HTTPS for production)
APP_URL=https://yourdomain.com
# Database - CHANGE THE PASSWORD from default!
DATABASE_URL=postgresql://postgres:YOUR_SECURE_PASSWORD@db:5432/metamcp
POSTGRES_PASSWORD=YOUR_SECURE_PASSWORD
# Generate secure secrets - DO NOT use the example values!
BETTER_AUTH_SECRET=your-super-secret-key-here
ENCRYPTION_KEY=your-32-character-encryption-key
# Optional: Configure OIDC if needed
# OIDC_CLIENT_ID=your-oidc-client-id
# OIDC_CLIENT_SECRET=your-oidc-client-secret
# OIDC_DISCOVERY_URL=https://your-provider.com/.well-known/openid-configuration
```
### 3.3 Update Docker Compose for Production
Edit `docker-compose.yml` to ensure proper volume naming:
```bash theme={null}
nano docker-compose.yml
```
Update the volumes section to avoid conflicts:
```yaml theme={null}
volumes:
metamcp_postgres_data:
driver: local
```
### 3.4 Start MetaMCP
```bash theme={null}
# Pull images and start services
docker-compose up -d
# Check if services are running
docker-compose ps
# View logs if needed
docker-compose logs -f
```
## Step 4: Configure Nginx Reverse Proxy
### 4.1 Create Nginx Configuration
Create a new site configuration:
```bash theme={null}
sudo nano /etc/nginx/sites-available/metamcp
```
Add the following configuration (replace `yourdomain.com` with your actual domain):
```nginx theme={null}
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
# SSL configuration (will be managed by Certbot)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
location / {
proxy_pass http://localhost:12008;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# SSE-specific optimizations for MCP connections
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 86400s; # 24 hours for long-lived SSE connections
proxy_send_timeout 86400s;
# HTTP/1.1 with proper connection handling for SSE
proxy_set_header Connection '';
proxy_http_version 1.1;
# Additional headers for better SSE support
proxy_set_header Cache-Control 'no-cache';
proxy_set_header X-Accel-Buffering 'no';
}
# Optional: Increase client max body size for file uploads
client_max_body_size 100M;
}
```
### 4.2 Enable the Site
```bash theme={null}
# Enable the site
sudo ln -s /etc/nginx/sites-available/metamcp /etc/nginx/sites-enabled/
# Remove default site
sudo rm /etc/nginx/sites-enabled/default
# Test nginx configuration
sudo nginx -t
# Start nginx
sudo systemctl enable nginx
sudo systemctl start nginx
```
## Step 5: SSL Certificate with Let's Encrypt
### 5.1 Obtain SSL Certificate
First, temporarily use HTTP only configuration for initial certificate:
```bash theme={null}
# Create temporary HTTP-only config
sudo nano /etc/nginx/sites-available/metamcp-temp
```
Add this temporary configuration:
```nginx theme={null}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:12008;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
Enable temporary config:
```bash theme={null}
sudo ln -sf /etc/nginx/sites-available/metamcp-temp /etc/nginx/sites-enabled/metamcp
sudo nginx -t && sudo systemctl reload nginx
```
Obtain the certificate:
```bash theme={null}
sudo certbot --nginx -d yourdomain.com
```
### 5.2 Restore Full Configuration
After obtaining the certificate, restore the full configuration:
```bash theme={null}
sudo ln -sf /etc/nginx/sites-available/metamcp /etc/nginx/sites-enabled/metamcp
sudo nginx -t && sudo systemctl reload nginx
```
### 5.3 Set Up Auto-Renewal
```bash theme={null}
# Test auto-renewal
sudo certbot renew --dry-run
# Add to crontab for automatic renewal
sudo crontab -e
```
Add this line to check for renewal twice daily:
```
0 12 * * * /usr/bin/certbot renew --quiet
```
# null
Source: https://docs.metamcp.com/en/development/architecture
## Architecture Overview (WIP)
### Main
```mermaid theme={null}
sequenceDiagram
participant MCPClient as MCP Client (e.g., Claude Desktop)
participant MetaMCP as MetaMCP Server
participant MCPServers as Installed MCP Servers
MCPClient ->> MetaMCP: Request list tools
loop For each listed MCP Server
MetaMCP ->> MCPServers: Request list_tools
MCPServers ->> MetaMCP: Return list of tools
end
MetaMCP ->> MetaMCP: Aggregate tool lists & apply middleware
MetaMCP ->> MCPClient: Return aggregated list of tools
MCPClient ->> MetaMCP: Call tool
MetaMCP ->> MCPServers: call_tool to target MCP Server
MCPServers ->> MetaMCP: Return tool response
MetaMCP ->> MCPClient: Return tool response
```
### Idle Session invalidation
```mermaid theme={null}
sequenceDiagram
participant User
participant Frontend
participant Backend
participant McpServerPool
participant MetaMcpServerPool
participant McpServer
User->>Frontend: Updates MCP server command/args
Frontend->>Backend: PATCH /mcp-servers/{uuid}
Backend->>Backend: Update server in database
Note over Backend: New invalidation flow
Backend->>McpServerPool: invalidateIdleSession(serverUuid, newParams)
McpServerPool->>McpServerPool: Cleanup existing idle session
McpServerPool->>McpServer: Terminate old connection
McpServerPool->>McpServer: Create new connection with updated params
McpServerPool->>McpServerPool: Store new idle session
Backend->>Backend: Find affected namespaces
Backend->>MetaMcpServerPool: invalidateIdleServers(namespaceUuids)
MetaMcpServerPool->>MetaMcpServerPool: Cleanup namespace servers
MetaMcpServerPool->>MetaMcpServerPool: Create new namespace servers
Backend->>Frontend: Success response
Frontend->>User: "Server updated successfully"
Note over User,McpServer: Next connection will use updated parameters
```
# Contributing to MetaMCP
Source: https://docs.metamcp.com/en/development/contributing
Learn how to contribute to MetaMCP development and help improve the project
We welcome contributions to MetaMCP! This comprehensive guide will help you get started with contributing to the project, whether you're fixing bugs, adding features, or improving documentation.
## Getting Started
### Prerequisites
Before contributing, ensure you have:
* **Node.js 18+** and **pnpm** installed
* **Docker** for running PostgreSQL and testing
* **Git** for version control
* **Basic understanding** of TypeScript, React, and MCP protocol
### Development Setup
1. **Fork the repository** on GitHub
2. **Clone your fork** locally:
```bash theme={null}
git clone https://github.com/YOUR_USERNAME/metamcp.git
cd metamcp
```
3. **Add upstream remote**:
```bash theme={null}
git remote add upstream https://github.com/metatool-ai/metamcp.git
```
Install project dependencies using pnpm:
```bash theme={null}
pnpm install
```
This will install dependencies for all workspaces in the monorepo.
Set up your development environment:
```bash theme={null}
cp example.env .env
```
Modify the `.env` file as needed for your development setup.
Start PostgreSQL using Docker:
```bash theme={null}
docker compose up -d postgres
# or start full stack
docker compose up -d
```
First time migration (edit `.env.local` first)
```bash theme={null}
cd apps/backend
pnpm db:migrate:dev
```
## Development Workflow
### Creating a Feature Branch (naming not required)
```bash Feature Branch theme={null}
git checkout -b feature/your-feature-name
```
```bash Bug Fix Branch theme={null}
git checkout -b fix/issue-description
```
```bash Documentation Branch theme={null}
git checkout -b docs/documentation-update
```
### Making Changes
Follow these guidelines when making changes:
* **Follow TypeScript best practices**
* **Use ESLint and Prettier** for consistent formatting
* **Write descriptive commit messages**
* **Add JSDoc comments** for complex functions
* **Ensure type safety** throughout the codebase
* **Test your changes** manually
### Testing Your Changes
Run the development server and test your changes:
```bash theme={null}
pnpm dev
```
This starts both frontend and backend in development mode.
Ensure code quality:
```bash theme={null}
# Run linting
pnpm lint
# Fix linting issues
pnpm lint:fix
```
Test with Docker to ensure production compatibility:
```bash theme={null}
docker compose build
docker compose up
```
## Types of Contributions
### Bug Fixes
**Before reporting a bug:**
1. Check existing issues to avoid duplicates
2. Try to reproduce the issue consistently
3. Gather relevant information (OS, browser, MetaMCP version)
4. Include steps to reproduce the problem
**Bug report template:**
```markdown theme={null}
## Bug Description
Brief description of the issue
## Steps to Reproduce
1. Step one
2. Step two
3. Expected vs actual behavior
## Environment
- OS: [e.g., macOS 14.0]
- Browser: [e.g., Chrome 120]
- MetaMCP Version: [e.g., 1.0.0]
## Additional Context
Screenshots, logs, or other relevant information
```
**When fixing bugs:**
1. Create a branch: `fix/issue-number-description`
2. Implement the fix
3. Test manually to ensure the fix works
4. Update documentation if necessary
### Feature Development
**Before implementing a new feature:**
1. **Open an issue** to discuss the feature
2. **Provide use cases** and justification
3. **Consider impact** on existing functionality
4. **Get feedback** from maintainers
5. **Plan the implementation** approach
**Feature development process:**
1. **Create feature branch** from main
2. **Implement incrementally** with regular commits
3. **Update documentation**
4. **Test with real MCP servers**
5. **Consider i18n impact** for UI changes
### Documentation
**When updating documentation:**
* Use clear, concise language
* Include code examples where helpful
* Add screenshots for UI changes
* Update both README and docs site
* Test all code examples
* Consider multiple audiences (beginners, advanced users)
**Adding new language support:**
1. Create new locale directory: `public/locales/[locale]/`
2. Copy English files as templates
3. Translate content maintaining key structure
4. Update i18n configuration
5. Test the new locale thoroughly
6. Submit PR with translation files
## Pull Request Process
### Before Submitting
* ✅ **Code follows project standards**
* ✅ **Fix liniting as much as possible (somewhat tolerant as we dev rapidly)** (`pnpm lint`)
* ✅ **No TypeScript errors**
* ✅ **Documentation updated** if needed
* ✅ **Changes tested manually**
* ✅ **Database migrations** included if needed
* ✅ **No sensitive information** in commits
## Specialized Contributions
### OIDC Provider Setup
MetaMCP supports OpenID Connect for enterprise SSO. When working on OIDC features:
**Required environment variables:**
```bash theme={null}
# Required
OIDC_CLIENT_ID=your-oidc-client-id
OIDC_CLIENT_SECRET=your-oidc-client-secret
OIDC_DISCOVERY_URL=https://your-provider.com/.well-known/openid-configuration
OIDC_AUTHORIZATION_URL=https://your-provider.com/auth/authorize
# Optional
OIDC_PROVIDER_ID=oidc
OIDC_SCOPES=openid email profile
OIDC_PKCE=true
```
**For OIDC development:**
1. Use a test provider (Auth0, Keycloak)
2. Configure redirect URI: `${APP_URL}/api/auth/oauth2/callback/oidc`
3. Test the authentication flow
4. Verify user creation in database
5. Enable debug logging for troubleshooting
### Database Changes
When making database schema changes:
**Creating migrations:**
```bash theme={null}
# Generate migration after schema changes
cd apps/backend
pnpm db:generate
# Apply migrations
pnpm db:migrate:dev # which uses env.local for PG related env vars
# Reset database (development only)
pnpm db:reset
```
**Database development workflow:**
1. Update schema in `apps/backend/src/db/schema.ts`
2. Create repository in `apps/backend/src/db/repositories/`
3. Create serializer in `apps/backend/src/db/serializers/`
4. Add tRPC procedures in `apps/backend/src/trpc/`
5. Update frontend types in `packages/zod-types/`
6. Generate and apply migrations
### Frontend Development
**Using shadcn/ui components:**
```bash theme={null}
# Add new components
cd apps/frontend
npx shadcn-ui@latest add [component-name]
```
**Component guidelines:**
* Follow existing design patterns
* Ensure accessibility compliance
* Add proper TypeScript types
* Include loading and error states
**For UI changes:**
1. Add English translations first
2. Update other locales or mark for translation
3. Use the `useTranslations()` hook
4. Test with different languages
5. Ensure text expansion doesn't break layout
## Community Guidelines
### Code of Conduct
We're committed to providing a welcoming and inclusive environment:
* **Be respectful** and inclusive in all interactions
* **Provide constructive feedback** and be open to receiving it
* **Focus on collaboration** and helping each other succeed
* **Respect different perspectives** and experience levels
* **Follow project guidelines** and maintain code quality
### Communication
Join our Discord server for:
* Development discussions
* Getting help with contributions
* Sharing ideas and feedback
* Community announcements
[Join MetaMCP Discord](https://discord.gg/mNsyat7mFX)
Use GitHub Issues and Discussions for:
* Bug reports and feature requests
* Technical discussions
* Documentation feedback
* Project roadmap discussions
## Getting Help
### Resources
Get help from the community
Browse existing issues and discussions
## Recognition
We appreciate all contributions to MetaMCP! Contributors are recognized through:
* **GitHub contributors list** on the repository
* **Release notes** mentioning significant contributions
Thank you for helping make MetaMCP better for everyone! 🚀
## Next Steps
Browse open issues and start contributing
# Internationalization (i18n)
Source: https://docs.metamcp.com/en/development/i18n
Add multi-language support to MetaMCP with Next.js locale routing and client-side translations
MetaMCP uses **Next.js locale-based routing** and **client-side translations** to support multiple languages. This guide explains the i18n system and how to add new languages.
## Current Language Support
MetaMCP currently supports:
* **English (en)** - Default language
* **Chinese Simplified (zh)** - Full translation available
The author maintains both languages for translation accuracy, but contributions for additional languages are welcome.
## Project Structure
The internationalization system is organized as follows:
```bash theme={null}
apps/frontend/
├── app/
│ └── [locale]/ # Locale-based routing
│ ├── layout.tsx # Locale layout
│ ├── (sidebar)/ # Sidebar layout group
│ └── ...
├── public/locales/
│ ├── en/ # English translations
│ │ ├── common.json
│ │ ├── auth.json
│ │ ├── navigation.json
│ │ ├── mcp-servers.json
│ │ ├── namespaces.json
│ │ ├── endpoints.json
│ │ ├── api-keys.json
│ │ ├── settings.json
│ │ ├── search.json
│ │ ├── inspector.json
│ │ ├── logs.json
│ │ └── validation.json
│ └── zh/ # Chinese translations
│ └── (same structure)
├── lib/
│ └── i18n.ts # Client-side i18n utilities
├── hooks/
│ ├── useLocale.ts # Hook to get current locale
│ └── useTranslations.ts # Hook for client-side translations
├── components/
│ └── language-switcher.tsx # Language switching component
└── middleware.ts # Locale detection and routing
```
## How It Works
### URL Structure
MetaMCP uses locale-based routing:
* **English (default)**: `/mcp-servers`, `/settings`, `/namespaces`
* **Chinese**: `/zh/mcp-servers`, `/zh/settings`, `/zh/namespaces`
### Middleware
The `middleware.ts` file handles:
* **Locale detection** from URL, cookies, and Accept-Language header
* **Automatic redirects** to appropriate locale
* **Authentication checks**
```typescript middleware.ts theme={null}
import { NextRequest } from 'next/server';
import { getLocale, getLocalizedPath } from '@/lib/i18n';
export function middleware(request: NextRequest) {
// Detect locale from URL, cookie, or headers
const locale = getLocale(request);
// Redirect if needed
if (!request.nextUrl.pathname.startsWith(`/${locale}`)) {
const localizedPath = getLocalizedPath(request.nextUrl.pathname, locale);
return Response.redirect(new URL(localizedPath, request.url));
}
}
```
```typescript lib/i18n.ts theme={null}
export function getLocalizedPath(path: string, locale: string): string {
if (locale === 'en') {
return path; // Default locale doesn't need prefix
}
return `/${locale}${path}`;
}
export function detectLocale(request: NextRequest): string {
// Check URL first, then cookies, then Accept-Language
// Return detected locale or fallback to 'en'
}
```
## Using Translations
### Client Components
For client-side components, use the `useTranslations` hook:
```tsx Basic Usage theme={null}
"use client";
import { useTranslations } from "@/hooks/useTranslations";
function ClientComponent() {
const { t, isLoading, locale } = useTranslations();
if (isLoading) return
);
```
### Translation Key Format
Use colon-separated namespaces for organization:
```json theme={null}
{
"server": {
"create": "Create Server",
"edit": "Edit Server",
"delete": "Delete Server",
"status": {
"online": "Online",
"offline": "Offline",
"error": "Error"
},
"validation": {
"nameRequired": "Server name is required",
"commandRequired": "Command is required"
}
}
}
```
**Usage**: `t('mcp-servers:server.create')`, `t('mcp-servers:server.status.online')`
## Translation File Organization
### Namespace Structure
Each translation namespace serves a specific purpose:
**Shared UI elements and general terms**
```json theme={null}
{
"actions": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"search": "Search"
},
"status": {
"loading": "Loading...",
"error": "Error",
"success": "Success"
},
"form": {
"required": "This field is required",
"invalid": "Invalid input"
}
}
```
**Authentication-related text**
```json theme={null}
{
"signIn": "Sign In",
"signOut": "Sign Out",
"signUp": "Sign Up",
"email": "Email",
"password": "Password",
"forgotPassword": "Forgot Password?",
"createAccount": "Create Account",
"loginWithOIDC": "Login with OIDC"
}
```
**Menu items and navigation text**
```json theme={null}
{
"dashboard": "Dashboard",
"mcpServers": "MCP Servers",
"namespaces": "Namespaces",
"endpoints": "Endpoints",
"apiKeys": "API Keys",
"settings": "Settings",
"inspector": "MCP Inspector",
"logs": "Live Logs"
}
```
**MCP server-specific translations**
```json theme={null}
{
"server": {
"create": "Create Server",
"edit": "Edit Server",
"name": "Server Name",
"type": "Server Type",
"command": "Command",
"args": "Arguments",
"env": "Environment Variables"
},
"types": {
"stdio": "STDIO",
"http": "HTTP",
"websocket": "WebSocket"
}
}
```
### Best Practices for Translation Keys
* **Use descriptive, hierarchical keys**: `server.validation.nameRequired`
* **Use camelCase for consistency**: `signIn`, `mcpServers`
* **Group related translations**: All server-related terms under `server`
* **Keep context clear**: `auth:signIn` vs `form:signIn` if different
* **Use interpolation for dynamic content**: `"welcome": "Welcome, {{name}}!"`
## Adding New Languages
### Step 1: Create Translation Files
1. **Create language directory** in `public/locales/`:
```bash theme={null}
mkdir -p public/locales/es # For Spanish
```
2. **Copy English files** as templates:
```bash theme={null}
cp -r public/locales/en/* public/locales/es/
```
3. **Translate the content** in each JSON file:
```json theme={null}
// public/locales/es/common.json
{
"actions": {
"save": "Guardar",
"cancel": "Cancelar",
"delete": "Eliminar",
"edit": "Editar",
"create": "Crear"
}
}
```
### Step 2: Update Configuration
Add the new locale to your i18n configuration:
```typescript lib/i18n.ts theme={null}
export const SUPPORTED_LOCALES = ['en', 'zh', 'es'] as const;
export type Locale = typeof SUPPORTED_LOCALES[number];
export const LOCALE_NAMES: Record = {
en: 'English',
zh: '中文',
es: 'Español'
};
```
```typescript middleware.ts theme={null}
import { SUPPORTED_LOCALES } from '@/lib/i18n';
export function middleware(request: NextRequest) {
// Update locale detection to include new language
const supportedLocales = SUPPORTED_LOCALES;
// ... rest of middleware logic
}
```
### Step 3: Update Language Switcher
The language switcher will automatically include new languages:
```tsx theme={null}
// components/language-switcher.tsx
import { LOCALE_NAMES, SUPPORTED_LOCALES } from '@/lib/i18n';
export function LanguageSwitcher() {
return (
);
}
```
### Step 4: Test the Implementation
1. **Add test content** in the new language
2. **Navigate to** `/{locale}/` URLs (e.g., `/es/mcp-servers`)
3. **Verify translations** appear correctly
4. **Test language switching** functionality
5. **Check fallbacks** work for missing translations
## Translation Workflow
### For New Features
When adding new features to MetaMCP:
1. **Add English translations first** in appropriate namespace
2. **Use descriptive keys** that make sense in context
3. **Test with English** to ensure keys work correctly
4. **Add other languages** (or mark for translation)
5. **Test all languages** before deployment
### For Contributors
**To contribute translations:**
1. Fork the repository
2. Create new language files or update existing ones
3. Follow the existing key structure
4. Test your translations locally
5. Submit a Pull Request with your changes
**Tips:**
* Keep translations concise but clear
* Maintain consistent terminology
* Consider cultural context, not just literal translation
* Test with longer text to ensure UI still works
**Using AI tools like Cursor/Claude:**
```prompt theme={null}
Translate this English JSON file to Spanish, maintaining the same structure and keys:
{
"server": {
"create": "Create Server",
"edit": "Edit Server"
}
}
Keep technical terms like "MCP" and "API" unchanged.
```
## Troubleshooting
### Common Issues
**When translations don't appear:**
1. Check the translation key exists in the JSON file
2. Verify the namespace is correct (`common:save` vs `auth:save`)
3. Ensure the locale file exists and is valid JSON
4. Check browser console for missing key warnings
5. Verify the component is using `useTranslations` correctly
**Server/client translation mismatches:**
1. Ensure consistent locale detection between server and client
2. Use the `isLoading` state from `useTranslations`
3. Avoid rendering translations during SSR if locale might change
4. Test with JavaScript disabled to check SSR behavior
**URL routing problems:**
1. Check middleware configuration for new locales
2. Verify `getLocalizedPath` function handles new languages
3. Test direct navigation to localized URLs
4. Ensure fallback behavior works correctly
### Debugging Tools
```bash Development Debugging theme={null}
# Check for missing translation keys
grep -r "t('" apps/frontend/app --include="*.tsx" | \
grep -v "useTranslations"
# Validate JSON files
for file in public/locales/*/*.json; do
echo "Checking $file"
cat "$file" | jq . > /dev/null
done
```
```typescript Debug Component theme={null}
"use client";
import { useTranslations } from "@/hooks/useTranslations";
export function TranslationDebugger() {
const { t, locale, isLoading } = useTranslations();
return (
Current locale: {locale}
Is loading: {isLoading.toString()}
Test translation: {t('common:save')}
);
}
```
## Future Enhancements
### Planned Features
* **RTL language support** for Arabic, Hebrew
* **Date/time localization** with proper formatting
* **Number formatting** based on locale
* **Currency formatting** for pricing features
* **Pluralization rules** for complex language requirements
### Contributing Guidelines
* 📝 **Add English first**: Always start with English translations
* 🔍 **Test thoroughly**: Verify all locales work correctly
* 📊 **Use consistent terminology**: Maintain glossary for technical terms
* 🌍 **Consider context**: Adapt to cultural differences, not just language
* 📱 **Test UI impact**: Ensure longer translations don't break layout
* 🤝 **Collaborate**: Work with native speakers when possible
## Next Steps
Learn how to contribute to MetaMCP development
Understand the frontend architecture and development setup
Learn about UI component development with i18n
Test your internationalization changes
# MetaMCP Documentation
Source: https://docs.metamcp.com/en/index
MCP Aggregator, Orchestrator, Middleware, Gateway in one docker
**MetaMCP** is a MCP proxy that lets you dynamically aggregate MCP servers into a unified MCP server, and apply middlewares. MetaMCP itself is a MCP server so it can be easily plugged into **ANY** MCP clients.
## 🎯 Use Cases
Group MCP servers into namespaces, host them as meta-MCPs, and assign public endpoints (SSE or Streamable HTTP) with authentication.
Pick only the tools you need when remixing MCP servers. Apply pluggable middleware for observability and security.
Use as enhanced MCP inspector with saved server configs, and inspect your MetaMCP endpoints.
Use as Elasticsearch for MCP tool selection (coming soon).
Generally developers can use MetaMCP as **infrastructure** to host dynamically composed MCP servers through a unified endpoint, and build agents on top of it.
## Quick Start
Get MetaMCP running in minutes with Docker Compose:
```bash Clone & Setup theme={null}
git clone https://github.com/metatool-ai/metamcp.git
cd metamcp
cp example.env .env
```
```bash Start with Docker theme={null}
docker compose up -d
```
Follow our complete setup guide to configure your first MCP servers and namespaces.
## Core Concepts
Understanding these key concepts will help you get the most out of MetaMCP:
Learn how to configure and manage MCP server instances.
Group MCP servers and apply middleware at the namespace level.
Create public endpoints for your namespaces with different transport options.
Transform MCP requests and responses with pluggable middleware.
## Integrations
Connect MetaMCP to your favorite tools and platforms:
Configure Cursor to use MetaMCP endpoints via mcp.json
Connect Claude Desktop using mcp-proxy for STDIO compatibility
## Features
* Better Auth for frontend & backend
* Session cookies for secure connections
* API key authentication for external access
* OpenID Connect (OIDC) support for enterprise SSO
* Multi-tenancy with public/private scopes
* **SSE (Server-Sent Events)** for MCP backward compatibility and real-time connections
* **Streamable HTTP** for Streamable HTTP-based MCP communication (now standard remote MCP connection)
* **OpenAPI endpoints** compatible with clients like Open WebUI
* **STDIO compatibility** via proxy for local
* Built-in support for English and Chinese
* Easy to add additional languages
* Locale-based routing and content
* Pre-allocated idle sessions for reduced cold start time
* Configurable session management
* Designed for at least 2GB-4GB memory instances
* Docker-based deployment with nginx support
* Cluster scaling and separation of MCP manager and worker will release in the future.
## Getting Help
Set up a local development environment and contribute to MetaMCP.
Explore the complete API documentation for MetaMCP endpoints.
Report bugs, request features, or browse existing issues.
Join our Discord server for support and community discussions.
# Claude Desktop Integration
Source: https://docs.metamcp.com/en/integrations/claude-desktop
Configure Claude Desktop to connect to MetaMCP endpoints using mcp-proxy
**Claude Desktop** integration allows you to access MetaMCP tools directly through Claude's interface. Since Claude Desktop only supports stdio servers, you'll need a local proxy to connect to MetaMCP's remote endpoints.
## Prerequisites
Before starting, ensure you have:
* **Claude Desktop** installed and running
* **MetaMCP** running locally or deployed
* **Active endpoint** configured in MetaMCP
* **API key** generated (if authentication is enabled)
## Basic Configuration
### Using mcp-proxy (Recommended)
Since MetaMCP endpoints are remote only (SSE, Streamable HTTP), Claude Desktop needs a local proxy to connect. Based on testing, `mcp-proxy` is the recommended solution for API key authentication.
```json Streamable HTTP (Recommended) theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
}
}
}
}
```
```json SSE (Alternative) theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/your-endpoint-name/sse"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
}
}
}
}
```
```json Multiple Endpoints theme={null}
{
"mcpServers": {
"MetaMCP-Dev": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/dev-tools/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_dev_key"
}
},
"MetaMCP-Research": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/research-tools/sse"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_research_key"
}
}
}
}
```
## Configuration File Location
Edit Claude Desktop's configuration file at:
* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
* **Linux**: `~/.config/claude/claude_desktop_config.json`
## Authentication Methods
**Most common method** using environment variable:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_key_here"
}
}
}
}
```
**For public endpoints** without authentication:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/public-tools/sse"
]
}
}
}
```
## Remote/Production Setup
For remote MetaMCP instances, simply replace the localhost URL:
```json theme={null}
{
"mcpServers": {
"MetaMCP-Production": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"https://your-metamcp-domain.com/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_production_key"
}
}
}
}
```
## Important Notes
* **Replace** `your-endpoint-name` with your actual endpoint name
* **Replace** `sk_mt_your_api_key_here` with your MetaMCP API key
* **mcp-proxy** handles the protocol conversion between stdio and HTTP/SSE
* **Environment variables** are the secure way to pass API keys
* For detailed troubleshooting, see [issue #76](https://github.com/metatool-ai/metamcp/issues/76)
# Cursor Integration
Source: https://docs.metamcp.com/en/integrations/cursor
Configure Cursor IDE to use MetaMCP endpoints via mcp.json
**Cursor** is a popular AI-powered code editor that supports MCP (Model Context Protocol) integration. This guide shows you how to connect Cursor to your MetaMCP endpoints for enhanced coding capabilities.
Also refer to Cursor's doc on MCP [https://docs.cursor.com/context/mcp](https://docs.cursor.com/context/mcp)
## Prerequisites
Before starting, ensure you have:
* **Cursor IDE** installed and running
* **MetaMCP** running locally or deployed
* **Active endpoint** configured in MetaMCP
* **API key** generated (if authentication is enabled)
## Basic Configuration
### Simple mcp.json Setup
Create or edit your `mcp.json` file in Cursor's configuration directory:
```json Basic Configuration theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/your-endpoint-name/mcp"
}
}
}
```
```json With Authentication theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/your-endpoint-name/mcp",
"headers": {
"Authorization": "Bearer sk_mt_your_api_key_here"
}
}
}
}
```
```json Multiple Endpoints theme={null}
{
"mcpServers": {
"MetaMCP-Dev": {
"url": "http://localhost:12008/metamcp/dev-tools/mcp",
"headers": {
"Authorization": "Bearer sk_mt_dev_key"
}
},
"MetaMCP-Research": {
"url": "http://localhost:12008/metamcp/research-tools/mcp",
"headers": {
"Authorization": "Bearer sk_mt_research_key"
}
}
}
}
```
## Configuration Options
### Transport Types
MetaMCP supports different transport protocols. **Streamable HTTP is recommended** for Cursor:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/your-endpoint-name/mcp"
}
}
}
```
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/your-endpoint-name/sse"
}
}
}
```
### Authentication Methods
**Most common method** using Authorization header:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/your-endpoint-name/mcp",
"headers": {
"Authorization": "Bearer sk_mt_your_key_here"
}
}
}
}
```
**For public endpoints** without authentication:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"url": "http://localhost:12008/metamcp/public-tools/sse"
}
}
}
```
# General Stdio Integration using `mcp-proxy` with API Key
Source: https://docs.metamcp.com/en/integrations/general-stdio-with-api-key
Configure any stdio-based MCP client to connect to MetaMCP endpoints using mcp-proxy
**General Stdio Integration** allows any MCP client that supports stdio servers to connect to MetaMCP's remote endpoints. Since MetaMCP endpoints are remote-only (SSE, Streamable HTTP), you'll need a local proxy to bridge the connection.
## Prerequisites
Before starting, ensure you have:
* **MCP client** that supports stdio servers (Claude Desktop, Cursor, etc.)
* **MetaMCP** running locally or deployed
* **Active endpoint** configured in MetaMCP
* **API key** generated (if authentication is enabled)
* **mcp-proxy** installed (`uvx mcp-proxy`)
## Basic Configuration
### Using mcp-proxy (Required)
Since MetaMCP endpoints are remote only, you need `mcp-proxy` to convert between stdio and HTTP/SSE protocols.
```json Streamable HTTP (Recommended) theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
}
}
}
}
```
```json SSE (Alternative) theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/your-endpoint-name/sse"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
}
}
}
}
```
```json Multiple Endpoints theme={null}
{
"mcpServers": {
"MetaMCP-Dev": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/dev-tools/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_dev_key"
}
},
"MetaMCP-Research": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/research-tools/sse"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_research_key"
}
}
}
}
```
## Authentication Methods
**Most common method** using environment variable:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_key_here"
}
}
}
}
```
**For public endpoints** without authentication:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"http://localhost:12008/metamcp/your-endpoint-name/sse"
]
}
}
}
```
## Troubleshooting
### Common Issues
1. **Connection refused**: Ensure MetaMCP is running and accessible
2. **Authentication failed**: Verify API key is correct and has proper permissions
3. **mcp-proxy not found**: Install with `pip install mcp-proxy` or `uvx mcp-proxy`
### Debug Mode
Enable debug logging for mcp-proxy:
```json theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "uvx",
"args": [
"mcp-proxy",
"--transport",
"streamablehttp",
"--debug",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
],
"env": {
"API_ACCESS_TOKEN": "sk_mt_your_api_key_here"
}
}
}
}
```
## Important Notes
* **Replace** `your-endpoint-name` with your actual endpoint name
* **Replace** `sk_mt_your_api_key_here` with your MetaMCP API key
* **mcp-proxy** handles the protocol conversion between stdio and Streamable HTTP/SSE
* **Environment variables** are the secure way to pass API keys
Configure any stdio-based MCP client to connect to MetaMCP endpoints using mcp-remote with OAuth
Troubleshoot common OAuth-related issues
Configure Cursor IDE to use your MetaMCP endpoints
Set up Claude Desktop with MetaMCP using mcp-proxy
# General Stdio Integration using `mcp-remote` with OAuth
Source: https://docs.metamcp.com/en/integrations/general-stdio-with-oauth
Configure any stdio-based MCP client to connect to MetaMCP endpoints using mcp-remote with OAuth authentication
**General Stdio Integration with OAuth** allows any MCP client that supports stdio servers to connect to MetaMCP's remote endpoints using OAuth authentication. Since MetaMCP endpoints are remote-only (SSE, Streamable HTTP), you'll need a local proxy to bridge the connection.
## Prerequisites
Before starting, ensure you have:
* **MCP client** that supports stdio servers (Claude Desktop, Cursor, etc.)
* **MetaMCP** running locally or deployed with OAuth enabled
* **Active endpoint** configured in MetaMCP
* **OAuth application** registered in MetaMCP
* **mcp-remote** available via npx (`npx -y mcp-remote`)
## Basic Configuration
### Using mcp-remote (Required)
Since MetaMCP endpoints are remote only, you need `mcp-remote` to convert between stdio and HTTP/SSE protocols with OAuth authentication.
```json Basic OAuth Configuration theme={null}
{
"mcpServers": {
"MetaMCP": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:12008/metamcp/your-endpoint-name/mcp"
]
}
}
}
```
```json Multiple Endpoints theme={null}
{
"mcpServers": {
"MetaMCP-Dev": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:12008/metamcp/dev-tools/mcp"
]
},
"MetaMCP-Research": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:12008/metamcp/research-tools/mcp"
]
}
}
}
```
## OAuth Flow
When you first connect, `mcp-remote` will:
1. **Open your browser** to the OAuth authorization URL
2. **Prompt you to authorize** the application
3. **Redirect back** to the local callback server
4. **Store the tokens** locally for future use
5. **Establish the MCP connection** with authenticated access
### Token Management
* **Tokens are stored locally** by mcp-remote
* **Refresh tokens** are automatically used when access tokens expire
* **Clear tokens** by deleting the mcp-remote cache directory if needed
## Important Notes
* **Use** `http://localhost:12008/metamcp/your-endpoint-name/mcp` for OAuth authentication
* **Replace** `your-endpoint-name` with your actual endpoint name for public endpoints
* **mcp-remote** handles the protocol conversion between stdio and HTTP/SSE
* **OAuth flow** requires browser interaction on first connection
* **No manual OAuth setup** required - MetaMCP handles it automatically
Troubleshoot common OAuth-related issues
Configure any stdio-based MCP client to connect to MetaMCP endpoints using mcp-proxy
Configure Cursor IDE to use your MetaMCP endpoints
Set up Claude Desktop with MetaMCP using mcp-proxy
# Open WebUI Integration
Source: https://docs.metamcp.com/en/integrations/open-web-ui
Use MetaMCP to manage tools for Open WebUI
## Prerequisites
Before starting, ensure you have:
* Docker and Docker Compose installed
* Open WebUI running (locally or deployed)
* MetaMCP deployed with a properly configured `APP_URL` (default to `http://localhost:12008`)
## Step 1: Deploy MetaMCP with Proper Configuration
If you haven't already, clone MetaMCP and set it up:
```bash theme={null}
git clone https://github.com/metatool-ai/metamcp.git
cd metamcp
cp example.env .env
```
**Critical**: Configure your `APP_URL` properly in the `.env` file for Open WebUI integration:
```bash theme={null}
# For local Open WebUI accessing local MetaMCP
APP_URL=http://localhost:12008
# For deployed Open WebUI accessing deployed MetaMCP
APP_URL=https://your-metamcp-domain.com
# For local Open WebUI accessing deployed MetaMCP
APP_URL=https://your-metamcp-domain.com
```
Open WebUI must be able to reach your MetaMCP instance at the configured `APP_URL`. Ensure firewall rules and network configuration allow this access.
Also configure other production settings:
```bash theme={null}
POSTGRES_PASSWORD=your_secure_password
BETTER_AUTH_SECRET=your_auth_secret # Generate with: openssl rand -hex 32 | base64
```
Launch MetaMCP using Docker Compose:
```bash theme={null}
docker compose up -d
```
Verify it's running by visiting your configured `APP_URL`.
## Step 2: Configure MetaMCP for Open WebUI
1. Open your browser and go to your `APP_URL` (e.g., `http://localhost:12008`)
2. **Create an account** or log in
3. **(Recommended)** Disable new user registration in **Settings** for security
Add the MCP servers you want to expose to Open WebUI:
1. Navigate to **MCP Servers** in the sidebar
2. Click **"Add Server"** button
3. Configure your server (example with filesystem server):
**Basic Information:**
* **Name**: `hacker-news-server`
* **Description**: `Hacker News integration for fetching stories and comments`
* **Type**: `STDIO`
**Server Configuration:**
* **Command**: `uvx`
* **Arguments**: `mcp-hn`
* **Environment Variables**: (if needed)
**Ownership:**
* Choose **"Everyone (Public)"** for Open WebUI access
4. Click **"Create Server"**
Repeat this process for all MCP servers you want to make available to Open WebUI.
Group your MCP servers into a namespace for Open WebUI:
1. Go to **Namespaces** in the sidebar
2. Click **"Create Namespace"**
3. Configure the namespace:
**Basic Information:**
* **Name**: `openwebui-tools`
* **Description**: `Aggregated tools for Open WebUI integration`
**Ownership:**
* Choose **"Everyone (Public)"**
**Select MCP Servers:**
* Check all servers you want to include
* These will be aggregated into one endpoint
4. Click **"Create Namespace"**
Fine-tune which tools are available:
1. Click on your **"openwebui-tools"** namespace
2. Review the **Tools Management** section
3. Disable any tools you don't want Open WebUI to access
4. This helps keep the tool set focused and secure
## Step 3: Create OpenAPI Endpoint
Create an endpoint that Open WebUI can consume:
1. Navigate to **Endpoints** in the sidebar
2. Click **"Create Endpoint"**
3. Configure the endpoint:
**Basic Information:**
* **Name**: `openwebui-api`
* **Description**: `OpenAPI endpoint for Open WebUI integration`
**Ownership:**
* Choose **"Everyone (Public)"**
**Namespace Selection:**
* Select your **"openwebui-tools"** namespace
**API Key Authentication:**
* **Enable API Key Authentication**: Toggle ON
* **Use Query Parameter Authentication**: Toggle OFF (Open WebUI supports Bearer tokens)
**MCP Server Creation:**
* Check **"Automatically create an MCP server for this endpoint"**
4. Click **"Create Endpoint"**
**Your OpenAPI endpoint will be available at:**
* OpenAPI UI: `{APP_URL}/metamcp/openwebui-api/api`
* OpenAPI Schema: `{APP_URL}/metamcp/openwebui-api/api/openapi.json`
## Step 4: Generate API Key
In the last step, if you select **"Automatically create an MCP server for this endpoint"** option, then at least one API key will be automatically generated for you. Feel free to use it instead of creating a new one.
1. Go to **API Keys** in the sidebar
2. Click **"Generate Key"**
3. Configure the API key:
**Key Information:**
* **Description**: `Open WebUI Integration Key`
* **Scope**: **Public** (so Open WebUI can use it)
4. Click **"Generate Key"**
5. **Important**: Copy the generated key (starts with `sk_mt_`)
Save this key securely - it's only shown once and will be needed for Open WebUI configuration.
## Step 5: Configure Open WebUI
Open your Open Web UI page. Find settings.
In Settings pop up. Go to "Tools".
Under **"Manage Tool Servers"** on top right corner click on the **"+"** button to add a connection.
For **URL > Base URL** enter `{APP_URL}/metamcp/openwebui-api/api`. For example if `APP_URL` is `http://localhost:12008` then enter `http://localhost:12008/metamcp/openwebui-api/api`.
For **URL > openapi.json Path** enter `{APP_URL}/metamcp/openwebui-api/api/openapi.json`. For example if `APP_URL` is `http://localhost:12008` then enter `http://localhost:12008/metamcp/openwebui-api/api/openapi.json`.
Put the **"API Key"** generated in previous steps to **"Auth Bearer"** field.
Use the "refresh" button to test connection.
Close any pop ups. In home page click new chat. Then inspect the available tools.
In new chat, a query of "show top hacker news" would look like:
Then in new chats, with a model that supports tool calling, should automatically try to call tools if necessary.
## Troubleshooting
**Connection Errors:**
* Verify `APP_URL` is accessible from Open WebUI
* Check firewall and network configuration
* Ensure API key is correctly configured. Turn off Auth to test if it works first.
* With Auth off, you can manually visit e.g., `http://localhost:12008/metamcp/openwebui-api/api/openapi.json` to verify the `openapi.json`.
**Authentication Issues:**
* Verify API key format (should start with `sk_mt_`)
* Ensure Bearer token authentication is properly configured in Open WebUI
* Verify Authorization header format: `Bearer {your_api_key}`
**Tool Execution Failures:**
* Check MCP server status in MetaMCP dashboard
* Review tool permissions in namespace settings
* Monitor logs for specific error messages
**CORS Errors:**
* Ensure Open WebUI domain is allowed
* Check MetaMCP CORS configuration
* Verify APP\_URL matches access URL
* Check [MetaMCP GitHub Issues](https://github.com/metatool-ai/metamcp/issues)
* Join our [Discord community](https://discord.gg/mNsyat7mFX)
* Review Open WebUI documentation if necessary
# Quick Start
Source: https://docs.metamcp.com/en/quickstart
Get MetaMCP running in minutes and configure your first MCP servers
Get MetaMCP up and running in just a few minutes and configure your first MCP server aggregation.
## Prerequisites
Before starting, ensure you have:
* Docker and Docker Compose installed
* Git for cloning the repository
* Basic understanding of MCP (Model Context Protocol)
## Step 1: Installation
Clone MetaMCP from GitHub and navigate to the project directory:
```bash theme={null}
git clone https://github.com/metatool-ai/metamcp.git
cd metamcp
```
Copy the example environment file and customize as needed:
```bash theme={null}
cp example.env .env
```
If you modify `APP_URL` in the `.env` file, make sure you only access MetaMCP from that URL due to CORS policy enforcement.
In production environment, make sure you modify POSTGRES\_PASSWORD and BETTER\_AUTH\_SECRET. Also use HTTPS. A typical way to generate secrets is `openssl rand -hex 32 | base64`
Launch MetaMCP using Docker Compose:
```bash theme={null}
docker compose up -d
```
This will start:
* MetaMCP fullstack docker image
* PostgreSQL database
The first startup may take a few minutes as Docker images are pulled and downloaded.
## Step 2: Access MetaMCP
Once the containers are running:
1. **Open your browser** and go to `http://localhost:12008` (or your configured `APP_URL`)
2. **Create an account** or log in
3. **Explore the dashboard** - you'll see sections for MCP Servers, Namespaces, and Endpoints
4. **(Optional) Disable signup** You may only allow you and your team access MetaMCP, so once you setup the accounts, you can disable new user registration in Settings page.
## Step 3: Configure Your First MCP Server
1. Navigate to **MCP Servers** in the sidebar (or you can quickly add one from **Explore & Search** page)
2. Click **"Add Server"** button (top right)
3. In the dialog that opens, fill out the server configuration:
**Basic Information:**
* **Name**: `hackernews-server` (must be URL-compatible: letters, numbers, underscores, hyphens only)
* **Description**: `HackerNews MCP server for fetching stories and comments`
* **Type**: Select `STDIO` from dropdown
**Server Configuration:**
* **Command**: `uvx`
* **Arguments**: `mcp-hn` (space-separated arguments)
* **Environment Variables**: Leave empty (format: `KEY=value`, one per line)
**Ownership:**
* Choose **"For myself (Private)"** or **"Everyone (Public)"**
* Private servers are only accessible to you
* Public servers are accessible to all users
4. Click **"Create Server"**
5. You should see a success message: "MCP Server Created"
After creating the server, you can click on it to view details, test the connection, and see available tools.
**Why Namespaces?** Namespaces group multiple MCP servers together and provide a unified endpoint for external access.
1. Go to **Namespaces** in the sidebar
2. Click **"Create Namespace"** button (top right)
3. Fill out the namespace form:
**Basic Information:**
* **Name**: `news-information` (descriptive name for your server group)
* **Description**: `Namespace containing news and information retrieval tools`
**Ownership:**
* Choose **"For myself (Private)"** or **"Everyone (Public)"**
**Select MCP Servers:**
* You'll see a list of available MCP servers with checkboxes
* Check the box next to your **"hackernews-server"**
* You can select multiple servers for one namespace
* Each server shows its type (STDIO, SSE, etc.) and description
4. Click **"Create Namespace"**
5. Success message: "Namespace Created"
You can add or remove servers from a namespace later by editing it.
## Step 4: Manage Tools in Your Namespace
**Why Manage Tools?** Each MCP server may expose many tools, but you might only want to make certain tools available through your endpoint.
1. Go to **Namespaces** in the sidebar
2. Click on your **"news-information"** namespace to view details
3. You'll see three main sections:
**Connection Status:**
* Check if the namespace can connect to its MCP servers
* Green status means all servers are reachable
* Click **"Connect"** if needed to establish connection
**MCP Servers:**
* View all servers assigned to this namespace
* See server status (Active/Inactive/Error)
* Monitor server health and configuration
**Tools Management:**
* See all tools available from your servers
* Each tool shows:
* **Tool name** (e.g., `get_top_stories`, `get_story`)
* **Source server** (which server provides this tool)
* **Description** and input schema
* **Status** (enabled/disabled)
4. **Disable unwanted tools:**
* Uncheck tools you don't want to expose via the endpoint
* For example, you might keep `get_top_stories` but disable `get_user_info`
* This helps keep your endpoint focused and secure
5. **Refresh Tools** if needed to get latest tools from servers
Only enabled tools will be available when external applications use your endpoint.
## Step 5: Create an Endpoint
**What are Endpoints?** Endpoints provide external access to your namespaces via HTTP APIs that other applications can consume.
1. Navigate to **Endpoints** in the sidebar
2. Click **"Create Endpoint"** button (top right)
3. Configure your endpoint:
**Basic Information:**
* **Name**: `news-endpoint` (URL-compatible name - this becomes `/metamcp/news-endpoint`)
* **Description (Optional)**: `Public endpoint for news and information tools`
**Ownership:**
* Choose **"For myself (Private)"** or **"Everyone (Public)"**
**Namespace Selection:**
* Click the **"Select a namespace"** dropdown
* Choose your **"news-information"** namespace
* You'll see the namespace name and description in the dropdown
**API Key Authentication:**
* **Enable API Key Authentication**: Toggle ON (recommended)
* This requires API keys for endpoint access
* **Use Query Parameter Authentication**: Toggle ON/OFF
* When ON: Allows `?api_key=xxx` in URLs
* When OFF: Only accepts API keys in `Authorization: Bearer xxx` headers
**MCP Server Creation:**
* **"Automatically create an MCP server for this endpoint"**: Check this box
* This creates a Streamable HTTP MCP server configuration for inspection
4. Click **"Create Endpoint"**
5. Success message: "Endpoint Created"
**Your endpoint will be available at:**
* SSE: `http://localhost:12008/metamcp/news-endpoint/sse`
* Streamable HTTP: `http://localhost:12008/metamcp/news-endpoint/mcp`
* OpenAPI: `http://localhost:12008/metamcp/news-endpoint/api`
* Schema: `http://localhost:12008/metamcp/news-endpoint/api/openapi.json`
## Step 6: Generate API Key
1. Go to **API Keys** in the sidebar
2. Click **"Generate Key"** button
3. Fill out the API key form:
**Key Information:**
* **Description**: `My first MetaMCP API key for news endpoint`
* **Scope**:
* **Private**: Only you can use this key
* **Public**: All users can use this key
4. Click **"Generate Key"**
5. **Important**: Copy and save the key securely - it starts with `sk_mt_`
6. This key will be used to authenticate requests to your endpoints
The API key is only shown once. Make sure to copy it immediately.
## Step 7: Managing Your Configuration
**View Server Details:**
* Click on any server in the MCP Servers list
* See connection status, available tools, and configuration
* Test server connection and inspect tools
**Edit Servers:**
* Use the actions menu (⋯) next to each server
* Modify configuration, add environment variables
* Update commands and arguments
**Server States:**
* **Active**: Server is running and available
* **Inactive**: Server is configured but not running
* **Error**: Server has connection issues
**View Namespace Details:**
* Click on any namespace to see its servers and tools
* Monitor which servers are active in the namespace
* View aggregated tools from all servers
**Edit Namespaces:**
* Add or remove servers from existing namespaces
* Update name and description
* Change ownership settings
**Tool Management:**
* See all tools available across servers in the namespace
* Enable/disable specific tools
* View tool schemas and documentation
**Endpoint URLs:**
Each endpoint provides multiple access methods:
* **SSE**: Server-Sent Events for real-time communication
* **Streamable HTTP**: HTTP-based MCP communication
* **OpenAPI**: REST API with OpenAPI documentation
* **Schema**: OpenAPI JSON schema for integration
**Copy URLs:**
* Use the actions menu (⋯) to copy specific URLs
* Copy URLs with or without embedded API keys
* Use different formats for different integrations
**Edit Endpoints:**
* Change which namespace an endpoint maps to
* Update authentication settings
* Modify access permissions
## Next Steps
Learn how to configure different types of MCP servers (STDIO, HTTP, etc.)
Apply middleware to filter tools and transform requests/responses
Configure Cursor IDE to use your MetaMCP endpoints
Set up Claude Desktop with MetaMCP using mcp-proxy
## Troubleshooting
**CORS errors**: Ensure you're accessing MetaMCP from the URL specified in `APP_URL`.
**Database connection**: Check that PostgreSQL container is running with `docker ps`.
**Memory issues**: MetaMCP requires at least 2GB RAM for optimal performance.
**Server connection failures**: Check MCP server logs in the server detail pages.
**Authentication issues**: Verify API keys are active and correctly formatted.
* Browse [GitHub Issues](https://github.com/metatool-ai/metamcp/issues)
* Join our [Discord community](https://discord.gg/mNsyat7mFX)
# MCP OAuth Troubleshooting
Source: https://docs.metamcp.com/en/troubleshooting/oauth-troubleshooting
This page explains the authentication logic in MetaMCP exposed MCP endpoints and helps troubleshoot common OAuth-related issues.
> **Implementation Reference**: The authentication logic described in this page is implemented in [`apps/backend/src/middleware/api-key-oauth.middleware.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/middleware/api-key-oauth.middleware.ts).
## Authentication Scenarios
MetaMCP supports four different authentication configurations, each with specific behaviors:
### 1. Both API Key and OAuth Disabled
**Configuration**: `enable_api_key_auth: false`, `enable_oauth: false`
**Behavior**:
* All requests pass through without authentication
* No authentication headers required
* Suitable for public endpoints that don't require authentication
**Example Response**:
```json theme={null}
{
"message": "Public endpoint - no authentication required"
}
```
### 2. API Key Only (OAuth Disabled)
**Configuration**: `enable_api_key_auth: true`, `enable_oauth: false`
**Behavior**:
* Requires valid API key via `X-API-Key` header or query parameter
* **Critical Issue**: If API key is missing or invalid, some MCP clients (like Inspector) may attempt OAuth flow
* This can cause infinite refresh loops and 429 rate limit errors
**Valid Request**:
```bash theme={null}
curl -H "X-API-Key: mcp_1234567890abcdef" \
https://your-domain.com/api/endpoint
```
**Invalid/Missing API Key Response**:
```json theme={null}
{
"error": "authentication_required",
"error_description": "Authentication required via API key",
"supported_methods": [
"X-API-Key header",
"query parameter (api_key or apikey)"
],
"timestamp": "2024-01-01T00:00:00.000Z"
}
```
**⚠️ Common Issue**: MCP Inspector may still try OAuth flow even when only API keys are enabled, leading to:
* Infinite token refresh attempts
* 429 "Too Many Requests" errors
* Inspector becoming unusable
**Solution**: Ensure your MCP client is configured to use API keys only when OAuth is disabled. Make sure you are providing the correct API key or it may result in 429 rate limited errors.
### 3. Both API Key and OAuth Enabled
**Configuration**: `enable_api_key_auth: true`, `enable_oauth: true`
**Behavior**:
* Accepts both API keys and OAuth bearer tokens
* API key takes precedence if provided
* Falls back to OAuth if no API key is provided
* Most flexible configuration
**Authentication Flow**:
1. **No Token Provided**: Initiates OAuth flow
```json theme={null}
{
"error": "authentication_required",
"error_description": "Authentication required via OAuth bearer token or API key",
"supported_methods": [
"Authorization header (Bearer token)",
"X-API-Key header",
"query parameter (api_key or apikey)"
]
}
```
2. **Valid API Key**: Passes through
```bash theme={null}
curl -H "X-API-Key: mcp_1234567890abcdef" \
https://your-domain.com/api/endpoint
```
3. **Valid OAuth Token**: Passes through
```bash theme={null}
curl -H "Authorization: Bearer mcp_token_1234567890abcdef" \
https://your-domain.com/api/endpoint
```
4. **Invalid Credentials**: Returns 401 with rate limiting
```json theme={null}
{
"error": "invalid_credentials",
"error_description": "Authentication failed. Invalid credentials provided.",
"timestamp": "2024-01-01T00:00:00.000Z"
}
```
### 4. OAuth Only (API Key Disabled)
**Configuration**: `enable_api_key_auth: false`, `enable_oauth: true`
**Behavior**:
* Requires OAuth bearer token
* No API key support
* Clean OAuth-only authentication
**Valid Request**:
```bash theme={null}
curl -H "Authorization: Bearer mcp_token_1234567890abcdef" \
https://your-domain.com/api/endpoint
```
**No Token Response**:
```json theme={null}
{
"error": "authentication_required",
"error_description": "Authentication required via OAuth bearer token",
"supported_methods": ["Authorization header (Bearer token)"],
"WWW-Authenticate": "Bearer realm=\"MetaMCP\", scope=\"admin\""
}
```
**Invalid Token Response**:
```json theme={null}
{
"error": "invalid_token",
"error_description": "The provided OAuth token is invalid or has expired.",
"timestamp": "2024-01-01T00:00:00.000Z"
}
```
## Common Issues and Solutions
### Issue 1: Infinite OAuth Refresh Loop
**Symptoms**:
* MCP Inspector continuously refreshes tokens
* 429 "Too Many Requests" errors
* Inspector becomes unresponsive
**Root Cause**: MCP client attempting OAuth flow when only API keys are enabled
**Solutions**:
1. **Enable OAuth in endpoint configuration**:
```json theme={null}
{
"enable_api_key_auth": true,
"enable_oauth": true
}
```
2. **Configure MCP client to use API keys only**:
* Update client configuration to use `X-API-Key` header
* Disable OAuth flow in client settings
3. **Use OAuth-only configuration**:
```json theme={null}
{
"enable_api_key_auth": false,
"enable_oauth": true
}
```
### Issue 2: 429 Rate Limit Errors
**Symptoms**:
* "Too many failed authentication attempts" errors
* Temporary lockout from authentication attempts
**Solutions**:
1. **Wait for rate limit to reset** (1 minute)
2. If you have enabled Auth, make sure you never pass in a wrong API key.
```
```
### Issue 3: Access Denied (403) Errors
**Symptoms**:
* "Access denied" errors even with valid credentials
* "Public API keys cannot access private endpoints" messages
**Root Cause**: Access control based on endpoint ownership
**Solutions**:
1. **For Private Endpoints**: Use API key owned by endpoint creator
2. **For Public Endpoints**: Any valid API key or OAuth token works
3. **Check endpoint ownership**:
```bash theme={null}
# Get endpoint details
curl -H "Authorization: Bearer your-token" \
https://your-domain.com/api/endpoints/endpoint-uuid
```
### Issue 4: Wrong Authentication Method
**Symptoms**:
* "Authentication required via API key" when using OAuth
* "Authentication required via OAuth bearer token" when using API key
**Solutions**:
1. **Check endpoint configuration**:
```bash theme={null}
# Get endpoint configuration
curl -H "Authorization: Bearer your-token" \
https://your-domain.com/api/endpoints/endpoint-uuid
```
2. **Use correct authentication method**:
* API key: `X-API-Key` header or `api_key` query parameter
* OAuth: `Authorization: Bearer` header