Skysay
Conecte assistentes de IA ao seu workspace Skysay para inspecionar e gerenciar agentes de voz, números de telefone, chamadas, SMS e campanhas por meio de OAuth ou chaves de API com escopo.
Servidor MCP hospedado
npx add-mcp 'https://api.skysay.ai/mcp'Instala no Claude Code, Codex, Cursor e outros
Documentação
MCP overview
Connect an assistant with OAuth or an API key, inspect tool schemas, and control workspace permissions.
Skysay speaks MCP (Model Context Protocol). An MCP-capable client points at the hosted endpoint, connects with OAuth or a scoped API key, and the Skysay tools appear in tools/list — ready to call. This is the universal path; the OpenClaw connector and the REST API are convenience wrappers around the same tools.
The endpoint
POST https://api.skysay.ai/mcp
Authorization: Bearer sky_your_scoped_key
Standard JSON-RPC: tools/list to discover, tools/call to invoke.
Connect with OAuth
For an assistant that supports remote MCP authorization, enter https://api.skysay.ai/mcp as the server URL and choose OAuth. Sign into Skysay, check the client and workspace shown on the consent screen, and approve the permissions you want to grant. Adding a custom connection does not require Skysay to be listed in that assistant's public directory.
The initial permissions read workspace, agent, call metadata, coverage, number and onboarding information, and evaluate policy. Reading conversation content or performing supported writes requires additional consent. Check each consent screen: some permissions allow actions that contact people or spend your Skysay balance. A connection cannot access a different workspace by passing its organization ID.
Manage and revoke connections from Connected apps on the API keys page in the Skysay workspace. Revocation invalidates the connection's tokens. Existing API keys continue to work independently and must be revoked separately.
OAuth client configuration
| Setting | Value |
|---|---|
| MCP resource | https://api.skysay.ai/mcp |
| Authorization server | https://api.skysay.ai |
| Resource discovery | https://api.skysay.ai/.well-known/oauth-protected-resource/mcp |
| Authorization server discovery | https://api.skysay.ai/.well-known/oauth-authorization-server |
| Authorization endpoint | https://api.skysay.ai/oauth/authorize |
| Token endpoint | https://api.skysay.ai/oauth/token |
| Dynamic registration endpoint | https://api.skysay.ai/oauth/register |
| Revocation endpoint | https://api.skysay.ai/oauth/revoke |
Use the authorization-code flow with PKCE S256 and public-client token authentication (none); no client secret is required. Both Client ID Metadata Documents (CIMD) and dynamic client registration (DCR) are supported. CIMD documents may advertise supported authentication methods as a list containing none, even when their legacy preference is a different method. Redirect URIs must match the client's metadata or registration. Authorization responses include the issuer (iss).
Access tokens expire after one hour. Refresh tokens rotate, expire after 30 days without renewal, and have a maximum family lifetime of 90 days. Reconnect when the client asks you to sign in again. An unauthenticated MCP request returns a 401 discovery challenge; a supported tool that needs more consent returns a 403 scope challenge. Only the scopes advertised by the authorization server can be granted through OAuth; the API-key catalogue is broader. Skysay does not currently provide OpenID Connect UserInfo or the openid and email scopes for ChatGPT Enterprise workspace-domain restrictions.
Read-only connector for Claude
Use https://api.skysay.ai/mcp/read-only for a connection that can inspect workspace data without generating audio or performing writes. It exposes exactly five tools:
account_overview: a short workspace summary — wallet, usage totals, and for each collection its total with the newest few items.list_agents: list your agents, one page at a time.get_agent: read one agent's configuration.list_numbers: list your phone numbers, one page at a time.list_calls: inspect call metadata one page at a time, without recordings or transcripts.
Each of the four collection tools answers with at most 25,000 characters, so a large workspace is read in pages rather than in one oversized answer; see Bounded results and paging.
All other tool calls are refused at this endpoint, even with a broad API key. OAuth consent accepts only account:read, agents:read, calls:read, and numbers:read. Its discovery document is https://api.skysay.ai/.well-known/oauth-protected-resource/mcp/read-only, and its OAuth resource is https://api.skysay.ai/mcp/read-only. Tokens for this resource cannot be used at /mcp, and tokens for /mcp cannot be used at the read-only endpoint. Both connections use the same sign-in, PKCE, consent, refresh and revocation flow described above.
Try “Show my Skysay workspace overview,” “List my Skysay agents,” or “Show my Skysay phone numbers.” A new workspace may return empty lists; the connector will not create sample data or provision numbers to fill them.
Connect from the workspace
You do not have to assemble the configuration by hand. The API keys page in the workspace carries a Connect an AI assistant card: create a key with only the scopes the assistant should have, then copy the ready-made server entry it shows and paste it into the assistant's MCP settings, replacing the placeholder with that key.
{
"url": "https://api.skysay.ai/mcp",
"headers": {
"Authorization": "Bearer sky_YOUR_KEY"
}
}
Use this canonical API URL for every new connection. The assistant can do exactly what the key allows and nothing more, and revoking the key disconnects it.
Results, errors and tool metadata
Tool calls return a text content block containing JSON and the same data in result.structuredContent. A tool that answers with a plain list uses { "items": [...] } in structured content; the paged collection tools (list_agents, list_calls, list_numbers) answer with a named array and a pagination object instead. A refused tool returns result.isError: true and structuredContent.error with type and message. Unexpected failures use internal_error and a request_id to quote to support. An unknown tool, or a params, name or arguments that is not the right shape, remains a JSON-RPC error (-32602); anything that goes wrong once the tool runs is a refused tool result.
Every tool has a title and read-only or destructive hints. Required scopes are in _meta["ai.skysay/required_scopes"]; alternatives are in _meta["ai.skysay/alternative_required_scopes"]. The catalogue lists all tools, even when your credential lacks their scopes. A call whose credential lacks a tool's scopes fails closed with a refused tool result naming the missing scopes.
organization_id is optional on all tools and defaults to your credential's workspace. A different workspace is refused. Streamable HTTP negotiates 2025-11-25, 2025-06-18 or 2025-03-26 through initialize. Notifications receive 202 with no body; ping is supported; GET and HEAD return 405, with no SSE stream.
The endpoint also speaks MCP 2026-07-28, which has no handshake. A client using it sends MCP-Protocol-Version: 2026-07-28 and Mcp-Method headers on every request (plus Mcp-Name for tools/call and resources/read), with the protocol version and client capabilities in params._meta. server/discover lists the supported revision; every result carries resultType, and list and read results carry ttlMs and cacheScope. A request that revision does not define, such as ping, returns 404 with -32601; a header that disagrees with the body returns 400 with -32020, and an unsupported version returns 400 with -32022 and the supported list. Requests without that header keep the handshake-era behavior only when their body does not explicitly claim a modern version. A modern body with a missing or legacy version header is rejected before any tool runs; removing the header cannot bypass modern validation.
Non-browser clients may omit Origin. If a client supplies it, either MCP endpoint accepts only the origins of the deployment's configured MCP resource URL and OAuth consent URL; an invalid, duplicate or unapproved origin returns HTTP 403 before the request body is read. The hosted defaults are https://api.skysay.ai and https://skysay.ai. Self-hosted deployments derive these origins from SKYSAY_MCP_RESOURCE_URL and SKYSAY_OAUTH_CONSENT_URL, never from a request's Host or forwarded headers.
These refusals follow the official Streamable HTTP transport specification: supplied origins are validated and contradictory version headers/body claims are refused before tools run.
Bounded results and paging
account_overview, list_agents, list_calls and list_numbers grow with your workspace, so each answers with at most 25,000 characters of result text, however large the workspace is.
The three list tools return one newest-first page:
{
"calls": [ ... ],
"pagination": {
"limit": 10,
"returned": 7,
"has_more": true,
"next_cursor": "<opaque>",
"omitted": []
}
}
limittakes 1 to 50.list_callsandlist_numbersdefault to 10,list_agentsto 50. A larger value is lowered to 50 and a smaller one raised to 1; the page reports the limit it used.- A page holds at most
limititems and at most 25,000 characters, so it can hold fewer.returnedsays how many it holds. Usehas_more, neverreturned < limit, to decide whether to continue. - Pass
next_cursorback ascursorto read the next page. It is meaningful only whilehas_moreis true, and it is opaque: pass it back exactly as given. Leavecursorout for the first page. - An item too large to fit any page on its own is not returned. It is named in
omittedas{ "id", "reason": "exceeds_result_size_budget", "read_with" }, and the next page continues after it.read_withnames the tool that reads that one item on this connection (get_agentfor an agent,get_callfor a call on the full/mcpendpoint), or isnullwhen the connection has none. - A listing is not a snapshot: an item created while you page through it may not appear, and nothing is repeated or skipped because of it.
list_callsitems are the same call recordsGET /v1/callsreturns, withoutruntime_config(the agent configuration the call ran with).get_callreturns the complete record.
account_overview is a summary, not a page. It returns wallet; usage with its totals and up to 10 line items; and, for agents, numbers, number_requests, calls and conversations, a section with:
total: how many there are;preview: up to 5 of the newest, with identifying fields only (for example an agent'sid,name,modeandstatus; a call'sid,direction,status, numbers andcreated_at; a conversation's numbers,status,last_message_atandmessage_count);returned,has_more(totalis larger thanreturned) andomitted;list_tool: the tool on this connection that pages through the complete records, ornullwhen there is none (number requests; conversations on the read-only connector). It needs its own scope.
The overview never includes SMS message content. Read messages with list_conversations (sms:read).
Migration for custom MCP clients
Read result.structuredContent instead of result.content[0].json, inspect result.isError and structuredContent.error.type instead of error.type, and read scope metadata from _meta instead of annotations.required_scopes. Standard MCP clients already understand these result types.
Since the bounded results above:
list_callsandlist_numbersreturn{ calls | numbers, pagination }instead of a list (structuredContent.items). Follownext_cursorwhilehas_moreis true to read everything.account_overviewreturns sections withtotalandpreviewinstead of complete lists of agents, numbers, number requests, calls and conversations; itsusagecarries totals and up to 10 line items.list_callsitems no longer carryruntime_config; useget_call.list_agentspages can now stop beforelimitand can name items inpagination.omitted.limitmust be an integer (10,10.0or"10"). A boolean, a fraction or other text is refused instead of being coerced. Acursormust be one this tool returned.account_overview,list_callsandlist_numbersare refused for a credential that belongs to no workspace, aslist_agentsalready was.
Prefix scopes
Some scopes are grouped by prefix — for example sms:* covers both sms:read and sms:send. Grant the specific leaf scope for least privilege, or the prefix when an agent legitimately needs the whole group.
Capabilities that a deployment can switch off
A few tools belong to capabilities an operator enables per deployment — the Simulations Lab is one. tools/list publishes them regardless, because it is a catalog of what Skysay can do rather than an inventory of what your instance has switched on. Calling one where the capability is off returns the same not-found the equivalent REST route returns.
When a tool call is refused
A refused call is a tool result with isError: true, so the assistant reads it and can correct itself. structuredContent.error names the refusal's type and message. When the same request over REST would answer with a structured body, that body is under error.body: for example, the issues of a refused configuration, or the current revision after a conflict. A missing MCP scopes or workspace refusal carries no body.
Configure an agent from MCP
An organization-scoped key with agents:read and agents:write can complete the normal customer configuration loop without switching to REST:
- Call
get_agent_catalogto discover selectable STT, LLM, and TTS options plus conversation engines. It accepts eitheragents:readorcoverage:read; usemetered_only: truewhen you need only component-metered choices. Passvoice_frontend: "gpt_live"oncreate_agentorset_agent_voice_stackto select GPT-Live 1; omit it to keep Standard. - Call
create_agent, then uselist_agentsfor a bounded newest-first page orget_agentfor one current safe agent projection. - Use
update_agentfor the ordinary mutable fields andset_agent_voice_stackto publish a selected stack. Read the published configuration back withget_agent_voice_stack. - Use
preview_voiceonly as an explicit Listen action. It can contact a provider or validate a BYOK credential, is rate-limited per workspace, and may write safe preview-rate or voice-availability state. It is not a read-only or free preview.
list_agents is deliberately a bounded MCP collection: it returns the same safe agent items as REST inside { agents, pagination }, with up to 50 agents per page (the default and maximum), and fewer when the page reaches its 25,000-character limit. Follow pagination.next_cursor only while pagination.has_more is true. REST also returns a named bounded page; its limits and migration contract are documented in REST endpoints.
list_audio_environments is the same catalogue as GET /v1/audio-environments, with the same account:read scope. It is a read-only, provider-independent discovery call: it returns Off plus the currently packaged versioned presets and never changes an agent or starts a preview. Use its exact preset ID and asset version when configuring output ambience or a Simulation Lab caller condition; do not maintain a client-side copy of the catalogue.
The key's organization is authoritative. You may omit the redundant organization_id input from create, list, and preview calls; if supplied, it must match the key's workspace. Agent IDs, optional project filters, saved voice pins, preview rate limits, credential ownership, and provider/BYOK validation stay in the same services as the REST workflow.
Browser sessions stay a browser workflow
For local stdio MCP, set both SKYSAY_MCP_SCOPES and SKYSAY_MCP_ORGANIZATION_ID before calling any tool. An absent organization fails closed; tools/list remains schema discovery only.
Superseded: /docs/agents
Content fields
Conversation content needs its content scope wherever it appears, over MCP and REST. Tools that combine content with other data stay callable at their base scope and omit the content fields:
account_overview(account:read) previews conversations without any message, so it never carries a message'sbody,metadata,errororidempotency_key, whatever the scopes.send_sms(sms:send) andsend_agent_template_message(sms:send+agents:read) return the message ID and delivery status;body,metadata,errorandidempotency_keycome back only withsms:read. This includes a retry that replays an existingidempotency_key.get_simulation_run(agents:read) returns status, verdicts and pagination. Withoutrecordings:readit omits each attempt'stranscript,recording_refandfacts, assertionactualvalues, rubricrationaleand linked-evidencenote, because each can quote the conversation.
Content-bearing webhook subscriptions
Creating or changing a webhook subscription for sms.received requires sms:read. Subscribing to call.extraction.ready requires recordings:read, because extracted results can quote the conversation. Changing any existing webhook destination requires both sms:read and recordings:read: queued deliveries and concurrent subscription changes can contain either kind of content. Removing a subscription does not make its queued content safe to redirect. Agent names and lifecycle-only subscriptions remain editable with agents:write. Over MCP, a call lacking one of these content scopes receives a refused tool result naming the missing scope, before anything is written.
[
Post-call results
Verify signed lifecycle and artifact events, then optionally read a bounded advisory summary from a completed call.
](https://skysay.ai/docs/post-call-results)[
Tool reference
Every Skysay MCP tool with its required scope, generated from the server's TOOL_SCOPES.