Admin API Advanced

Automate panel operations through the admin routes under /api/phoenix-mcp/admin/. Use a Home Assistant admin session; Phoenix tokens cannot call this API.

Home Assistant session, admin only

Every admin route requires a valid Home Assistant session and the admin role. A Phoenix MCP token can never authenticate here, not even a pass-through token. See Security.

Conventions

Bodies
JSON, Content-Type: application/json. Bodies over 1 MB are rejected with 413.
Request ID
Every response carries X-Phoenix-Request-ID. Admin actions are recorded in Home Assistant's own log, not the Phoenix audit store; the audit-entry correlation applies to token-facing API requests.
Errors
Error responses are { "error": code, "message": text }, with an optional suggestions array. Codes: unauthorized (401), forbidden (403), not_found (404), invalid_request (400), request_too_large (413), conflict (409, e.g. a duplicate token name or an approval already being processed), service_unavailable (503, e.g. the kill switch or MESA unavailable), internal_error (500).

Tokens

GET     /api/phoenix-mcp/admin/tokens                 List tokens
POST    /api/phoenix-mcp/admin/tokens                 Create a token
GET     /api/phoenix-mcp/admin/tokens/{id}            Get one token
PATCH   /api/phoenix-mcp/admin/tokens/{id}            Update a token
DELETE  /api/phoenix-mcp/admin/tokens/{id}            Revoke a token
POST    /api/phoenix-mcp/admin/tokens/{id}/rotate     Generate a new raw value
POST    /api/phoenix-mcp/admin/tokens/{id}/presets                Save current settings as a preset
PATCH   /api/phoenix-mcp/admin/tokens/{id}/presets/{pid}          Rename a preset
DELETE  /api/phoenix-mcp/admin/tokens/{id}/presets/{pid}          Delete a preset (active preset refused)
POST    /api/phoenix-mcp/admin/tokens/{id}/presets/{pid}/apply    Make the token match a preset
GET     /api/phoenix-mcp/admin/tokens/{id}/stats      Request counters
GET     /api/phoenix-mcp/admin/tokens/{id}/connection last_used_at + request_count
GET     /api/phoenix-mcp/admin/tokens/{id}/audit      Audit log for one token
GET     /api/phoenix-mcp/admin/tokens/archived        List archived tokens
DELETE  /api/phoenix-mcp/admin/tokens/archived/{id}   Delete an archived record

Create (POST /tokens) takes a name and optional lifetime and limits. The response is the full token record plus a one-time token field (the raw value, never returned again).

{
  "name": "claude-code",          // required, 3-32 chars: letters, digits, _ or -
  "expires_at": "2026-07-01T00:00:00Z", // optional ISO-8601, omit for no expiry; a value without a timezone is read as HA's local time and stored as UTC
  "pass_through": false,          // optional
  "confirm_pass_through": false,  // required to be true when pass_through is true
  "rate_limit_requests": 60,      // optional, 0 disables rate limiting
  "rate_limit_burst": 10          // optional
}

Presets (all four endpoints return 403 while the token_presets_enabled setting is off): a preset is a named snapshot of the token's full configuration. Create takes {"name": "..."} and snapshots the CURRENT settings (at most 8 per token, names unique per token). Apply makes the token match the stored preset; applying a preset other than the active one first auto-saves the live state into the outgoing active preset, while applying the active preset reverts to its saved state. Applying a preset that would enable pass-through on a scoped token requires {"confirm_pass_through": true}. All return the updated token record.

