Workspace and Session
ASession is one session’s handle: shell runs a line as it, glob matches as it, and vfs is the file API run as it, so every call answers under the session’s profile, with its working directory, environment, mount modes and hides.
ws.session(id) creates the session when the id is new and adopts it when it exists. Pass { profile } to create it under one of the workspace’s profiles, or { mounts } to narrow its mount modes. A profile, mounts or permissions for an existing session throw, since a profile is set once, when the session is created. ws.shell(line, { sessionId }) and ws.glob(pattern, sessionId) are the same calls without the handle; without a session id they act as the workspace’s default session.
session.shell
It answers a result with
exitCode, stdoutText and stderrText (stdout and stderr are the bytes). A non-zero exit is a result, not an exception.
Cancel a line
Abort the signal. The line stops at its next await,$? goes back to what it was before the line ran, and the call throws a DOMException named AbortError:
124.
session.vfs
The file API, run as the session. Paths are absolute workspace paths, and bytes areUint8Array.
A failure throws an
Error whose code is the POSIX name, as Node’s fs does: ENOENT for a missing path, EROFS or EACCES for a refused one.
The agent tool table
MirageToolOperations is the seven agent tools (shell, read, write, edit, ls, grep, glob) as a class, answered for one session. MCP, RPC’s tools/call, the HTTP tool routes and the CLI’s tool verbs all call it, so an agent loop of your own gets the same answers:
Each tool is also a method:
await tools.read('/data/report.csv', 0, 20), await tools.grep('todo', '/src', { ignoreCase: true }). call takes the arguments as the schema reads them, is what every interface uses, and throws for a name no tool has. readMedia(path) answers an image or a PDF as media instead of numbered text, for adapters that hand media to the model. @struktoai/mirage-agents/tool_descriptions exports each tool’s description and JSON schema (READ_DESCRIPTION, READ_INPUT, …) to hand your model, and the agent adapters wrap the table for each framework.
Embed the MCP server
The MCP server the Mirage server runs is a factory you can call yourself, over any MCP transport, without the Mirage server:
It returns the SDK’s
McpServer. To serve it over streamable HTTP from your own route, hand the factory to the SDK’s createMcpHandler(() => createMirageMcpServer(ws, { operations })), sharing one operations across requests so stale-write stamps carry from one request to the next, which is what the Mirage server does.
Embed the RPC server
MirageRpcServer serves one session over JSON-RPC, with the same methods the Mirage server answers. handle answers one message, for a route of your own; serve answers a stream of lines until it ends, running each request on its own so $/cancelRequest reaches a running one:
In-app,
shell runs the line directly on the session; the Mirage server runs it as a job instead.
Reach a server from code
When the workspace lives in a server,fetch reaches it. The token is in ~/.mirage/auth_token in the default local mode:
POST /rpc carries the whole Session API in one route; the HTTP page lists the rest, and the RPC page shows a mirage rpc client over stdio.