MCP server
Connect any MCP client to Cymo. Agents read rooms, run scenarios and manage webhooks with one tool per API operation.
Remote MCP server
Cymo hosts the MCP server at:
https://mcp.cymatics.tech/mcpConnect any MCP client that supports remote servers over Streamable HTTP. There's nothing to install or run. The server holds no data: each tool calls the API with your key, so the key's scopes, rate limits and metering apply, and a test key keeps every call on the simulator.
Authentication
Send a Cymo API key from the dashboard as a bearer token: Authorization: Bearer cym_test_…. A request without one gets 401 missing_api_key. Use a cym_test_ key while you build and a cym_live_ key for your paired Cymos.
Set up your client
Replace cym_test_… with your key.
claude mcp add --transport http cymo https://mcp.cymatics.tech/mcp \
--header "Authorization: Bearer cym_test_…"{
"mcpServers": {
"cymo": {
"url": "https://mcp.cymatics.tech/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}{
"mcp": {
"servers": {
"cymo": {
"type": "http",
"url": "https://mcp.cymatics.tech/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}
}export CYMO_API_KEY=cym_test_…
codex mcp add cymo --url https://mcp.cymatics.tech/mcp \
--bearer-token-env-var CYMO_API_KEY{
"mcpServers": {
"cymo": {
"serverUrl": "https://mcp.cymatics.tech/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}{
"mcpServers": {
"cymo": {
"httpUrl": "https://mcp.cymatics.tech/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}{
"context_servers": {
"cymo": {
"url": "https://mcp.cymatics.tech/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}Claude's custom connectors (Settings > Connectors) sign in with OAuth and can't send an API key, so in Claude Desktop use the local server. Any other client that can send a header on a remote server works with the same URL and header.
Read-only mode
Add ?read_only=1 to the URL to list only tools that read, for an agent that should look but never change anything. The key's scopes still apply on top.
https://mcp.cymatics.tech/mcp?read_only=1Local MCP server
The hosted server runs the same code as @cymos/mcp. Run it yourself over stdio with your key in CYMO_API_KEY; add --read-only after the package name to list only read tools.
{
"mcpServers": {
"cymo": {
"command": "npx",
"args": [
"-y",
"@cymos/mcp"
],
"env": {
"CYMO_API_KEY": "cym_test_…"
}
}
}
}claude mcp add cymo -e CYMO_API_KEY=cym_test_… \
-- npx -y @cymos/mcp{
"mcpServers": {
"cymo": {
"command": "npx",
"args": [
"-y",
"@cymos/mcp"
],
"env": {
"CYMO_API_KEY": "cym_test_…"
}
}
}
}{
"mcp": {
"servers": {
"cymo": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@cymos/mcp"
],
"env": {
"CYMO_API_KEY": "cym_test_…"
}
}
}
}
}codex mcp add cymo --env CYMO_API_KEY=cym_test_… \
-- npx -y @cymos/mcpWith cymatics mock start, the whole loop runs on your machine:
$ cymatics mock start --port 8787
# then run the MCP server against it
$ CYMO_API_URL=http://127.0.0.1:8787 CYMO_API_KEY=cym_test_local \
npx -y @cymos/mcpLocal HTTP server
The package also serves Streamable HTTP at http://127.0.0.1:8788/mcp, with each client sending its own key as a bearer token, as with the hosted server.
$ npm install @cymos/mcp
$ PORT=8788 node node_modules/@cymos/mcp/dist/http.js{
"mcpServers": {
"cymo": {
"url": "http://127.0.0.1:8788/mcp",
"headers": {
"Authorization": "Bearer cym_test_…"
}
}
}
}CYMO_API_KEYstdio, required | The key every tool call is made with. |
CYMO_API_URLdefault https://api.cymatics.tech | The API the tools call, such as a local simulator. |
CYMO_MCP_READ_ONLY1 or true | List only tools that read, for every client. The --read-only flag does the same over stdio. |
PORT, HOSTHTTP, default 8788, 127.0.0.1 | Where the HTTP server listens. |
MCP tools
The server has one tool per API operation, named after it and generated from the same contract, with the operation's input schema and read, write and destructive hints. Each API reference page names its tool. Tools for operations with a request body take it as input. Read-only mode hides the tools marked write.
Project
Capabilities
Models
Sensing profiles
Retention profiles
Coordinate frames
Skeleton definitions
Rooms
list_roomscreate_roomwriteget_roomupdate_roomwritearchive_roomwriteget_zonesreplace_zoneswriteget_calibrationreplace_calibrationwriteget_processing_configreplace_processing_configwritestream_roomDevices
list_devicesget_deviceupdate_devicewriteget_device_healthget_sensing_configreplace_sensing_configwritelist_device_observationsScenes
list_scenescreate_scenewriteget_sceneupdate_scenewritedelete_scenewriteVitals
Presence
Movement
Stress
Skeleton
Classifications
Results
People
Sleep
Activity
Analyses
Events
Webhooks
list_webhookscreate_webhookwriteget_webhookupdate_webhookwritedelete_webhookwritetest_webhookwritelist_webhook_deliveriesScenarios
Scenario runs
Raw data
Usage
Request logs
Streaming windows
Stream tools return a bounded window instead of an open stream. They watch for duration_ms (default 10 s, up to 60 s) or until max_samples messages (default 20, up to 200), then return them with truncated set when more may have followed. Raw radar bytes have no tool; use the raw-data export tools instead.
stream_room({ room_id: "room_bedroom", duration_ms: 30000, max_samples: 50 })
{
"data": {
"object": "stream_window",
"operation_id": "stream-room",
"sample_count": 50,
"truncated": true,
"ended_by": "max_samples",
"messages": [{ "id": "…", "kind": "snapshot", "data": { … } }, …]
},
"meta": { "livemode": false, … }
}Example prompts
- Run the bed_exit scenario and tell me when the person left bed.create_scenario_run, list_events
- Is anyone in room_bedroom right now? What are their heart rate and breathing?get_room, get_vitals
- Watch room_bedroom for 30 seconds and summarise what changed.stream_room
- How did the person in room_bedroom sleep last night?get_sleep_summary
- Send bed.exited and fall.detected events to my staging webhook.create_webhook, test_webhook
- Which of my requests failed today, and why?list_request_logs