PalveronPalveronDocs

MCP API

Complete API reference for the MCP Gateway: servers, tools, policies, approval requests, proxy.

All MCP endpoints require API-key authentication (Authorization: Bearer {project_api_key}) and additionally enforce a role floor. Editor: register, scan, create a stricter policy. Admin: approve / resume / pause / reject / delete a server, admit tools, emergency-stop, set a tool rule, create an allowing policy, delete a policy.

A refusal has the shape {"error": {"code", "message", "request_id"}}; message is English, code is what to act on (see Refusal codes).

Servers

List servers

GET /api/v1/mcp/servers

Returns all registered MCP servers for the project. Per server:

FieldMeaning
statusset only by humans: PENDING_APPROVAL (waiting for approval), ACTIVE, BLOCKED (paused). A scan never changes it.
scan_statewhat the last scan says: never · failed · not_run (could not run because of the address or sign-in) · unreadable (result outdated, scan again) · succeeded. Only succeeded can be approved.
scan_reasonreason of the last attempt that did not succeed: for failed unreachable · bad_status · rpc_error · invalid_response; for not_run upstream_url_forbidden · auth_method_unsupported · auth_token_missing; otherwise null
is_healthywhether the server answered at the last scan
tool_count, tools_unreleasednumber of tools and of those not admitted (changed tools are not counted)
last_scan_attime of the last successful scan

Register a server (Editor)

POST /api/v1/mcp/servers
{
  "name": "GitHub MCP Server",
  "server_url": "https://api.githubcopilot.com/mcp/",
  "connector_type": "custom",
  "description": "Optional description",
  "is_proxied": true
}

connector_type is an optional free-form label (defaults to custom). New servers start in PENDING_APPROVAL; registering does not trigger a scan.

Update a server (Editor)

PATCH /api/v1/mcp/servers/{id}

Fields: name, description, auth_method, auth_config. This route is metadata-only — it cannot change status. Status transitions go exclusively through the audited lifecycle actions below.

Delete a server (Admin)

DELETE /api/v1/mcp/servers/{id}

Cascades to this server's tools and policies. Audited.

Lifecycle actions (Admin, audited)

Status changes only through these dedicated, admin-audited routes:

POST /api/v1/mcp/servers/{id}/activate   # PENDING_APPROVAL → ACTIVE (approve) or BLOCKED → ACTIVE (resume)
POST /api/v1/mcp/servers/{id}/pause      # ACTIVE → BLOCKED
POST /api/v1/mcp/servers/{id}/reject     # PENDING_APPROVAL → removed

Approving is a decision about every tool and possible only after a successful scan. The body names every tool of the last successful scan exactly once, with a rule and the current_fingerprint from the tool list; a server without tools is approved with "tools": []:

{ "tools": [ { "tool_id": "clxyz...", "rule": "REQUIRE_APPROVAL", "fingerprint": "5f0c7e…" } ] }

rule ∈ ALLOW · LOG_ONLY · REQUIRE_APPROVAL · DENY. In one step the server becomes active and every tool is admitted with its rule: the rule counts as confirmed by this Admin (is_auto_generated: false), and the tool's state (name, description, input schema) is recorded. Response: {"id", "status": "ACTIVE", "release": {"release_id", "released": [{"tool_id", "tool_name", "rule", "approved_hash"}]}}.

Resuming takes no tools ({}) and admits nothing: a tool changed since its admission stays blocked. Each action writes an entry to the tamper-evident log of admin actions (mapped to OCSF for SIEM export).

Admit tools (Admin)

POST /api/v1/mcp/servers/{id}/tools/release

Only on an ACTIVE server. The body has the same shape as for the approval and names at least one tool that is not admitted (matches_approved: null) or changed since its admission (matches_approved: false). This is also how a changed tool is admitted again. Response: {"release_id", "released": […]}. Each tool gets a log entry MCP_TOOL_RELEASED.

Scan tools (Editor)

POST /api/v1/mcp/servers/{id}/scan

Connects to the MCP server, discovers tools, determines each tool's action and risk, and records the current state of every tool. The scan sets no rule, admits no tool and never changes the status.

The response mirrors the outcome honestly:

// reached and scanned
{ "scanned": true, "tool_count": 12, "tools_new": 2, "tools_vanished": 0, "poisoning_suspects": 0, "policies_bound": 0, "tools_unreleased": 12, "server_status": "PENDING_APPROVAL" }

// target could not be scanned (still HTTP 200 — not a Palveron 5xx)
{ "scanned": false, "reason": "unreachable", "detail": "refused", "target": "https://…", "server_status": "PENDING_APPROVAL" }

tools_unreleased is the number of tools that serve nothing until an Admin admits them; server_status is the unchanged status. reason ∈ unreachable · bad_status · rpc_error · invalid_response; the server list then shows scan_state: failed. When the scan cannot run because of the configuration (private or internal address, unsupported sign-in method, missing token), the route answers 400 (validation) and records scan_state: not_run with its reason.

List server tools

GET /api/v1/mcp/servers/{id}/tools

Each tool carries risk_level, category, description_hash, action, the effective server-wide rule policy_action (null = no rule, calls are held for approval) and is_auto_generated (true = created by the system, false = confirmed by an Admin), plus the admission:

FieldMeaning
matches_approvedtrue = admitted and unchanged · false = changed since the admission (blocked) · null = not admitted (blocked)
approved_hash, approved_atrecorded state and time of the admission
current_fingerprintfingerprint of the current state; an admission names it back
proposed_ruleproposed rule for a waiting tool, otherwise null; decides no call
proposed_rule_sourceaction (from the action) or template (from a stricter template rule, the only way to DENY); null exactly when proposed_rule is null

"Accept proposals" is exactly tools = [{tool_id: id, rule: proposed_rule, fingerprint: current_fingerprint}].

Set a tool rule (Admin)

POST /api/v1/mcp/servers/{id}/tools/{tool_id}/verdict
{ "action": "LOG_ONLY", "reason": "Reviewed — safe to log only" }

Sets (or loosens) the tool's server-wide rule, replacing its server-wide rules with the new one so loosening actually takes effect. It admits nothing: for a tool that is not admitted or changed, the way is …/tools/release. Logged. There is no update endpoint for policies; use this route, or delete and create again.

Templates

GET /api/v1/mcp/templates

Lists the templates Palveron maintains with id, name, description, category, connector_type, auth_method, default_policies, plus available and unavailable_reason. All templates are locked at the moment (available: false, unavailable_reason: "auth_method_unsupported"): they sign in with a method the gateway does not support yet. Locked templates stay listed; POST /api/v1/mcp/servers/from-template refuses them with 409 mcp_template_unavailable and creates nothing.

Registry (catalog)

GET /api/v1/mcp/registry?q={search}&frontable=true&cursor={registry_name}&limit=50

Returns Palveron's mirror of the official MCP registry — the catalog behind the one-click connect flow. Each item: registry_name, version, description, remote_url, frontable (has a usable HTTP remote), website_url, registry_status, and the trust signals registry_updated_at, published_at, repository_url. The response carries items, an optional keyset next_cursor (over registry_name), and total.

Proxy

Forward a tool call

POST /api/v1/mcp/proxy/{server_id}

Accepts any JSON-RPC 2.0 request. Optionally send an X-Agent-Id header with a registered agent id (plain CUID) so calls are attributed to that agent — an unknown id is treated as anonymous. For the tools/call method, the following checks run in order:

  1. Agent suspended: a suspended agent is refused first (-32003, AGENT_EMERGENCY_STOP)
  2. Server active: PENDING_APPROVAL → -32002, paused (BLOCKED) → -32001
  3. Admission: a tool changed since its admission (-32002, APPROVED_FINGERPRINT_MISMATCH) and a tool that is not admitted (-32002, TOOL_NOT_RELEASED) are blocked; a tool that is not admitted and whose description changed since the last scan carries the legacy poisoning reason (-32002)
  4. Rules: the strictest rule wins (see Tool Policies): DENY → -32003, REQUIRE_APPROVAL → -32004, no rule → -32004 (NO_TOOL_RULE_REQUIRE_APPROVAL); the agent's permission model can tighten further
  5. Upstream auth attach: if the server's auth cannot be attached, the call is refused fail-closed (-32008)
  6. Forward to the MCP server, then record the call with traceType: MCP_TOOL_CALL

Non-tool-call methods (initialize, tools/list) pass through without policy evaluation.

Error codes:

