Complete enumeration of every endpoint. REST is JSON unless noted; the only SSE endpoint is
/api/events.
All non-API routes return static files (server.js → serveStatic /
serveIndex).
- Base URL:
http://127.0.0.1:8080(or LAN IP if enabled) - Path prefix:
/api/ - Content-Type:
application/json; charset=utf-8for both request and response - Auth header: if
TOKENenv is set, every request must include either- query:
?token=… - header:
Authorization: Bearer … - 401 if missing or wrong
- query:
- CID: each request should include
?cid=<uuid>to identify the webui tab. The webui injects this automatically; if missing, the server falls back to thedefaultCID. - Errors: every error response is
{ok: false, error: 'human-readable message'}with an appropriate 4xx/5xx status. Some legacy endpoints still return{ok: true, …}even on soft failures — those are called out below.
Returns server status. No auth required, no CID required.
Response 200
{
"ok": true,
"port": 8080,
"defaultModel": "minimax_api/MiniMax-M3",
"defaultWorkspace": "C:\\Users\\you\\.minimax-code\\webui",
"mcodeCmd": "C:\\Users\\you\\.minimax-code\\mcode.cmd",
"mcodeVersion": "0.1.2",
"maxConcurrent": 3
}Returns the current state object for this CID. See
ARCHITECTURE.md §4 for the full shape.
Response 200
{ "ok": true, "version": "0.1.3", "running": {"active": false}, … }Server-Sent Events stream for this CID. The connection stays open indefinitely. Events are listed in ARCHITECTURE.md §5.
Response 200 (Content-Type: text/event-stream)
event: state
data: {"version":"0.1.3","running":{"active":false},…}
event: delta
data: {"text":"hello","isPartial":true}
event: exec
data: {"status":"ok","durationMs":12345}
The connection is held open until the client closes it (EventSource.close())
or the server shuts down. No automatic reconnect from the server side;
the webui handles reconnection with exponential backoff.
Send a user message. Spawns (or reuses) the mcode subprocess for this CID and streams the result via SSE.
Request
{
"content": "refactor the workspace picker to use a tree",
"attachments": ["@C:\\path\\to\\file.py"],
"isAskAnswer": false
}content(string, required) — the user message. May include@pathreferences to attachments; the webui injects these automatically.attachments(string[], optional) — list of@pathstrings to prepend to the content. The webui populates this from the attachment UI; you usually don't pass it directly.isAskAnswer(bool, optional) — whentrue, the content is the answer to an activeask_userquestion. Set by the ask modal automatically.
Response 200 {ok: true} immediately. The actual response is
streamed via /api/events.
Errors
- 409 if
state.running.active === true(already running) - 400 if
contentis empty
Cancel the current run. Best-effort: tries session/cancel via acp
(unimplemented in 0.1.5), then SIGTERM, then SIGKILL after 2s.
Request {}
Response 200 {ok: true}
Send a raw slash command (e.g. /compact, /clear). The server sends
the command to mcode and streams the result.
Request
{ "cmd": "/compact" }Response 200 {ok: true}
List webui sessions + mcode sessions (merged, deduplicated).
Response 200
{
"ok": true,
"count": 12,
"sessions": [
{ "id": "uuid", "title": "…", "workspace": "C:\\…", "mcodeSessionId": "mvs_…", "updatedAt": 1234567890 }
]
}Create a new webui session. Optionally tied to a workspace.
Request
{ "workspace": "C:\\path\\to\\project" }Response 200 {ok: true, id: "uuid"}
Switch to an existing session. Loads its chat history and (if linked) re-attaches to the mcode session.
Request
{ "id": "uuid" }Response 200 {ok: true}
Delete mcode sessions that no webui session references. Two scopes:
scope: "orphans"(default) — only delete mcode sessions with no webui reference. The currently-active session is always preserved.scope: "all"— delete every mcode session, then re-link webui sessions that had amcodeSessionId(which now points to a deleted session — they become "webui-only" again).
Request
{ "scope": "orphans" }Response 200
{
"ok": true,
"scope": "orphans",
"total": 37,
"targets": 18,
"deleted": 18,
"failed": 0,
"log": ["deleted mvs_5103ca…", "deleted mvs_88c796…", …]
}Delete a webui session AND its linked mcode session (if any). The mcode deletion is a transaction across 8 sqlite tables.
Response 200 {ok: true}
Raw mcode session list (from sqlite). No webui merge.
Response 200 {ok: true, sessions: [...]}
Get the title of an mcode session.
Response 200 {ok: true, title: "…"}
Change the workspace for the current CID.
Request
{
"dir": "C:\\path\\to\\project",
"syncTui": true
}dir(string, required) — absolute pathsyncTui(bool, optional) — also write the path tocwd.jsonso the mcode TUI sees itaction: "detect"— instead of changing, return the current TUI cwdaction: "useTui"— copy the TUI's cwd to webuiaction: "reset"— restore webui's default workspace
Response 200 {ok: true, dir: "…", branch: "main", treeState: "clean"}
List a directory for the tree browser.
Request query: ?path=C:\\Users (omit for drive roots on Windows
or / for Linux)
Response 200
{
"ok": true,
"path": "C:\\Users",
"children": [
{ "name": "Public", "path": "C:\\Users\\Public", "isDir": true }
]
}When path is omitted:
- Windows:
roots: ["C:", "D:", …] - Linux:
children: [{name: "/", path: "/", isDir: true}]
Returns the full settings snapshot. This endpoint is exempt from the LAN guard — it's how a remote user toggles LAN back on after locking themselves out. The same snapshot is also pushed via SSE on state changes (see ARCHITECTURE.md §5 SSE state push).
Response 200 (v1.0.1, fields added in v1.0.1 marked with 🆕)
{
"ok": true,
"lanBroadcast": true,
"port": 8080,
"host": "0.0.0.0",
"lanIp": "192.168.1.50",
"lanUrl": "http://192.168.1.50:8080",
"lanUrlWithToken": "http://192.168.1.50:8080/?token=…", // 🆕 v1.0.1 — full URL with token, for clipboard sharing
"localUrl": "http://127.0.0.1:8080",
"mcodeCmd": "C:\\…\\mcode.cmd",
"mcodeVersion": "0.1.2",
"defaultWorkspace": "C:\\…",
"defaultModel": "minimax_api/MiniMax-M3",
"readOnly": false, // 🆕 v1.0.1 — read-only mode toggle
"tokenEnabled": true, // 🆕 v1.0.1 — token auth master switch (default true)
"currentToken": "…", // 🆕 v1.0.1 — auto-generated 32-hex token; "" after tokenAcknowledged=true
"tokenAcknowledged": false, // 🆕 v1.0.1 — operator has confirmed they saved the token
"tokenRotatedAt": 1724259600000 // 🆕 v1.0.1 — ms-since-epoch of the last rotation
}
}Fields currentToken and tokenAcknowledged are persisted to
~/.mcode-webui/settings.json (mode 0600 on Unix). currentToken
is omitted after tokenAcknowledged=true — the server only ships
the token while the operator still has a copy of it in the UI.
MCODE_WEBUI_SETTINGS_PATH env overrides the file location.
Update one or more settings. v1.0.1 expanded the payload — any combination of the fields below is settable in one request. Always exempt from the LAN guard AND the read-only gate (so the admin can always toggle things remotely, even in read-only mode).
v1.0.1 request — all settable fields
{
"lanBroadcast": true, // (existing) LAN on/off
"readOnly": true, // 🆕 v1.0.1 — toggle read-only mode
"tokenEnabled": false, // 🆕 v1.0.1 — toggle token auth master switch
"resetToken": true, // 🆕 v1.0.1 — generate new token + broadcast auth.token_rotated SSE
"acknowledgeToken": true // 🆕 v1.0.1 — operator confirms they saved the token; server stops sending it
}Responses
200 {"ok":true, "changed":true, …}— at least one field was updated200 {"ok":true, "tokenRotated":true, "currentToken":"…", "tokenAcknowledged":false, "tokenRotatedAt":…}— special response forresetToken:true(returns the new value so the caller can update its localStorage)200 {"ok":true, "changed":false}— no field actually changed500 {"ok":false, "error":"…"}— only onrotateTokendisk write failure (rare)
Multipart file upload. Saves to MCODE_WEBUI_UPLOAD_DIR and returns
the absolute path.
Request multipart/form-data with a file field.
Response 200
{
"ok": true,
"filename": "screenshot.png",
"path": "C:\\…\\.webui-uploads\\screenshot.png",
"size": 12345,
"mime": "image/png"
}Returns the builtin + currently-configured model list.
Response 200
{
"ok": true,
"current": "minimax_api/MiniMax-M3",
"models": [
{ "id": "minimax_api/MiniMax-M3", "label": "MiniMax-M3", "provider": "minimax_api" }
]
}If the list is empty, the response includes a hint field pointing
the user at the mcode TUI for model configuration.
Change the model for the current CID.
Request
{ "model": "minimax_api/MiniMax-M3" }Response 200 {ok: true, model: "…"}
Change the session-level permission mode.
Request
{ "permissions": "ask" }permissions(string) — one ofask,auto,full,plan
Response 200 {ok: true, permissions: "ask"}
Note: mcode 0.1.5 acp does not implement
session/set_mode. The webui's UI shows the mode the user selected, but the underlying mcode session does not change. This is logged in the server console as[mcode-rpc] UNSUPPORTED session/set_mode. Will start working when mcode implements the method.
List the available permission modes.
Response 200 {ok: true, modes: ["default", "bypassPermissions", "auto", "off", "read", "full"]}
Respond to an active permission / plan / ask_user prompt.
Request
{ "type": "permission", "option": "ask" }type(string) —permission|plan|planmode|askoption(string) — depends on type:permission:ask|auto|fullplan:agree|skip|addplanmode:continue|denyask:esc(skip) |<index>(option) |<text>(free-form)
Response 200 {ok: true}
Fetch the current mmx quota show snapshot. POST /api/usage-trigger
also triggers a fresh fetch from the CLI. GET /api/usage and
POST /api/usage return the cached value if recent.
Response 200
{
"ok": true,
"remaining": 91,
"resetAt": 1234567890,
"weeklyResetAt": 1234567890,
"fetchedAt": 1234567890,
"source": "mmx"
}Fetch per-turn context usage from the mavis runtime db. This is the
source of truth for "已用 N / 占比 N%" in the right panel.
Response 200
{
"ok": true,
"lastTurnContextTokens": 12345,
"lastInputTokens": 1000,
"lastCacheReadTokens": 500,
"lastCacheWriteTokens": 200,
"lastOutputTokens": 800,
"contextLimit": 524288,
"model": "MiniMax-M3",
"ts": 1234567890
}Re-fetch quota + per-turn context. The webui calls this when the user clicks the "刷新" button in the usage popover.
Response 200 {ok: true}
These endpoints wrap the acp protocol methods that the webui can
call. Methods that mcode 0.1.5 doesn't implement return 501 with
{code: 'unsupported'}.
Calls session/set_mode. Currently returns 501 (mcode 0.1.5).
Calls session/set_config_option. Currently returns 501.
Calls session/cancel. Currently returns 501 (falls back to
SIGTERM on the subprocess).
Calls session/load. Works in 0.1.5.
Request {sessionId: "mvs_…", cwd: "C:\\…"}
Calls session/activate. Currently returns 501.
Calls session/list. Works in 0.1.5.
Returns the list of acp methods the webui knows about and their support status. Used by the webui to decide which UI controls to enable.
Response 200
{
"ok": true,
"agentInfo": { "name": "mcode", "title": "mcode", "version": "0.1.5" },
"supported": ["session/new", "session/list", "session/load", "session/prompt", "session/close"],
"unsupported": ["session/set_mode", "session/set_config_option", "session/cancel", …]
}Inject a fake event into the SSE channel for a CID. Used for testing the UI without a real mcode subprocess.
Request
{ "cid": "uuid", "type": "delta", "text": "hello" }Response 200 {ok: true}
Gating: this endpoint only works if DEBUG_INJECT=1 is set in the
server's environment. The server logs a warning every time it's
called. Production deployments should leave the env unset.
Returns the full per-cid state including internal flags. Same
DEBUG_INJECT gating.
Returns public/index.html.
Returns the file from public/ if it exists. Served by serveStatic.
Cache headers: public, max-age=3600. The HTML/JS/CSS paths
embed a ?v=N cache-bust query string; bump it in index.html when
you want clients to refetch.
All errors follow one of these shapes:
{ "ok": false, "error": "human-readable message" }{ "ok": false, "code": "unsupported", "error": "mcode 0.1.5 acp does not implement session/set_mode" }{ "ok": false, "error": "LAN 访问已关闭。在本机打开设置开启。" }The HTTP status is appropriate to the cause (400 / 401 / 403 / 404 / 409 / 500 / 501).