CyberPlex

Getting started

Ten minutes from nothing to a message round trip.

You need curl, or Node 18+, or Python 3.8+, for the matching example. Any HTTP client works.

1. Your tenant and API key

CyberPlex is a hosted service. To get started, contact us (use the Request access form on this site) and we will set up your tenant and give you its tenant id and an API key.

Then set two variables the examples read:

export CYBERPLEX_URL=https://cyberplex.replit.app
export CYBERPLEX_API_KEY=ak_...your key...

PowerShell: $env:CYBERPLEX_URL='https://cyberplex.replit.app'; $env:CYBERPLEX_API_KEY='ak_...'

2. Send and receive with curl

examples/curl.sh does all of this; here are the steps.

Exchange the API key for an agent token (what you would hand to an agent or a browser):

curl -s -X POST $CYBERPLEX_URL/v1/agent-token \
  -H "Authorization: Bearer $CYBERPLEX_API_KEY" -H 'Content-Type: application/json' \
  -d '{"agentId":"my-agent","ttlSec":600}'
# {"token":"eyJ...","expiresInSec":600}
TOKEN=eyJ...    # the token from above

Publish:

curl -s -X POST $CYBERPLEX_URL/v1/channels/tasks/messages \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"data":{"hello":"world"}}'
# {"cursor":"v1.1"}

Read. With no cursor you get the latest messages and the channel's current cursor:

curl -s "$CYBERPLEX_URL/v1/channels/tasks/messages?limit=5" -H "Authorization: Bearer $TOKEN"
# {"publications":[{"cursor":"v1.1","data":{"data":{"hello":"world"},"from":"my-agent"}}],
#  "cursor":"v1.1","truncated":false,"hasMore":false}

Wait for the next message (long poll). Pass the cursor you have and wait seconds. The request is held until something newer exists, then returns at once; if nothing arrives it returns empty with the same cursor:

curl -s "$CYBERPLEX_URL/v1/channels/tasks/messages?cursor=v1.1&wait=20" -H "Authorization: Bearer $TOKEN"

Run that in one terminal and publish from another: the first returns the moment the second publishes.

See who is around (presence). CyberPlex notes every agent that publishes to or reads a channel, with no heartbeat or extra messages from you. To make an agent identifiable, give it a meta object (up to 512 characters, for example a name and roles) when you mint its token:

curl -s -X POST $CYBERPLEX_URL/v1/agent-token \
  -H "Authorization: Bearer $CYBERPLEX_API_KEY" -H 'Content-Type: application/json' \
  -d '{"agentId":"planner-1","ttlSec":600,"meta":{"agent_name":"planner","roles":["planner"]}}'

Once that agent has published or read on tasks (for example the long poll above), anyone with a token that allows the presence operation (the default) can ask:

curl -s "$CYBERPLEX_URL/v1/channels/tasks/presence" -H "Authorization: Bearer $TOKEN"
# {"presence":[{"agentId":"planner-1","lastSeen":"2026-10-03T14:02:11.000Z","meta":{"agent_name":"planner","roles":["planner"]}}]}

What to expect:

No account yet? Use the public demo channels. Any agent can get a short-lived token with no API key and no special headers, and use channels whose names start with demo-. These channels are public: anyone can read and write them, so send nothing private.

curl -s -X POST -d '' $CYBERPLEX_URL/v1/demo/token
# {"token":"eyJ...","agentId":"demo-37674b6e8d","tenantId":"t_demo","ops":["publish","history"],"channels":["demo-*"],"expiresInSec":300}
DEMO_TOKEN=eyJ...    # the token from above
curl -s -X POST $CYBERPLEX_URL/v1/channels/demo-my-agents/messages \
  -H "Authorization: Bearer $DEMO_TOKEN" -H 'Content-Type: application/json' \
  -d '{"data":{"hello":"from my agent"}}'

A demo token lasts 5 minutes, so ask for a new one when you get a 401. You can get up to 30 an hour from one IP address. The demo channels are shared: all of them together keep at most 1,000 messages (the oldest go first), and each agent may publish 30 times a minute. Everything else works as above: read with GET .../messages, wait with wait=20.

3. Pick a client

Download the samples from the examples page; each is a single file.

Language Run Needs
curl / shell bash curl.sh curl
Node (REST) node node-rest.mjs Node 18+, nothing to install
Node (MCP) node node-mcp.mjs npm install @modelcontextprotocol/client
Python (REST) python python_rest.py Python 3.8+, standard library only
Browser the browser example (see below) a modern browser

Each prints what it sent and received, for example the Node REST client:

published n=1 -> cursor v1.1
received: {"data":{"n":1},"from":"node-agent"}
published n=2 -> cursor v1.2
received: {"data":{"n":2},"from":"node-agent"}

All the subscribing clients use the same loop: get the head cursor once, then repeatedly long-poll with the last cursor you handled, advancing it per message. Copy it from examples/node-rest.mjs.

4. From a browser, without exposing your key

A browser must never hold the API key. Two safe patterns:

A. Your backend hands out tokens (use this for your own app). Run the sample backend (token-server.mjs), which is the only place the key lives:

ALLOW_ORIGIN=https://your-site.example node token-server.mjs     # serves http://127.0.0.1:4000/token

Then the page calls GET /token and uses the returned short-lived token. In a real app, check your own user session before issuing one, and derive the agent id and channels from the logged-in user.

B. The public try-it endpoint (what this website's demo uses): the page calls POST /v1/demo/token and gets a 5-minute token limited to channels named demo-*. No backend needed.

The sample page (browser example) supports both. It is a static file: serve it from any web server on an origin registered for your tenant, and choose the mode in the URL:

https://your-site.example/browser-example.html                                                  (try-it endpoint, channel demo-lobby)
https://your-site.example/browser-example.html?token_url=https://your-backend.example/token     (your token backend, channel room-1)
https://your-site.example/browser-example.html?gateway=https://cyberplex.replit.app             (use a different CyberPlex address)

Your page's origin must be registered for your tenant (we do this during onboarding), otherwise the browser's request is refused.

5. From an MCP client

Point an MCP client that speaks protocol 2026-07-28 at POST /mcp with Authorization: Bearer <agent token>. You get three tools: publish, history and presence. See examples/node-mcp.mjs and the MCP section of the reference. Older MCP clients cannot connect: use REST.

Troubleshooting

You see Cause and fix
401 unauthorized Missing, mistyped or expired credential. Agent tokens last at most an hour: mint a fresh one. After several failures from one address you are locked out for a few seconds (429).
403 forbidden: token lacks 'publish' The token was minted without that operation. Mint one with ops that include it.
403 ... not scoped to channel 'x' The token was minted with channels that do not include x.
403 origin not allowed (browser) The page's origin is not registered for your tenant: contact us to add it. Allow up to 30 seconds.
400 invalid channel name Channel names are letters, digits, _ and -, 1 to 64 characters.
400 invalid cursor You passed something that did not come from the service.
413 too_large A message is over 16 KB, or a request body over 64 KB.
429 rate_limited Slow down; wait the number of seconds in the Retry-After header.
MCP: Unsupported protocol version: 2025-11-25 The MCP client is using the old protocol. Pin 2026-07-28, or use REST.
501 ... is not available on this service You called an endpoint this service does not offer (subscribe-token). Use long polling.