Skip to main content

REST API

MCPProxy provides a REST API for server management and monitoring.

OpenAPI Specification

Interactive API documentation is available at http://127.0.0.1:8080/swagger/ when MCPProxy is running. The OpenAPI spec file is also available at oas/swagger.yaml.

Authentication

All /api/v1/* endpoints require authentication via API key:

# Using X-API-Key header (recommended)
curl -H "X-API-Key: your-api-key" http://127.0.0.1:8080/api/v1/servers

# Using query parameter
curl "http://127.0.0.1:8080/api/v1/servers?apikey=your-api-key"

Note: Unix socket connections bypass API key authentication (OS-level auth).

Base URL

http://127.0.0.1:8080/api/v1

Request ID Tracking

All API responses include an X-Request-Id header for request tracing and log correlation. This is useful for debugging issues and correlating errors with server logs.

Request Header

You can optionally provide your own request ID:

curl -H "X-API-Key: your-api-key" \
-H "X-Request-Id: my-custom-id-123" \
http://127.0.0.1:8080/api/v1/servers

Validation rules:

  • Pattern: ^[a-zA-Z0-9_-]{1,256}$
  • Max length: 256 characters
  • If missing or invalid, MCPProxy generates a UUID v4

Response Header

Every response includes the request ID:

X-Request-Id: my-custom-id-123

Error Responses

Error responses include the request_id in the JSON body for easy correlation:

{
"success": false,
"error": "server 'nonexistent' not found",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Log Correlation

Use the request ID to find related activity logs:

# Via CLI
mcpproxy activity list --request-id a1b2c3d4-e5f6-7890-abcd-ef1234567890

# Via API
curl "http://127.0.0.1:8080/api/v1/activity?request_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Endpoints

Status

GET /api/v1/status

Get server status and statistics.

Response:

{
"status": "running",
"version": "0.11.0",
"uptime": 3600,
"servers": {
"total": 5,
"connected": 4,
"quarantined": 1
},
"tools": {
"total": 42
}
}

Servers

GET /api/v1/servers

List all upstream servers with unified health status.

Header redaction and the mask format

By default, sensitive header values (Authorization, X-API-Key, Cookie, Set-Cookie, etc.) are replaced with a length-preserving mask of the form ••••<last2> (<N> chars) before serialization. This applies to:

  • GET /api/v1/servers and its single-server children
  • The /events SSE servers.changed payloads
  • The upstream_servers list MCP tool

The mask preserves enough information to identify which token is in use (the last two characters + total length) while keeping the secret out of the response. Values that are already secret references — ${keyring:NAME} or ${env:VAR} — pass through unchanged because they're labels, not secrets.

Setting reveal_secret_headers: true in mcp_config.json disables redaction on all three channels. This is not normally needed: the Web UI / macOS tray / CLI can edit, delete, and convert-to-secret without ever seeing the plaintext, because the PATCH endpoint deep-merges (omitted keys are preserved) and the config-to-secret endpoint reads the real value server-side. Flip the flag only if you need to inspect a raw value through the API for debugging.

The MCP upstream_servers tool was the original motivator for redaction (see PR #425) — a prompt-injected agent could otherwise read another upstream's PAT via upstream_servers list.

Response:

{
"success": true,
"data": {
"servers": [
{
"name": "github-server",
"protocol": "http",
"enabled": true,
"connected": true,
"quarantined": false,
"tool_count": 15,
"health": {
"level": "healthy",
"admin_state": "enabled",
"summary": "Connected (15 tools)",
"action": ""
}
},
{
"name": "oauth-server",
"protocol": "http",
"enabled": true,
"connected": false,
"quarantined": false,
"tool_count": 0,
"health": {
"level": "unhealthy",
"admin_state": "enabled",
"summary": "Token expired",
"detail": "OAuth access token has expired",
"action": "login"
}
}
]
}
}

Health Object Fields:

FieldTypeDescription
levelstringHealth level: healthy, degraded, or unhealthy
admin_statestringAdmin state: enabled, disabled, or quarantined
summarystringHuman-readable status message
detailstringOptional additional context about the status
actionstringSuggested remediation: login, restart, enable, approve, view_logs, or empty

PATCH /api/v1/servers/{name}

Partial update of an existing upstream server. All request fields are optional; omitted fields are preserved as-is.

The map-typed fields headers and env follow JSON Merge Patch (RFC 7396) semantics:

Value in patch bodyEffect on stored map
key present with a non-null string valueupsert (add or replace that key)
key present with JSON nulldelete that key
key absent from the patch bodypreserve as-is

This is the same convention the MCP upstream_servers patch tool uses. It lets the Web UI / macOS tray / CLI send a minimal diff — keys that match the server's current masked view (••••<last2> (<N> chars) — see Header redaction below) simply stay out of the patch body, so the real stored value is never overwritten by the mask string.

Request body (AddServerRequest — all fields optional):

{
"url": "https://api.example.com/mcp",
"command": "uvx",
"args": ["mcp-server-foo"],
"env": {"API_KEY": "new-value", "OLD_VAR": null},
"headers": {"X-Trace": "on", "X-Stale": null},
"working_dir": "/path/to/dir",
"protocol": "http",
"enabled": true,
"quarantined": false,
"isolation": {"enabled": true, "image": "node:20"}
}

Examples:

# Rotate a Bearer token without touching anything else on the server
curl -X PATCH -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"headers":{"Authorization":"Bearer new-token"}}' \
http://127.0.0.1:8080/api/v1/servers/synapbus

# Remove a stale header (the JSON null is the delete signal)
curl -X PATCH -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"headers":{"X-Stale":null}}' \
http://127.0.0.1:8080/api/v1/servers/synapbus

# Upsert one env var and delete another in a single round-trip
curl -X PATCH -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"env":{"LOG_LEVEL":"debug","OBSOLETE":null}}' \
http://127.0.0.1:8080/api/v1/servers/obsidian-pilot

Notes:

  • Empty string "" is set-to-empty, NOT delete. JSON Merge Patch is explicit about this — only the JSON null token deletes.
  • Boolean fields (enabled, quarantined, reconnect_on_use) use pointer-style semantics: absent = preserve, present = explicit value.

POST /api/v1/servers/{name}/config-to-secret

Atomically move a header or env value out of mcp_config.json and into the OS keyring. The backend reads the real value from the loaded config, stores it in the keyring under secret_name, and rewrites the config field with ${keyring:<secret_name>}. The client never needs to possess the plaintext — useful when the API redacts sensitive header values on the read path.

Request body:

{
"scope": "header",
"key": "Authorization",
"secret_name": "synapbus-auth"
}
FieldTypeDescription
scopestringheader or env
keystringThe key on the server's headers / env map
secret_namestringName to store the value under in the OS keyring

Response (200 OK):

{
"success": true,
"data": {
"message": "header \"Authorization\" on \"synapbus\" now references keyring secret \"synapbus-auth\"",
"reference": "${keyring:synapbus-auth}"
}
}

Failure cases:

StatusCause
400Missing scope / key / secret_name, invalid scope, value is already a ${keyring:…} or ${env:…} reference, or value is empty
404Server or key not found
500Secret resolver unavailable, keyring store failed, or config update failed

This endpoint is what the Web UI and macOS tray "Convert to secret" button calls. It works even for headers the API redacts (the backend has the real value on disk).

POST /api/v1/servers/{name}/enable

Enable a server.

POST /api/v1/servers/{name}/disable

Disable a server.

POST /api/v1/servers/{name}/quarantine

Place a server in quarantine to prevent tool execution. No request body required.

POST /api/v1/servers/{name}/unquarantine

Remove a server from quarantine to allow tool execution. No request body required.

POST /api/v1/servers/{name}/restart

Restart a server.

POST /api/v1/servers/{name}/login

Initiate OAuth authentication flow for a server.

Response (200 OK):

{
"success": true,
"data": {
"success": true,
"server_name": "github-server",
"correlation_id": "a1b2c3d4e5f6789012345678",
"browser_opened": true,
"message": "OAuth authentication started for server 'github-server'. Please complete authentication in browser."
}
}

OAuthStartResponse Fields:

FieldTypeDescription
successbooleanAlways true for successful initiation
server_namestringName of the server being authenticated
correlation_idstringUnique ID for tracking this OAuth flow
auth_urlstringAuthorization URL (for manual browser opening)
browser_openedbooleanWhether browser was automatically opened
browser_errorstringError message if browser opening failed
messagestringHuman-readable status message

Error Response (400 Bad Request):

OAuth errors return structured error responses for better debugging:

{
"success": false,
"error_type": "dcr_failed",
"server_name": "github-server",
"message": "Dynamic Client Registration failed: 403 Forbidden",
"suggestion": "Check if the OAuth server requires pre-registered clients",
"correlation_id": "a1b2c3d4e5f6789012345678",
"request_id": "req-xyz-123",
"details": {
"metadata": {
"protected_resource_url": "https://api.example.com/.well-known/oauth-protected-resource",
"authorization_server_url": "https://auth.example.com/.well-known/oauth-authorization-server",
"status": "ok"
},
"dcr": {
"attempted": true,
"status": "failed",
"error": "403 Forbidden"
}
},
"debug_hint": "For logs: mcpproxy upstream logs github-server"
}

OAuthFlowError Fields:

FieldTypeDescription
error_typestringError category: client_id_required, dcr_failed, metadata_discovery_failed, code_flow_failed
server_namestringName of the server
messagestringHuman-readable error description
suggestionstringActionable remediation hint
correlation_idstringFlow tracking ID
request_idstringHTTP request ID for log correlation
detailsobjectDiagnostic details (metadata status, DCR status)
debug_hintstringCLI command for debugging

POST /api/v1/servers/{name}/logout

Clear OAuth tokens and disconnect a server.

Tool Quarantine

POST /api/v1/servers/{name}/tools/approve

Approve pending or changed tools for a server. See Tool Quarantine for details.

Request Body:

{
"tools": ["create_issue", "delete_repo"]
}

Or approve all pending/changed tools:

{
"approve_all": true
}

Response:

{
"success": true,
"data": {
"approved": 2,
"tools": ["create_issue", "delete_repo"],
"message": "Approved 2 tools for server github-server"
}
}

GET /api/v1/servers/{name}/tools/{tool}/diff

Get the description/schema diff for a changed tool.

Response:

{
"success": true,
"data": {
"server_name": "github-server",
"tool_name": "delete_repo",
"status": "changed",
"approved_hash": "abc123...",
"current_hash": "def456...",
"previous_description": "Delete a repository",
"current_description": "Delete a repository (modified description)",
"previous_schema": "...",
"current_schema": "..."
}
}

GET /api/v1/servers/{name}/tools/export

Export all tool descriptions and schemas for a server. Useful for audit and compliance.

Query Parameters:

  • format - Export format: json (default) or text

Routing

GET /api/v1/routing

Get the current routing mode and available MCP endpoints.

Response:

{
"success": true,
"data": {
"routing_mode": "retrieve_tools",
"description": "BM25 search via retrieve_tools + call_tool variants (default)",
"endpoints": {
"default": "/mcp",
"direct": "/mcp/all",
"code_execution": "/mcp/code",
"retrieve_tools": "/mcp/call"
},
"available_modes": ["retrieve_tools", "direct", "code_execution"]
}
}

See Routing Modes for details on each mode.

Tools

GET /api/v1/tools

Search tools across all servers.

Query Parameters:

  • q - Search query (optional)
  • limit - Maximum results (default: 15)

Response:

{
"tools": [
{
"name": "github:create_issue",
"server": "github-server",
"description": "Create a new GitHub issue"
}
]
}

GET /api/v1/servers/{name}/tools

List tools for a specific server.

Real-time Updates

GET /events

Server-Sent Events (SSE) stream for live updates.

curl "http://127.0.0.1:8080/events?apikey=your-api-key"

Events include:

  • servers.changed - Server status changed
  • config.reloaded - Configuration reloaded
  • tools.indexed - Tool index updated
  • activity.tool_call.started - Tool call initiated
  • activity.tool_call.completed - Tool call finished
  • activity.policy_decision - Tool call blocked by policy

Error Responses

{
"error": "error message",
"code": "ERROR_CODE"
}
CodeDescription
401Unauthorized - Invalid or missing API key
404Not Found - Server or resource not found
500Internal Server Error

Configuration

GET /api/v1/config

Get current configuration.

POST /api/v1/config/apply

Apply configuration changes.

POST /api/v1/config/validate

Validate configuration without applying.

Diagnostics

GET /api/v1/diagnostics

Get system diagnostics.

GET /api/v1/doctor

Run health checks (same as mcpproxy doctor CLI).

GET /api/v1/info

Get application info, version, and update availability.

Response:

{
"success": true,
"data": {
"version": "v1.2.3",
"web_ui_url": "http://127.0.0.1:8080/?apikey=xxx",
"listen_addr": "127.0.0.1:8080",
"endpoints": {
"http": "127.0.0.1:8080",
"socket": "/Users/user/.mcpproxy/mcpproxy.sock"
},
"update": {
"available": true,
"latest_version": "v1.3.0",
"release_url": "https://github.com/smart-mcp-proxy/mcpproxy-go/releases/tag/v1.3.0",
"checked_at": "2025-01-15T10:30:00Z",
"is_prerelease": false
}
}
}

Response Fields:

FieldTypeDescription
versionstringCurrent MCPProxy version
web_ui_urlstringURL to access the web control panel
listen_addrstringServer listen address
endpoints.httpstringHTTP API endpoint address
endpoints.socketstringUnix socket path (empty if disabled)
updateobjectUpdate information (may be null if not checked yet)
update.availablebooleanWhether a newer version is available
update.latest_versionstringLatest version available on GitHub
update.release_urlstringURL to the GitHub release page
update.checked_atstringISO 8601 timestamp of last update check
update.is_prereleasebooleanWhether the latest version is a prerelease
update.check_errorstringError message if update check failed
Update Checking

MCPProxy automatically checks for updates every 4 hours. The update information is exposed via this endpoint and used by the tray application and web UI to show update notifications.

Docker

GET /api/v1/docker/status

Get Docker isolation status.

Secrets

GET /api/v1/secrets

List stored secrets.

GET /api/v1/secrets/{name}

Get secret metadata (not the value).

Sessions

GET /api/v1/sessions

List active MCP sessions.

GET /api/v1/sessions/{id}

Get session details.

Activity

Track and audit AI agent tool calls. See Activity Log for detailed documentation.

GET /api/v1/activity

List activity records with filtering and pagination.

Query Parameters:

ParameterTypeDescription
typestringFilter by type: tool_call, policy_decision, quarantine_change, server_change
serverstringFilter by server name
toolstringFilter by tool name
session_idstringFilter by MCP session ID
statusstringFilter by status: success, error, blocked
start_timestringFilter after this time (RFC3339)
end_timestringFilter before this time (RFC3339)
limitintegerMax records (1-100, default: 50)
offsetintegerPagination offset (default: 0)

Response:

{
"success": true,
"data": {
"activities": [
{
"id": "01JFXYZ123ABC",
"type": "tool_call",
"server_name": "github-server",
"tool_name": "create_issue",
"status": "success",
"duration_ms": 245,
"timestamp": "2025-01-15T10:30:00Z"
}
],
"total": 150,
"limit": 50,
"offset": 0
}
}

GET /api/v1/activity/{id}

Get full activity record details including request arguments and response data.

GET /api/v1/activity/export

Export activity records for compliance and auditing.

Query Parameters:

ParameterTypeDescription
formatstringExport format: json (JSON Lines) or csv
(filters)Same filters as list endpoint

Example:

# Export as JSON Lines
curl -H "X-API-Key: $KEY" "http://127.0.0.1:8080/api/v1/activity/export?format=json"

# Export as CSV
curl -H "X-API-Key: $KEY" "http://127.0.0.1:8080/api/v1/activity/export?format=csv"

Bulk Operations

POST /api/v1/servers/enable_all

Enable all servers.

POST /api/v1/servers/disable_all

Disable all servers.

POST /api/v1/servers/restart_all

Restart all servers.

POST /api/v1/servers/reconnect

Reconnect all servers.

OpenAPI Specification

The complete OpenAPI 3.1 specification is available at:

  • /swagger/ - Interactive Swagger UI
  • /swagger/swagger.yaml - Raw specification

See oas/swagger.yaml in the repository for the complete API reference.