Skip to content

Transport parity matrix

Chorus exposes the same core operations through several public surfaces. They are intended for different callers, so do not infer a command name on one surface from another surface’s name.

Caller Recommended surface Why
TypeScript service or automation SDK Typed resource methods, response types, error handling, and pagination helpers
Tool-using agent Standalone MCP Discoverable chorus_* tools over local stdio or a shared remote-safe HTTP wrapper
Human operator CLI Focused, scriptable commands with table or JSON output
Non-TypeScript integration REST Conventional routes described by the generated OpenAPI document
Client that needs canonical command dispatch JSON-RPC Dot-style command IDs through POST /rpc when that command has a registered RPC method
In-process Chorus extension Embedded MCP Server-owned tools without the standalone chorus_ prefix

The SDK uses REST and JSON-RPC internally. SDK callers normally should not choose between those wire formats themselves.

The command catalog ID is the canonical operation name. A registered dot-style JSON-RPC method uses that ID verbatim. REST routes, SDK methods, MCP tools, and CLI commands use names suited to their callers.

The two MCP surfaces are distinct:

  • The standalone chorus-mcp package exposes chorus_* tools. Its complete local/stdio tool list is generated from the live registry.
  • Shared HTTP mode uses the same standalone registry but omits five operations that would access paths on the MCP service host: chorus_artifact_upload, chorus_artifact_upload_many, chorus_artifact_download, chorus_workspace_upload_file, and chorus_workspace_download_file.
  • The MCP server embedded in Chorus exposes server-owned names such as admin_object_storage_health. Do not add or remove chorus_ mechanically; consult the registry for the surface you are connected to.

Legacy slash-style JSON-RPC aliases remain for compatibility in selected domains. New raw RPC integrations should use the registered dot-style method when one exists.

Both embedded and standalone MCP transports carry transport failures in JSON-RPC error.data.chorus_code. These transport codes are shared and typed by the SDK’s MCP_PROTOCOL_ERROR_CODES set:

  • MCP_BODY_INVALID
  • MCP_BODY_TOO_LARGE
  • MCP_MEDIA_TYPE_UNSUPPORTED
  • MCP_RESPONSE_TOO_LARGE
  • MCP_BATCH_UNSUPPORTED
  • MCP_PROTOCOL_VERSION_REQUIRED
  • MCP_RUNTIME_INCOMPATIBLE (standalone runtime-tree compatibility checks)
  • MCP_AUTHORITY_VALIDATION_FAILED (standalone could not safely classify the upstream authority failure)

The standalone tool wrapper also has a distinct MCP_TOOL_ERROR_CODES set for codes rendered inside failed CallToolResult text: MCP_OUTPUT_VALIDATION_FAILED, MCP_RESPONSE_TOO_LARGE, MCP_TOOL_INPUT_INVALID, and MCP_TOOL_INTERNAL_ERROR. MCP_RESPONSE_TOO_LARGE can appear on either carrier; the others are tool-result-only.

They are deliberately separate from the REST/HTTP error catalog. An MCP error may travel over HTTP 200 as a JSON-RPC error or over stdio, so assigning it one canonical HTTP status would be incorrect. HTTP MCP admission can additionally forward ordinary Chorus REST error codes such as AUTH_KEY_INVALID or RATE_LIMIT_EXCEEDED in the same chorus_code field.

All three object-storage administration operations require an admin identity. They are available on every public surface shown below.

Operation Catalog / JSON-RPC REST Embedded MCP Standalone MCP SDK CLI
Health admin.object_storage.health GET /admin/object-storage/health admin_object_storage_health chorus_admin_object_storage_health client.admin.objectStorageHealth() chorus admin object-storage health
List operations admin.object_storage.list GET /admin/object-storage/operations admin_object_storage_list chorus_admin_object_storage_list client.admin.objectStorageOperations(options) chorus admin object-storage list
Retry cleanup admin.object_storage.retry_cleanup POST /admin/object-storage/operations/:id/retry-cleanup admin_object_storage_retry_cleanup chorus_admin_object_storage_retry_cleanup client.admin.retryObjectStorageCleanup(id) chorus admin object-storage retry-cleanup ID

Health takes no input and returns fixed aggregate counters.