CodeMeaning
-32001Server paused or not ACTIVE
-32002Call blocked: server awaiting approval (PENDING_APPROVAL), tool not admitted (TOOL_NOT_RELEASED), changed since the admission (APPROVED_FINGERPRINT_MISMATCH), or a poisoning suspect
-32003Tool denied by a rule, or the agent is suspended (AGENT_EMERGENCY_STOP)
-32004Call held for approval (queued; carries the request id), by a rule or because no rule applies
-32005Limit exceeded — returned when too many approvals are already pending for the agent (resolve or wait before requesting more)
-32006Invalid response / protocol error from the MCP server
-32007MCP server unreachable
-32008Server authentication could not be attached (fail-closed; HTTP 403)

Policies

List policies

GET /api/v1/mcp/policies

Create a policy (Editor, allowing: Admin)

POST /api/v1/mcp/policies
{
  "action": "DENY",
  "mcp_tool_id": "clxyz...",
  "agent_id": "ckagent...",
  "reason": "Shell execution not allowed"
}

action is required, plus at least mcp_tool_id or agent_id; reason and conditions are optional. Valid actions: ALLOW, LOG_ONLY, REQUIRE_APPROVAL, DENY; any other value returns 400 listing the allowed set. An allowing policy (ALLOW, LOG_ONLY) needs an Admin. With agent_id only REQUIRE_APPROVAL and DENY are accepted, because an agent rule can only tighten the server-wide rule; ALLOW or LOG_ONLY returns 400 mcp_agent_rule_ineffective and writes nothing. There is no update endpoint; to change a tool's rule use the set-rule route above.

Delete a policy (Admin)

DELETE /api/v1/mcp/policies/{id}

Approval requests

List pending

GET /api/v1/mcp/approvals

Returns only open approval requests (PENDING) that have not yet expired.

Decide

POST /api/v1/mcp/approvals/{id}/decide
{ "approved": true, "comment": "Reviewed — one-time access granted" }

After an approval, send the call again and carry the approval id, either in the X-Palveron-Approval-Id header or in the _palveron_approval_id argument. The approval is single use and bound to the exact arguments it was requested for (a canonical hash of the tool arguments); a call with different arguments opens a new approval request.

Targeted MCP stop (Admin)

POST /api/v1/mcp/emergency-stop
{ "scope": "server", "target_id": "<server_id>", "reason": "Security incident" }

Scopes: server (block one specific server, target_id required; a server that is not ACTIVE stays unchanged) and agent (end the open approvals of one agent, target_id required). Each ends only the open approvals of its target. Admin only, and recorded as a Flare-attested log entry. The former scope: "all" has been removed (mcp_scope_all_removed); to stop the whole project at once, use the project emergency stop.

Refusal codes

With every one of these codes nothing is written.

CodeStatusMeaningRoute
mcp_scan_missing409server never scannedapprove
mcp_scan_failed409last scan failedapprove
mcp_scan_not_run409last scan could not run because of the address or sign-inapprove
mcp_scan_unreadable409stored scan result does not name the tools: scan againapprove
mcp_release_tools_required400tools missing, or empty when admittingapprove, admit
mcp_release_tool_missing400a tool of the last scan is missing; the message names themapprove
mcp_release_tool_unknown400a named tool is not in the decidable setapprove, admit
mcp_release_tool_duplicate400tool named more than onceapprove, admit
mcp_release_rule_invalid400rule outside the four valuesapprove, admit
mcp_release_surface_changed409name, description or parameters changed since the list was read: reloadapprove, admit
mcp_release_already_released409tool is admitted and unchanged; change its rule via …/verdictadmit
mcp_release_server_not_active409admitting only on an active serveradmit
mcp_resume_takes_no_tools400resume with toolsresume
mcp_release_author_unresolved403the Admin's identity could not be resolved; a confirmed rule needs its humanapprove, admit
mcp_agent_rule_ineffective400agent rule with ALLOW or LOG_ONLYcreate policy
mcp_template_unavailable409template locked; the message names the sign-in methodcreate from template
mcp_scope_all_removed400the MCP stop no longer stops all servers at once; use a targeted stop or the project emergency stopemergency-stop
mcp_server_name_conflict409a server with this name already exists in the project (ignoring case and outer spaces)register

On this page