The Hushscript MCP server connects an assistant to your recordings and transcripts using the Model Context Protocol. Approve an OAuth connection in your browser, or supply a personal access token. Transcription and paid actions follow your account’s personal or eligible workspace funding rules.
Two servers
Hushscript actually runs two separate MCP servers, and most readers want only one of them.
https://mcp.hushscript.com/mcp is the account server the rest of this
page describes. It accepts OAuth or a personal access token, and it is where
the account work happens: upload, transcribe, edit, export.
POST https://hushscript.com/mcp is a separate free documentation server.
No account, no token, nothing to sign in to. It is read-only and anonymous: it
cannot open an account, run a transcription, or touch anything belonging to
one. It answers questions about pricing, capabilities, page content, and how
to connect, through five tools (get_pricing, get_capabilities,
how_to_connect, list_pages, get_page) and the same information as three
resources (hushscript://pricing, hushscript://capabilities,
hushscript://connect).
If you are an agent that has just found Hushscript, hold no token, and are still deciding whether it fits before you spend anything, start with the documentation server. Come back to the rest of this page once you are ready to connect an account.
Connect
The server speaks Streamable HTTP at a single endpoint:
https://mcp.hushscript.com/mcp
There is no SSE endpoint and no Hushscript software to install locally. In Claude Code:
claude mcp add --transport http hushscript https://mcp.hushscript.com/mcp
In a client that takes a JSON config:
{
"mcpServers": {
"hushscript": {
"type": "http",
"url": "https://mcp.hushscript.com/mcp"
}
}
}
An OAuth-capable client reads /.well-known/oauth-authorization-server to
discover the endpoints. It may register through /oauth/register or use a
client ID metadata document, then opens a browser window for sign-in.
What you approve
Authorization is OAuth 2.1 with PKCE. The browser window is a Hushscript consent screen, not a password box for the client: it names the application asking, lists in plain language what it wants to do, and waits for you. Nothing is granted until you approve it there.
Access tokens last one hour, and refresh tokens last thirty days. With OAuth, your client handles those credentials for you; you never paste a personal access token into the config.
Without a browser
An OAuth connection requires browser approval. The same server also accepts a
personal access token directly, with no browser step at connection time. A
person creates one under Tokens on the
MCP page in the account,
picks its scopes, and decides whether it may buy minutes. The token is shown
once, looks like hsr1:<region>:pat.<id>.<secret>, and goes in
Authorization: Bearer <token> on every request: no OAuth round trip, no
consent screen, no client registration. The same token works against the
REST API.
A token can also belong to a machine account with no human account holder. An
agent starts a paid signup with POST /v1/agent/accounts, completes hosted
Stripe Checkout in a browser it may drive, and claims the account with a
one-time secret at POST /v1/agent/accounts/{signup_id}/claim to get its first token. That
token connects here exactly like any other. See
Automated usage for the flow end to end.
A token cannot create, list, or revoke other tokens. An account holds at most 25 active tokens. The machine account’s first token can rotate itself through the REST API; the flow is on Automated usage.
Permissions
A connection holds a set of scopes. An OAuth request that names none defaults
to ten of the eleven caller-selectable scopes, all except billing. A person
chooses the scopes on a token created in the app. A machine account’s first
token has only transcripts:read, transcripts:write, transcribe,
account:read, export, billing, and the separate pat:rotate scope for
self-rotation. Its claim enables both billing switches; a person-created token
needs them enabled deliberately. When scopes are known, the server advertises
matching tools; the backend enforces them on every call.
| Scope | What it allows |
|---|---|
transcripts:read |
Read and export transcripts, their metadata, and the deleted list |
transcripts:write |
Edit, tag, translate, restore, and delete transcripts |
transcribe |
Upload recordings, import from a link, and run transcriptions |
insights |
Read, generate, and delete Insights |
context |
Manage saved dictionaries and prompt presets |
account:read |
Read balance, usage, transactions, and holds |
settings:write |
Change account settings |
org:read |
Read workspace members, ledger, invoices, and audit log |
org:write |
Change member rights, place and lift legal holds, and schedule the move to firm (permanent) custody |
export |
Request a full account export, check its status, and download it |
billing |
Save or manage payment methods and buy minute packs |
billing is the exception in every direction. It is never granted implicitly,
the consent screen warns you before you approve it, and a purchase tool needs
both the token’s billing flag and the account-wide billing switch enabled.
pat:rotate cannot be selected in an OAuth request or the app’s token form.
What the tools cover
56 tools, grouped by what they touch:
| Group | Tools | Examples |
|---|---|---|
| Transcripts, reading | 4 | list_transcripts, get_transcript, list_deleted |
| Transcripts, writing | 10 | update_body, revert_body, retranslate, tag_transcripts |
| Transcribing | 8 | create_upload, transcribe_from_url, list_jobs, cancel_job |
| Account | 6 | get_balance, get_usage, list_transactions |
| Insights | 3 | get_insights, generate_insights, delete_insights |
| Export | 4 | export_transcript, request_account_export |
| Transcription context | 5 | save_dictionary, save_prompt_preset |
| Workspace | 10 | get_org, list_org_members, get_org_audit_log, place_transcript_hold |
| Billing | 6 | list_packs, purchase_pack, list_payment_methods, add_payment_method |
export_transcript returns TXT, SRT, VTT, Markdown, or JSON. The full set of 21
export formats lives in the app.
Beside the tools, the server publishes three resources and an instructions
string on connect: the minute packs, the credit and scope model, and the
complete error-code catalog, so a client can read the rules before it calls
anything. Paginated list tools take a limit and an opaque cursor from the
previous page’s next_cursor; list_packs and list_payment_methods return
their lists without a cursor.
MCP uploads send prepared audio. For a local video, prepare its audio on your
device first; transcribe_from_url fetches supported audio links server-side
and does not import video links. Jobs started through MCP use standard mode:
their transcripts are stored under the account’s retention setting. The
one-time private mode is available in the app, not through MCP tokens.
Examples
A client doing the OAuth flow gets a normal MCP session and never sees any of this directly: its SDK builds the JSON-RPC underneath. This is the same protocol a token-holding client sends by hand, and it works as a debugging aid either way.
Connect with a token by putting it straight on the request, no handshake
beyond initialize:
curl -s https://mcp.hushscript.com/mcp \
-H "Authorization: Bearer hsr1:us:pat.4f2a1c.9e7b3d2a5c8f1e6b4a0d7c3f2e1b9a8d" \
-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": "example-client", "version": "1.0.0" }
}
}'
Send the same request again with a different body to see every tool the token’s scopes cover:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
Each entry carries a name, a description and a JSON Schema inputSchema,
matching the groups above. Calling a tool looks like this, create_upload
reserving credit and starting an upload:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "create_upload",
"arguments": {
"size_bytes": 52428800,
"duration_seconds": 1800,
"title": "Team standup 2026-09-10",
"transcription_options": { "speaker_detection": true }
}
}
}
Structured tools such as create_upload return a content text block with
stringified JSON. For example:
{
"content": [
{
"type": "text",
"text": "{\n \"job_id\": \"job_8f3a1c2b9e\",\n \"balance_seconds\": 5400,\n \"held_seconds\": 1800,\n \"upload\": {\n \"part_size_bytes\": 33554432,\n \"total_parts\": 2,\n \"part_urls\": [\n { \"n\": 1, \"url\": \"https://...\" }\n ],\n \"next_part_number\": 2\n }\n}"
}
]
}
The response above shows the upload fields; the full response also includes
limits, funding, and state. Upload the bytes to those URLs, call
complete_upload with each part’s ETag, then poll get_job until its state
is done. The structured examples below show inner JSON directly, already
parsed, and drop the {"jsonrpc":"2.0","id":...} request wrapper since it
never changes: only name and arguments do.
export_transcript returns the rendered format as text, and
download_account_export_chunk returns raw bytes encoded as base64 text.
Parse a result’s text as JSON only when the tool returns structured data.
Listing and reading transcripts:
{
"name": "list_transcripts",
"arguments": { "limit": 5 }
}
{
"transcripts": [
{
"id": "t_9c2b7f10",
"title": "Team standup 2026-09-10",
"language_detected": "en",
"duration_seconds": 1800,
"tags": ["standup"],
"insights_state": "none"
}
],
"next_cursor": null
}
Generating Insights, free on the first call for a transcript. This example
shows the balance after a new generation starts; reused is false:
{
"name": "generate_insights",
"arguments": { "id": "t_9c2b7f10" }
}
{
"ok": true,
"reused": false,
"balance_seconds": 5400,
"held_seconds": 0
}
Buying minutes, idempotency_key required so a retry after a dropped
response cannot double-charge:
{
"name": "purchase_pack",
"arguments": {
"pack": "300min",
"payment_method_id": "pm_1PxYzABC",
"idempotency_key": "agent-2026-09-11-refill-01"
}
}
{
"status": "ok",
"balance_seconds": 23400
}
Resources answer without a tool call, resources/read naming one of the
three URIs:
{
"jsonrpc": "2.0",
"id": 9,
"method": "resources/read",
"params": { "uri": "hushscript://pricing" }
}
Abbreviated response (the resource’s explanatory note is omitted):
{
"contents": [
{
"uri": "hushscript://pricing",
"mimeType": "application/json",
"text": "{\"packs\":[{\"id\":\"45min\",\"minutes\":45},{\"id\":\"300min\",\"minutes\":300},{\"id\":\"900min\",\"minutes\":900},{\"id\":\"1800min\",\"minutes\":1800},{\"id\":\"6000min\",\"minutes\":6000}]}"
}
]
}
Use list_packs for current pack amounts and currencies.
Every backend failure carries a stable slug and a numeric code, the same
{"error": "<slug>", "code": <number>} body documented in
hushscript://error-codes. A tool call surfaces that same slug and code,
folded into a readable message instead of a raw error object, and flags the
result with isError rather than throwing:
{
"content": [
{
"type": "text",
"text": "Not enough transcription credit. This job needs 1800 seconds and the balance is 900 seconds. Top up at https://app.hushscript.com/billing (insufficient_balance, E3001)"
}
],
"isError": true
}
What costs minutes
Reading account data does not spend transcription minutes. Priced actions use the same rates as the app. Personal prepaid minutes usually fund them; a workspace transcription can use a Teams pool when the active pool alone covers the whole job and no translation target is selected. A job with translation targets or an imported audio URL uses personal minutes. Funding does not change transcript custody.
Eligible personal accounts get 30 free minutes after card verification; a machine account starts with the pack it buys at signup.
- Transcribing a recording spends minutes for its length. Medical mode adds 100%, and each translation target adds 25%. With multichannel on, each audio channel is billed separately, so a stereo file counts twice.
- Insights: the first generation per transcript is free. Regenerating later costs 40% of the recording’s length from the original transcript, or 30% from a cleaned-up version. Regeneration uses the member’s personal minutes, even when a workspace pool paid for transcription.
- Re-translating a transcript costs 25% of its length per language, and it overwrites: every language the call charges loses any hand-edited copy of that translation, with no way to get it back.
purchase_packcharges an eligible saved card straight away on success. It needs thebillingscope, the token’s own billing flag, and the account-wide billing switch. It adds minutes to the personal balance, not a Teams pool.add_payment_methodcosts nothing. It returns a Stripe Checkout link that saves a card to the account without charging it; complete it once in a browser (an agent may drive its own). Laterpurchase_packattempts an off-session charge; a decline or an issuer challenge returns a distinct error code rather than an unfinished page.
See pricing for the packs themselves.
Reviewing and revoking
For an account you can sign in to, OAuth connections appear under Connected apps on the MCP page in your account, with their client and scopes. Tokens are listed there too; revoking one cuts off its calls. Removing a client config only stops that client from asking. A machine account has no usable login mailbox, so its token instead rotates itself through the agent account flow.
Limits
Human-account tokens allow 1,200 requests a minute each. An agent account’s
token lineage shares that budget across rotations. Stripe-calling billing
routes reached through a token share 60 requests a minute per account: card
setup, purchase, default-card changes, card removal, and card-list cache
misses. Agent-account purchases and human-account token purchases are capped
at three attempts per rolling 24 hours per account. The paid agent signup
counts, as do failures after an attempt is reserved; human browser-session
purchases are exempt. A cap refusal is HTTP 429 / code 4038
agent_purchase_capped, distinct from ordinary HTTP 429 / code 5000
rate_limited. Both provide Retry-After.
OAuth authorization and completion share a 30-per-minute address bucket.
Registration has its own 30-per-minute bucket; /oauth/token has a separate
600-per-minute bucket. Each uses one IPv4 address or one IPv6 /64 as its key.
Raw-token introspection cache misses have another 30-per-minute bucket on the
same key; that is not a limit on every MCP tool call.