Documentation
MCP Guide
Preview: features and APIs may change.
PDF uses your browser’s print dialog. It is not a hosted export service.
The OneSay MCP server lets an AI client read your OneSay Projects, Devices, Rooms, Tasks, logs and Usage, and ask for a few bounded changes, through the Model Context Protocol. It is a thin layer over the public Control API: every tool calls a public API operation or Action, and the Control API decides what your account may do. The server is available on Staging; see Availability.
MCP never carries audio. Voice goes through the SDKs: Task voice over the OneSay Realtime WebSocket, or Realtime RTC.
Connect#
- Endpoint:
https://<mcp host>/mcp, one per environment. On Staging it ishttps://mcp.staging.onesay.com/mcp. - Transport: stateless Streamable HTTP. The server keeps no session between requests.
- Protocol: MCP
2026-07-28only. Every request sendsMcp-Protocol-Version: 2026-07-28; another version is refused withmcp_protocol_version_unsupported, naming the supported one. - Request headers:
Mcp-Methodmust equal the body's method, and fortools/call,prompts/getandresources/readMcp-Namemust equal the tool name, prompt name or resource URI. A mismatch is answered with HTTP 400 and JSON-RPC error-32020before any token is read.
Sign in#
The server is an OAuth 2.1 protected resource. Its Protected Resource Metadata
is served at /.well-known/oauth-protected-resource (and at
/.well-known/oauth-protected-resource/mcp), and it names the environment's
authorization server.
- No token is needed for public discovery: the R0 tools, the quickstart resources, the prompts and the tool, resource and prompt lists.
- Account data needs a token. An R1 or R2 tool, or a resource other than a
quickstart, needs a Bearer access token whose audience is this MCP resource.
Without one the server answers HTTP 401 with a
WWW-Authenticatechallenge that points to the metadata. The body is a JSON-RPC error carrying your request id, with theoauth_resource_invaliderror envelope as its data. - Your token never reaches the Control API. For each Control API call the server exchanges it (OAuth 2.0 Token Exchange, RFC 8693) for a short-lived token whose subject is you and whose actor is the MCP service. No exchange is made after your token expires, and no token is logged or returned.
Tools#
Each tool has a risk class. Read-only tools are marked read-only to the client;
rooms.close and tasks.cancel are marked destructive.
| Risk | Tools | Needs |
|---|---|---|
| R0 | onesay.capabilities.list, onesay.capabilities.get, onesay.quickstarts.get | Nothing: public metadata |
| R1 | onesay.projects.list, onesay.projects.get, onesay.applications.list, onesay.devices.list, onesay.devices.get, onesay.devices.diagnose, onesay.rooms.get, onesay.tasks.get, onesay.logs.search, onesay.logs.timeline, onesay.usage.summary | A token and the Grants the matching API operation requires |
| R2 | onesay.rooms.create, onesay.rooms.close, onesay.tasks.cancel | A token, the Grant and the human's consent |
An R2 tool runs its Action only after the human has consented in OneSay. Without
that consent the call answers mcp_confirmation_required, and nothing changes.
On Staging the R2 tools are switched off for now: they answer
mcp_tool_not_exposed and change nothing.
Resources#
| URI template | Reads |
|---|---|
onesay://projects/{project_id} | The Project, like onesay.projects.get |
onesay://devices/{device_id} | The Device's state, like onesay.devices.get |
onesay://tasks/{task_id} | The Task's state, like onesay.tasks.get |
onesay://docs/quickstarts/{name} | A quickstart page (javascript or esp32); public |
The server lists templates only. Every read result has ttlMs 0, so a client
treats it as immediately stale.
Prompts#
build_voice_appfollows the JavaScript Quickstart.diagnose_devicefollows the Device Diagnostics guide.
Errors#
A tool error carries the OneSay error envelope, the same as the Control API's:
| Code | Meaning |
|---|---|
oauth_resource_invalid | The token is missing, invalid, for another resource, or was refused by the token exchange. |
capability_authority_unavailable | OneSay could not check your access right now. Retry. |
mcp_confirmation_required | An R2 call has no human consent yet. |
consent_required | The Control API needs a Consent the account has not given. |
mcp_tool_input_invalid | An argument is missing or does not match the tool's schema. |
mcp_tool_not_exposed | The tool is not enabled on this server. |
mcp_tool_output_invalid | The Control API answered with something the tool cannot return. |
Errors from the Control API itself, such as a missing Grant or an unknown resource, are passed through with their own codes. The Canonical Reference lists every code.
Availability#
- The server runs on Staging at
https://mcp.staging.onesay.com/mcp. Production is not available yet. - On Staging the R2 tools are switched off and answer
mcp_tool_not_exposed. - Tools, prompts and resources are fixed per release, so the server sends no list-changed notifications.
View original Markdown
# MCP Guide
The OneSay MCP server lets an AI client read your OneSay Projects, Devices,
Rooms, Tasks, logs and Usage, and ask for a few bounded changes, through the
Model Context Protocol. It is a thin layer over the public Control API: every
tool calls a public API operation or Action, and the Control API decides what
your account may do. The server is available on Staging; see
[Availability](#availability).
MCP never carries audio. Voice goes through the SDKs: Task voice over the OneSay
Realtime WebSocket, or Realtime RTC.
## Connect
- **Endpoint:** `https://<mcp host>/mcp`, one per environment. On Staging it is
`https://mcp.staging.onesay.com/mcp`.
- **Transport:** stateless Streamable HTTP. The server keeps no session between
requests.
- **Protocol:** MCP `2026-07-28` only. Every request sends
`Mcp-Protocol-Version: 2026-07-28`; another version is refused with
`mcp_protocol_version_unsupported`, naming the supported one.
- **Request headers:** `Mcp-Method` must equal the body's method, and for
`tools/call`, `prompts/get` and `resources/read` `Mcp-Name` must equal the tool
name, prompt name or resource URI. A mismatch is answered with HTTP 400 and
JSON-RPC error `-32020` before any token is read.
## Sign in
The server is an OAuth 2.1 protected resource. Its Protected Resource Metadata
is served at `/.well-known/oauth-protected-resource` (and at
`/.well-known/oauth-protected-resource/mcp`), and it names the environment's
authorization server.
- **No token** is needed for public discovery: the R0 tools, the quickstart
resources, the prompts and the tool, resource and prompt lists.
- **Account data needs a token.** An R1 or R2 tool, or a resource other than a
quickstart, needs a Bearer access token whose audience is this MCP resource.
Without one the server answers HTTP 401 with a `WWW-Authenticate` challenge
that points to the metadata. The body is a JSON-RPC error carrying your
request id, with the `oauth_resource_invalid` error envelope as its data.
- **Your token never reaches the Control API.** For each Control API call the
server exchanges it (OAuth 2.0 Token Exchange, RFC 8693) for a short-lived
token whose subject is you and whose actor is the MCP service. No exchange is
made after your token expires, and no token is logged or returned.
## Tools
Each tool has a risk class. Read-only tools are marked read-only to the client;
`rooms.close` and `tasks.cancel` are marked destructive.
| Risk | Tools | Needs |
|---|---|---|
| R0 | `onesay.capabilities.list`, `onesay.capabilities.get`, `onesay.quickstarts.get` | Nothing: public metadata |
| R1 | `onesay.projects.list`, `onesay.projects.get`, `onesay.applications.list`, `onesay.devices.list`, `onesay.devices.get`, `onesay.devices.diagnose`, `onesay.rooms.get`, `onesay.tasks.get`, `onesay.logs.search`, `onesay.logs.timeline`, `onesay.usage.summary` | A token and the Grants the matching API operation requires |
| R2 | `onesay.rooms.create`, `onesay.rooms.close`, `onesay.tasks.cancel` | A token, the Grant and the human's consent |
An R2 tool runs its Action only after the human has consented in OneSay. Without
that consent the call answers `mcp_confirmation_required`, and nothing changes.
On Staging the R2 tools are switched off for now: they answer
`mcp_tool_not_exposed` and change nothing.
## Resources
| URI template | Reads |
|---|---|
| `onesay://projects/{project_id}` | The Project, like `onesay.projects.get` |
| `onesay://devices/{device_id}` | The Device's state, like `onesay.devices.get` |
| `onesay://tasks/{task_id}` | The Task's state, like `onesay.tasks.get` |
| `onesay://docs/quickstarts/{name}` | A quickstart page (`javascript` or `esp32`); public |
The server lists templates only. Every read result has `ttlMs` 0, so a client
treats it as immediately stale.
## Prompts
- `build_voice_app` follows the [JavaScript Quickstart](JAVASCRIPT_QUICKSTART.md).
- `diagnose_device` follows the [Device Diagnostics](DEVICE_DIAGNOSTICS.md) guide.
## Errors
A tool error carries the OneSay error envelope, the same as the Control API's:
| Code | Meaning |
|---|---|
| `oauth_resource_invalid` | The token is missing, invalid, for another resource, or was refused by the token exchange. |
| `capability_authority_unavailable` | OneSay could not check your access right now. Retry. |
| `mcp_confirmation_required` | An R2 call has no human consent yet. |
| `consent_required` | The Control API needs a Consent the account has not given. |
| `mcp_tool_input_invalid` | An argument is missing or does not match the tool's schema. |
| `mcp_tool_not_exposed` | The tool is not enabled on this server. |
| `mcp_tool_output_invalid` | The Control API answered with something the tool cannot return. |
Errors from the Control API itself, such as a missing Grant or an unknown
resource, are passed through with their own codes. The
[Canonical Reference](../reference/generated/catalog.md) lists every code.
## Availability
- The server runs on Staging at `https://mcp.staging.onesay.com/mcp`. Production
is not available yet.
- On Staging the R2 tools are switched off and answer `mcp_tool_not_exposed`.
- Tools, prompts and resources are fixed per release, so the server sends no
list-changed notifications.