List accepts these optional fields:

  • states: up to eight unique operation states: prepared, uploading, uploaded, cleanup_pending, pending_delete, committed, completed, and dead_letter. REST and CLI encode the list as a comma-separated query value; RPC, MCP, and the SDK use an array.
  • after: the cursor returned by the previous page. Pass it back unchanged.
  • limit: page size from 1 to 100; the default is 50.

Each listed operation ID is canonical: object_storage_operation: followed by 32 lowercase hexadecimal characters. The list response contains operations, cursor, and has_more.

Health, list, retry results, and retry audit details are deliberately secret-free. They do not return provider URLs, physical or logical object keys, references, request metadata, lease authority, or arbitrary provider error text.

Retry accepts only the operation ID. The server owns provider verification, reference checks, lease generation, and accounting settlement:

  • A dead-lettered upload produces action: "upload_cleanup_observed". It records a bounded cleanup observation and retains the tombstone and accounting authority.
  • A dead-lettered delete produces delete_retry_completed, delete_retry_pending, or delete_retry_in_progress. The server creates or reuses the fenced retry chain and reports whether accounting remains retained.

Do not invent flags such as “provider absent” or “settled”; no public surface accepts them.

import {
ChorusClient,
isCommittedMutationAcknowledgement,
} from "@chorus-protocol/sdk";
const client = new ChorusClient({
url: process.env.CHORUS_URL!,
apiKey: process.env.CHORUS_API_KEY!,
});
const health = await client.admin.objectStorageHealth();
const page = await client.admin.objectStorageOperations({
states: ["dead_letter"],
limit: 50,
});
const operation = page.operations[0];
if (operation) {
// Retry only after an operator has reviewed and selected this operation.
const result = await client.admin.retryObjectStorageCleanup(operation.id);
if (isCommittedMutationAcknowledgement(result)) {
// The mutation committed. Reconcile by the returned resource/request identity; do not retry it.
console.log(result);
} else {
console.log(result.action, result.operation.state, result.accounting_retained);
}
}
console.log(health.global_unresolved, page.cursor, page.has_more);
Terminal window
chorus admin object-storage health --json
chorus admin object-storage list --states dead_letter --limit 50 --json
chorus admin object-storage retry-cleanup object_storage_operation:0123456789abcdef0123456789abcdef --json

Use the returned cursor to request the next page:

Terminal window
chorus admin object-storage list \
--states dead_letter \
--after object_storage_operation:0123456789abcdef0123456789abcdef \
--limit 50 \
--json

The embedded and standalone MCP tools take the same logical inputs; only their names differ.

{
"states": ["dead_letter"],
"limit": 50
}

Retry input:

{
"id": "object_storage_operation:0123456789abcdef0123456789abcdef"
}

REST list filters are query parameters and retry has an empty request body:

Terminal window
curl --fail-with-body \
-H "Authorization: Bearer $CHORUS_API_KEY" \
"$CHORUS_URL/admin/object-storage/operations?states=dead_letter&limit=50"
curl --fail-with-body -X POST \
-H "Authorization: Bearer $CHORUS_API_KEY" \
"$CHORUS_URL/admin/object-storage/operations/object_storage_operation:0123456789abcdef0123456789abcdef/retry-cleanup"

The equivalent raw RPC call uses the canonical command ID:

{
"jsonrpc": "2.0",
"id": "object-storage-health-1",
"method": "admin.object_storage.health",
"params": {}
}

For a list page, use method admin.object_storage.list with {"states":["dead_letter"],"limit":50}. For a reviewed retry, use method admin.object_storage.retry_cleanup with {"id":"object_storage_operation:0123456789abcdef0123456789abcdef"}.

  • Foundation signal emission is aligned across the catalog, standalone MCP, and CLI: pulse, sense, query, alert, artifact, approval_request, proposal, and shift are accepted. task emission was removed; create work with the native task API, chorus_task_create, or chorus tasks create.
  • chorus status reads the current flat stats response; the historical nested-stats caveat no longer applies.
  • Chorus does not implement a chorus auth codex OAuth flow. Authenticate the Codex host with its official codex login command, then configure Chorus separately with chorus login --api-key or an MCP Bearer header.