Integrations
MCP server
TwinTone exposes its stream control surface as a remote Model Context Protocol (MCP) server, so AI assistants and agent frameworks can start, watch and end streams as tools instead of hand-rolled HTTP calls.
| Endpoint | POST https://live.twintone.ai/api/mcp |
| Transport | Streamable HTTP (MCP spec 2025-06-18) |
| Auth | Same Authorization: Bearer tt_… API key as the REST API |
| Access | Growth plan and above for live keys (tt_test_ keys are free) |
| Tools | 5 — three reads, two writes |
Transport
This server speaks Streamable HTTP with JSON responses (no SSE stream):
- Every message is a single HTTP POST of one JSON-RPC 2.0
request,notification, orresponse. - A JSON-RPC request gets
200 OK+Content-Type: application/jsonwith the matching JSON-RPC response. - A notification or response gets
202 Acceptedwith no body. - The server is stateless — no
Mcp-Session-Idis issued and none is required on later requests. GET /api/mcpreturns405(this server has no server-initiated SSE stream) andDELETE /api/mcpreturns405(no session to terminate). Both are spec-legal answers for a stateless server.- Clients should send
Accept: application/json, text/event-stream, per the spec.
Because the transport is pure HTTP request/response, any MCP client that supports Streamable HTTP works — including clients that only read a single JSON reply.
Authentication
POST /api/mcp uses the same key, scopes, plan gate and rate limit as the
REST API. Send Authorization: Bearer tt_live_… (or tt_test_…). Each tool
call re-runs the underlying REST endpoint's full stack, so scope and plan
errors surface exactly as they do over REST. With a test key, list_streams,
get_stream and end_stream only reach streams started with a test key.
Tool classification
Meta's connector review classifies and approves each tool separately as Read, Write, or Sensitive write. A write hidden inside a tool described as a read is a policy breach, so the class is explicit in every tool's description and annotation:
| Tool | Class | readOnlyHint | destructiveHint | Spends money |
|---|---|---|---|---|
list_creators | Read | true | false | no |
list_streams | Read | true | false | no |
get_stream | Read | true | false | no |
start_stream | Sensitive write | false | false | yes — billable $/hr |
end_stream | Write (destructive) | false | true | no (stops billing) |
Approval is required for writes
Starting a stream spends money and ending one is irreversible, so both write
tools are approval-gated. A tools/call for start_stream or end_stream
is refused — returning isError: true and making no upstream request —
unless the arguments include confirm: true.
// Refused — no stream is created
{ "name": "start_stream", "arguments": { "creator_id": "avt_…", "product_name": "…", "platform": "youtube" } }
// Accepted
{ "name": "start_stream", "arguments": { "creator_id": "avt_…", "product_name": "…", "platform": "youtube", "confirm": true } }
start_stream's description reports the billable rate for the calling brand's
vertical, so the client can show the real cost before approving.
Tools
list_creators — Read
List the AI creators (avatars) available to host streams. Returns the stock
marketplace roster plus your brand-owned creators. Use it to find the
creator_id to pass to start_stream.
No arguments.
list_streams — Read
List your brand's streams, newest first.
| Argument | Type | Notes |
|---|---|---|
status | string | preparing · live · ended · error (omit for all) |
limit | number | 1–100 (default 20) |
offset | number | pagination offset (default 0) |
get_stream — Read
Get the current status of a single stream.
| Argument | Type | Required |
|---|---|---|
stream_id | string | ✅ |
start_stream — Sensitive write (billable)
Start (create) a live AI-hosted stream. Billable at your vertical's hourly
rate, billed per minute, until end_stream ends it. Requires confirm: true.
| Argument | Type | Required | Notes |
|---|---|---|---|
creator_id | string | ✅ | avt_… id from list_creators |
product_name | string | ✅ | Product/game being featured |
platform | string | ✅ | youtube tiktok twitch kick facebook instagram |
duration_minutes | number | live keys | 1–480 |
script | string | – | Talking points |
vertical | string | – | Must match your brand's vertical |
confirm | boolean | ✅ | Must be true |
end_stream — Write (destructive)
End a live stream immediately (status → ended; billing stops). Irreversible.
Requires confirm: true.
| Argument | Type | Required |
|---|---|---|
stream_id | string | ✅ |
confirm | boolean | ✅ (must be true) |
Example session
# initialize
curl -s https://live.twintone.ai/api/mcp \
-H "Authorization: Bearer tt_live_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"my-client","version":"1.0"}}}'
# list tools
curl -s https://live.twintone.ai/api/mcp \
-H "Authorization: Bearer tt_live_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# call a read tool
curl -s https://live.twintone.ai/api/mcp \
-H "Authorization: Bearer tt_live_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"list_creators","arguments":{}}}'
initialize response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": { "name": "twintone", "version": "1.0.0" }
}
}
tools/call result
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [ { "type": "text", "text": "{\"creators\":[…]}" } ],
"structuredContent": { "creators": [ … ] }
}
}
Errors
Transport/auth errors are JSON-RPC error objects:
| HTTP | error.code | Meaning |
|---|---|---|
| 401 | -32001 | Missing/invalid/revoked Bearer tt_… key |
| 429 | -32002 | Rate limited (100 req/min per brand) |
| 402 | — | Plan gate: the REST plan_required body is returned as-is |
| 400 | -32700 | Body was not valid JSON |
| 200 | -32600 | Invalid JSON-RPC request |
| 200 | -32601 | Unknown method |
A tool-level failure (e.g. a REST 400 invalid_creator, 404 not_found,
or a refused write) is not a JSON-RPC error. It returns a normal result with
isError: true and the upstream message in content[0].text.
Notes
- Every tool wraps the corresponding v1 REST endpoint — the payload shapes, scopes, gates and error codes documented in Streams and Creators apply unchanged.
- Read tools are safe to call freely; write tools require the caller to pass
confirm: truefor every call (approval is per-call, not remembered).
Was this page helpful?