Update (PATCH /tokens/{id}) accepts any subset of these fields. Capability fields take "deny" or "allow"; "confirm" is accepted only for the Confirm-eligible capabilities (the write, system, and irreversible tiers listed under Capabilities), and a PATCH setting it on a read-tier capability returns 400. Enabling pass-through requires confirm_pass_through: true in the same request, or the call returns 400. A token can also be renamed by sending name (same format and uniqueness rules as creation, excluding the token's own name); expires_at stays immutable. Renaming updates the display name of the token's sensors and their device; their entity IDs are unchanged.

{
  "persona": "voice_assistant",
  "pass_through": false,
  "confirm_pass_through": false,
  "confirm_inline_wait_seconds": 60,
  "rate_limit_requests": 60,
  "rate_limit_burst": 10,
  "cap_config_read": "allow",
  "cap_camera_read": "deny",
  "cap_template_render": "allow",
  "cap_log_read": "deny",
  "cap_log_control": "deny",
  "cap_search": "allow",
  "cap_registry_read": "allow",
  "cap_traces": "deny",
  "cap_diagnostics": "deny",
  "cap_broadcast": "deny",
  "cap_service_response": "allow",
  "cap_automation_write": "deny",
  "cap_script_write": "deny",
  "cap_scene_write": "deny",
  "cap_helper_write": "deny",
  "cap_blueprint_write": "deny",
  "cap_physical_control": "confirm",
  "cap_restart": "deny",
  "cap_integration_write": "deny",
  "cap_integration_reconfigure": "deny",
  "cap_lovelace_write": "deny",
  "cap_registry_write": "deny",
  "cap_radio_write": "deny",
  "cap_energy_write": "deny",
  "cap_backup": "deny",
  "cap_filesystem": "deny",
  "cap_yaml_edit": "deny",
  "cap_esphome_yaml": "deny",
  "cap_esphome_flash": "deny",
  "use_assist_exposure": false,
  "announce_all_tools": false
}

Setting a persona applies that persona's full preset across every capability in one request; see Personas. use_assist_exposure and announce_all_tools are advanced options described in Operations. confirm_inline_wait_seconds is how long a confirm-gated call holds the response open waiting for your decision before returning pending_approval. It must be 0 (off) or an integer from 30 to 180, and off is the default. It applies to external MCP clients only: Agent Chat, the Assist bridge, the voice agent and AI Task always return immediately and do their own waiting, so the value makes no difference to them.

Permissions

GET    /api/phoenix-mcp/admin/tokens/{id}/permissions                    Read the tree
PUT    /api/phoenix-mcp/admin/tokens/{id}/permissions                    Replace the tree
GET    /api/phoenix-mcp/admin/tokens/{id}/permissions/integration-options List integration selectors
POST   /api/phoenix-mcp/admin/tokens/{id}/permissions/bulk-select         Apply one state to an area, label, or integration
PATCH  /api/phoenix-mcp/admin/tokens/{id}/permissions/domains/{node}     Set one domain node
PATCH  /api/phoenix-mcp/admin/tokens/{id}/permissions/devices/{node}     Set one device node
PATCH  /api/phoenix-mcp/admin/tokens/{id}/permissions/entities/{node}    Set one entity node
GET    /api/phoenix-mcp/admin/tokens/{id}/resolve/{entity}               Explain effective permission
GET    /api/phoenix-mcp/admin/tokens/{id}/scope                          Readable / writable lists

A node PATCH sets a single node's state, with an optional per-token hint (max 200 characters; null clears it). The PUT replaces the whole tree; nodes use the same shape.

{
  "state": "GREEN",   // GREY | YELLOW | GREEN | RED
  "hint": "Rachel's desk lamp, not the ceiling light"  // optional, <= 200 chars, null clears
}

resolve returns the decision and the ancestor that made it: { entity_id, resolution_path: [{level, state}], effective, effective_hint }.

integration-options returns { integrations: [...] }. Each row includes entry_id, domain, title, device_count, deviceless_entity_count, registry_only_deviceless_count, required_domain_ids, and shared_device_count.

{
  "selector_type": "integration", // area | label | integration
  "selector_id": "config-entry-id",
  "state": "GREEN"                 // GREY | YELLOW | GREEN | RED
}

bulk-select resolves the selected area, label, or integration on the server and atomically applies the state to its device and entity nodes. GREY removes explicit nodes. The response is { permissions, summary }; the summary includes the selector, state, affected counts, registry-only deviceless count, required domain IDs, and shared-device count.

Entity hints

Global hints apply to every token that can see the entity. A per-token permission-node hint (above) always takes precedence over the global one. Both are capped at 200 characters.

GET  /api/phoenix-mcp/admin/entity-hints               The global entity_id > hint map
PUT  /api/phoenix-mcp/admin/entity-hints/{entity_id}   Set or clear one global hint
{ "hint": "Garage side door" }   // null clears the hint

Entities

GET  /api/phoenix-mcp/admin/entities                   The entity tree (domains, devices, entities)
GET  /api/phoenix-mcp/admin/entities?force_reload=1    Rebuild the cached tree

Approvals

GET     /api/phoenix-mcp/admin/approvals                List approvals (filter by status, token_id)
GET     /api/phoenix-mcp/admin/approvals/{id}           Get one approval
POST    /api/phoenix-mcp/admin/approvals/{id}/approve   Approve and run the held action
POST    /api/phoenix-mcp/admin/approvals/batch/approve  Approve several, stopping at the first failure
POST    /api/phoenix-mcp/admin/approvals/{id}/reject    Reject with an optional reason
DELETE  /api/phoenix-mcp/admin/approvals/{id}           Cancel a pending approval

List accepts ?status=pending|approved|rejected|expired|cancelled, ?token_id=, ?limit=, and ?offset=, and returns { approvals: [...], total, limit, offset }. Approve and reject take small optional bodies.

// POST .../approve
{ "note": "looks fine" }      // optional

// POST .../reject
{ "reason": "not this one" }  // optional

Configuration history

GET     /api/phoenix-mcp/admin/versions                              Recent changes across all resources
GET     /api/phoenix-mcp/admin/versions?resource_type=&resource_id=   One resource's version history
GET     /api/phoenix-mcp/admin/versions/{id}                          One version, with full before/after
POST    /api/phoenix-mcp/admin/versions/{id}/restore                 Re-apply a version (admin authority)

Every agent-made create, edit, or delete of an automation, script, scene, helper, blueprint, dashboard layout, entity-registry metadata, ESPHome device YAML, raw configuration.yaml, or scoped file is snapshotted here. With no query parameters, the list returns recent versions across all resources. Supply both resource_type and resource_id for one resource's history. List rows are compact summaries; fetch one version for the full before and after values.

Restore re-applies one snapshot. Optional body field side selects before or after. It defaults to after, or falls back to before for a delete. An empty body uses that default; malformed or non-object JSON returns 400 without restoring. Phoenix edits an existing resource or recreates a deleted one, then records a rollback attributed to the admin. Automations, scripts, and scenes keep their original IDs; Home Assistant assigns a new ID to a recreated helper.

Configs are stored raw so they can round-trip. ESPHome snapshots are credential-masked when displayed. Phoenix refuses an automation, script, or scene snapshot containing YAML tags such as !secret or !include, because the stored display value cannot safely recreate the tag. A deleted entity-registry entry also cannot be recreated; its integration owns it. Restoring an existing entity reapplies its captured metadata, enabled and hidden state, labels, categories, aliases, and entity ID. Raw-content snapshots over 100 KB are metadata-only and cannot be restored.

Dashboard card catalog

GET     /api/phoenix-mcp/admin/card_catalog                          The harvested catalog
POST    /api/phoenix-mcp/admin/card_catalog                          Report a harvest (panel only)

Which custom Lovelace cards this instance can render, backing the list_dashboard_cards tool. The POST is sent by the Phoenix MCP panel, not by hand: a card registers itself on window.customCards at runtime and many card sets build their type names by string concatenation, so the catalog can only be built by a browser that has loaded the resources. The panel harvests on load and re-checks shortly afterwards for cards that register late (an integration-provided card may wait on its own websocket first), re-reporting only if the set grew. Each report REPLACES the stored catalog, so an uninstalled card disappears rather than being recommended forever. harvested: false means no browser has reported yet, which is not the same as an instance with no custom cards, and the tool says so explicitly rather than returning an empty list.

MESA profiles

Profiles exist at the entity, device, area, integration, and domain levels, plus a canonical-tag vocabulary and a validation view. The profile document shape is defined by mesa-core; see MESA for how it fits into Phoenix MCP.

GET     /api/phoenix-mcp/admin/mesa/profiles               List entity profiles (domain, tag, area, origin, cursor)
GET     /api/phoenix-mcp/admin/mesa/profiles/{entity_id}   Stored + effective profile for one entity
PUT     /api/phoenix-mcp/admin/mesa/profiles/{entity_id}   Create or replace an entity profile
DELETE  /api/phoenix-mcp/admin/mesa/profiles/{entity_id}   Remove an entity profile
GET     /api/phoenix-mcp/admin/mesa/domains                List domain profiles
GET/PUT/DELETE  /api/phoenix-mcp/admin/mesa/domains/{domain}   One domain profile
GET     /api/phoenix-mcp/admin/mesa/integrations           List integration profiles
GET/PUT/DELETE  /api/phoenix-mcp/admin/mesa/integrations/{integration}   One integration profile
GET     /api/phoenix-mcp/admin/mesa/integration-options    Integrations with entities (picker source)
GET     /api/phoenix-mcp/admin/mesa/areas                  List area profiles
GET/PUT/DELETE  /api/phoenix-mcp/admin/mesa/areas/{area_id}    One area profile
GET     /api/phoenix-mcp/admin/mesa/devices                List device profiles
GET/PUT/DELETE  /api/phoenix-mcp/admin/mesa/devices/{device_id}    One device profile
GET     /api/phoenix-mcp/admin/mesa/device-options         Devices with display names (picker source)
GET/PUT /api/phoenix-mcp/admin/mesa/defaults               Deployment-default profile (the fallback level)
GET     /api/phoenix-mcp/admin/mesa/vocabulary             Canonical tags and roots
GET     /api/phoenix-mcp/admin/mesa/issues                 Validation issues + orphans (?refresh=1)
POST    /api/phoenix-mcp/admin/mesa/orphans/clear          Delete every orphaned entity, device, area, and integration profile in one call
GET     /api/phoenix-mcp/admin/mesa/export                 Export every profile as a portable archive
POST    /api/phoenix-mcp/admin/mesa/import                 Import a portable archive
POST    /api/phoenix-mcp/admin/mesa/suggestions/dismiss    Dismiss one profile suggestion
POST    /api/phoenix-mcp/admin/mesa/suggestions/restore    Restore a dismissed suggestion, or all of them

The orphans/clear action recomputes the orphan lists against the live registries, then deletes exactly those profiles (the per-profile DELETE endpoints remain for one-off removals). It returns the deleted ids grouped by kind and a total count. Profiles are never deleted automatically; this is an explicit admin action.

{
  "semantic_profile": { },        // mesa-core schema; see the mesa-core repo
  "privacy_classification": { }
}

Export / import move profiles between deployments using mesa-core's own portable archive format. Export takes no body and returns every stored profile (entity, device, area, integration, and domain levels, plus the deployment default) verbatim, with no filtering, so the response is exactly what import expects back. Import validates every document in the archive and never writes an invalid one; a document that fails validation is reported in invalid rather than aborting the rest of the archive.

{
  "archive": { },        // a document previously returned by GET .../export
  "on_conflict": "skip"  // skip (default, keep the existing profile) | overwrite
}

Import responds with { imported, overwritten, skipped_existing, invalid }, each a list or map keyed by profile.

Suggestions (surfaced as the suggestions array on GET .../issues) are computed, never auto-applied; dismiss and restore only change whether a suggestion is shown, they never touch a profile. Dismiss requires the key to match a suggestion in the currently computed set. Restore takes either key for one suggestion or {"all": true} to clear every dismissal; both return the current suggestions and dismissed_suggestions lists alongside the action's own result field (dismissed or restored).

// POST .../suggestions/dismiss
{ "key": "naked_risky:lock" }

// POST .../suggestions/restore
{ "key": "naked_risky:lock" }   // restore one
{ "all": true }                 // or clear every dismissal

Agent Chat

Agent Chat is the in-panel LLM chat that runs an agentic loop against a chosen token. Provider accounts ("instances", since more than one account of the same kind is allowed, for example two Claude keys) are configured through these admin routes and stored in a dedicated secrets file separate from tokens; the chat turn itself streams over Server-Sent Events rather than returning a single JSON body. Every route here, including the chat route, requires the same Home Assistant admin session as the rest of this page.

GET     /api/phoenix-mcp/admin/agentcli/providers                      List provider accounts
POST    /api/phoenix-mcp/admin/agentcli/providers                      Add a provider account (validated before it is stored)
PATCH   /api/phoenix-mcp/admin/agentcli/providers/{instance_id}         Change that account's default model
POST    /api/phoenix-mcp/admin/agentcli/providers/{instance_id}/refresh Re-read that account's models and declared capabilities
POST    /api/phoenix-mcp/admin/agentcli/providers/{instance_id}/probe   Ask the API which options the selected model accepts (uses API credit)
DELETE  /api/phoenix-mcp/admin/agentcli/providers/{instance_id}         Remove a provider account
GET     /api/phoenix-mcp/admin/agentcli/providers/{instance_id}/models  List that account's available models
POST    /api/phoenix-mcp/admin/agentcli/probe                           Validate credentials and list models, without storing anything
POST    /api/phoenix-mcp/agentcli/chat                                  Run one streaming agent turn (Server-Sent Events)

A provider account holds a kind (one of claude, deepseek, chatgpt, gemini, grok, groq, kimi, meta, minimax, mistral, openrouter, nvidia, opencode, ollama, ollama_cloud, zai, together, cerebras, fireworks, or qwen). Most use api_key; local ollama uses base_url, Z.ai also accepts endpoint_id, and Qwen requires both api_key and base_url. Create validates the setup against the provider before saving it; list never returns the key.

{
  "kind": "claude",
  "api_key": "sk-ant-...",              // required for every kind except ollama
  "base_url": "http://localhost:11434", // required for ollama and Qwen; ignored for fixed endpoints
  "endpoint_id": "standard",            // optional Z.ai route: standard or coding
  "model": "claude-opus-4-8"            // optional; a provider with no default is chosen later
}

The response is { "instance": { id, kind, name, model, base_url, endpoint_id } }. GET .../providers returns { "instances": [...], "provider_types": [...] }; the non-secret catalog contains each provider's kind, translated label_key, and ordered setup fields, including safe endpoint choices. name is a display label the server derives, with a discriminator only when needed. Probe accepts the same body as create but stores nothing, so a Settings form can validate a setup and populate a model dropdown before committing; it responds { "ok": true, "models": [...] } or { "ok": false, "error": "...", "models": [] } instead of an HTTP error, since a failed probe is an expected outcome, not a server fault.

Chat takes the token to act as, the provider account to use, the new user message, and the prior turns (the browser holds the transcript and resends it each turn; this endpoint keeps no conversation state of its own).

{
  "token_id": "...",                     // required, the Phoenix MCP token this turn acts as
  "instance_id": "...",                  // required, a stored provider account id
  "model": "claude-opus-4-8",            // optional, overrides the account's saved model
  "user": "turn off the kitchen lights", // required, the new user message
  "messages": [ ],                       // optional prior turns: [{"role": "user"|"assistant", "content": "..."}]
  "home_focus_bypass": false,            // optional one-turn override; valid only with a new user message
  "options": { "thinking": true, "effort": "high", "show_thinking": false, "temperature": 0.7, "max_tokens": 8192 }
}

The response is text/event-stream, not a single JSON body: named SSE frames (ready, assistant_delta, thinking_delta, tool_call, tool_progress (a live status line from a long-running tool, e.g. a firmware build percentage), tool_result, tool_image (a bounded base64 image for the current browser session), approval_required, approval_resolved, focus_declined (the model used the private Home-focused refusal protocol; the private marker is stripped from streamed and retained provider messages), continue_required (the turn paused at the steps-before-check-in limit; re-POST with "continue": true to resume it, the panel's Continue button), usage, notice, messages, error, done) carry the turn's progress as it streams, with periodic unnamed keepalive comments so an idle stretch (the model thinking, an approval awaiting a decision) does not get dropped by an intermediary. The usage frame reports provider-exact token counts for the turn so far (input_tokens, output_tokens, and context_tokens, the newest model call's input size); it only appears when the provider reports usage. Every tool call the agent makes runs through the same capability gates, MESA checks, and audit log as a real MCP client on that token; a confirm-gated call surfaces as an inline approval card in the panel rather than a plain pending_approval reply.

home_focus_bypass is accepted only with a new user message. When true, it suppresses the Agent Chat Home-focused instruction for this turn only. It does not persist, cannot be combined with continue, and changes no permissions or safety checks.

The chat route is kill-switch-gated; provider config is not

The provider configuration and model routes above are kill-switch-immune, like the rest of the admin API. POST /api/phoenix-mcp/agentcli/chat is agent activity, not administration, so it is gated by the kill switch the same way the MCP endpoint is: with the kill switch on, the route is not even registered.

Settings and system

GET    /api/phoenix-mcp/admin/settings                 Read global settings
PATCH  /api/phoenix-mcp/admin/settings                 Update global settings (any subset)
GET    /api/phoenix-mcp/admin/audit                     Global audit log (limit, offset, token_id, outcome, ip)
GET    /api/phoenix-mcp/admin/info                      Version info and tool counts
GET    /api/phoenix-mcp/admin/catalog/{language}        Panel string catalog for one language
POST   /api/phoenix-mcp/admin/voice_agent/pipeline      Create an Assist pipeline pointed at Phoenix MCP's voice agent
DELETE /api/phoenix-mcp/admin/voice_agent/pipeline      Remove the Phoenix-created pipeline
GET    /api/phoenix-mcp/admin/ai_task/preferred         Read the "Data generation tasks" default vs Phoenix MCP's entity
POST   /api/phoenix-mcp/admin/ai_task/preferred         Make Phoenix MCP the default data-gen entity
DELETE /api/phoenix-mcp/admin/ai_task/preferred         Clear Phoenix MCP as the default
DELETE /api/phoenix-mcp/admin/wipe                      Wipe tokens, audit log, and settings

GET /catalog/{language} returns { "language": …, "resources": { … } }, the panel's strings as flat dotted keys. Anything that language does not translate comes back in English.

GET /info returns version, min_ha_version, github_url, and tool_count: { "total": …, "native": …, "additional": … }, counted from the running build's own tool registry. That registry is the single source of truth for the count, so this endpoint is authoritative for the build you are running.

Settings are described in Operations. A PATCH may include any subset of the writable settings. An unknown field rejects the whole request with HTTP 400 and an invalid_request response that names the field. The GET response additionally carries computed, read-only fields (the *_supported flags, the ESPHome availability fields, and voice_agent_pipeline_id, which is managed through the pipeline routes below, not by PATCH). The voice_agent/pipeline and ai_task/preferred routes back the one-click Assist and AI Task setup buttons in the panel: POST a pipeline requires { "preferred": true|false } and needs the voice agent fully configured; the AI Task routes report and set Home Assistant's single default data-generation entity.

{
  "kill_switch": false,
  "disable_all_logging": false,
  "log_allowed": true,
  "log_denied": true,
  "log_rate_limited": true,
  "log_entity_names": true,
  "log_client_ip": true,
  "notify_on_rate_limit": false,
  "notify_on_approval": true,
  "audit_flush_interval": 15,    // minutes: 0 (never), 5, 10, 15, 30, 60
  "audit_log_maxlen": 10000,
  "mesa_mode": "advisory",       // off | advisory | enforced
  "mesa_inject_enabled": false,  // experimental in-context MESA buttons; admin-only, off by default
  "token_presets_enabled": false, // token settings presets; enabling seeds a default preset on every token
  "agentcli_global": true,        // Agent Chat floats over all of Home Assistant, not just the Phoenix MCP panel (default on)
  "agentcli_scrollback_lines": 100, // Agent Chat memory: 0-5000 lines, shown in the panel as "Chat memory"
  "agentcli_max_iterations": 20,  // Agent Chat rounds per turn (3-100) before it pauses to ask whether to continue
  "agentcli_conversation_style": "direct", // direct | warm | calm_guide | lively | technical
  "agentcli_detail_level": "concise", // concise | balanced | detailed
  "agentcli_home_focused": false, // focus preference for Agent Chat, not a security control
  "assist_bound_token_id": null,  // Assist Tool Provider: token whose tools "Phoenix MCP (scoped)" exposes (null = unbound)
  "voice_agent_enabled": false,   // Voice Agent: Phoenix MCP as an HA conversation agent, on its own token/provider/model
  "voice_agent_token_id": null,
  "voice_agent_provider_id": null, // an Agent Chat provider account id
  "voice_agent_model": null,
  "voice_agent_conversation_style": "direct",
  "voice_agent_detail_level": "concise",
  "voice_agent_home_focused": false,
  "voice_agent_pipeline_id": null, // set by Phoenix MCP when it creates the HA assistant for the voice agent; not set by hand
  "ai_task_enabled": false,       // AI Task: Phoenix MCP as an HA AI Task entity, on its own token/provider/model
  "ai_task_token_id": null,
  "ai_task_provider_id": null,    // an Agent Chat provider account id
  "ai_task_model": null,
  "ai_task_conversation_style": "direct",
  "ai_task_detail_level": "balanced"
}

Style and detail values are closed server-owned enums; invalid PATCH values are rejected. Older storage records load with the defaults shown above. Each surface reads its settings at the start of a model turn, so a PATCH affects the next turn without clearing Agent Chat history. AI Task omits its style and detail prompt additions whenever the task supplies a structured output schema. External MCP clients and the Assist Tool Provider do not use these settings.

The wipe route is intentionally guarded: it requires an exact confirmation string. It is scoped by three independent flags, so you choose what to delete. wipe_core (default true) clears every token and archived token, all settings back to their defaults, global entity hints, the audit log, and the configuration/version change history, plus in-memory request-tracking state (the rate limiter's windows, per-token request counters, and rate-limit/stale-tools notification markers) and any queued pending approvals (dismissing their notifications). wipe_providers (default true) deletes the Agent Chat provider accounts and their stored API keys from .storage/phoenix_mcp_agentcli_secrets. wipe_mesa (default false) deletes all MESA profiles from .storage/phoenix_mcp_mesa; it is off by default so a reset keeps hand-authored safety policy unless you ask otherwise. Omitting a flag uses its default (a bare { "confirm": "WIPE" } clears core data and provider keys but leaves MESA intact). The panel's Data Management card exposes all three as switches.

{
  "confirm": "WIPE",
  "wipe_core": true,       // tokens, settings, audit, versions, pending approvals (default true)
  "wipe_providers": true,  // Agent Chat provider accounts + API keys (default true)
  "wipe_mesa": false       // MESA safety profiles (default false)
}

PATCH is read-modify-write under a lock

Token and record PATCH handlers load, modify, and save atomically, so two admins editing the same token at once cannot clobber each other.

The token-facing MCP and skill routes are listed in Operations.