MCP Setup

Connect MCP clients to local speech, speakers, and model generation.

Twelve local MCP tools are supported, including text and image generation with installed language models.

Setup

Works with any MCP client that supports stdio. Install and activate edgespeak-cli first, then register EdgeSpeak. For Claude Code:

claude mcp add edgespeak -- edgespeak-cli mcp

Transports

stdio is recommended: when the desktop app is running, it reuses loaded models through the local gateway; when it is not running, stdio starts the bundled local engine and downloads missing models on demand. HTTP /mcp is the alternative, served by the running desktop app and by the headless service, and follows that gateway’s authentication setting. The shared selector also updates the HTTP examples; stdio needs no API key.

edgespeak-cli mcp                   # stdio
POST http://127.0.0.1:1117/mcp      # HTTP (desktop app running)
POST http://127.0.0.1:1118/mcp      # HTTP (edgespeak-cli serve)

Call MCP over HTTP

POST /mcp is a JSON-RPC transport at the server root, not /v1/mcp. Reuse the quickstart environment. This service uses stateless HTTP with JSON responses; there is no session ID to save. MCP clients handle initialization and discovery for you. To inspect it manually, send an initialize request first (requires jq):

Request:

Shell
MCP_URL="${EDGESPEAK_BASE_URL%/v1}/mcp"
curl --fail-with-body "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"docs-example","version":"1.0"}}}' \
  -o mcp-init.json
jq '{id, server: .result.serverInfo.name, protocolVersion: .result.protocolVersion}' mcp-init.json
MCP_PROTOCOL=$(jq -er '.result.protocolVersion' mcp-init.json)

Example output (jq projection; the negotiated protocol version may differ):

JSON
{"id":1,"server":"edgespeak","protocolVersion":"2025-03-26"}

Notify initialization, then call a tool. The notification returns 202 with an empty body; the tool request returns a JSON-RPC result. Reuse the negotiated version:

Shell
curl --fail-with-body "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $MCP_PROTOCOL" \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

curl --fail-with-body "$MCP_URL" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: $MCP_PROTOCOL" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"edgespeak_segment_sentences","arguments":{"text":"Hello world. Let us begin."}}}' \
  -o mcp-result.json
jq '.result.structuredContent' mcp-result.json

Example output (the structuredContent projection; model boundaries may differ):

JSON
{
  "metadata": {"sentence_count": 2},
  "result": [{"text":"Hello world.","start":0.0,"end":0.0},{"text":"Let us begin.","start":0.0,"end":0.0}],
  "truncated": false
}

For plain-text MCP segmentation, zero start and end values are placeholders, not measured audio timing. The HTTP text segmentation API omits these fields.

To retrieve the complete tool schemas, send {"jsonrpc":"2.0","id":3,"method":"tools/list","params":{}} with the same headers; the response has result.tools[] entries containing name, description, and inputSchema. Tool call failures may still return HTTP 200: inspect JSON-RPC error and result.isError before reading structured content.

File paths accepted by MCP are on the service host; they do not automatically upload files from a remote client. For remote transcription, pass inline audio or use the multipart HTTP API instead. Returned artifact paths also belong to the service host and are not download links.

Tools

Twelve tools, nine of them read-only. Voice creation, deletion, and Broadcast only modify managed local files. The product capability is called Broadcast, but tool identifiers keep the developer-contract term speech.

edgespeak_transcribe_file    required: path (absolute)
                             optional: model, language, diarize, timestamps (none|word|segment),
                                       min_chars, max_chars, start_margin, end_margin

edgespeak_transcribe         required: audio_base64 (decoded ≤ 50MB)
                             optional: same as transcribe_file

edgespeak_diarize_file       required: path (absolute)
                             optional: num_speakers (1..32)

edgespeak_align              required: text + exactly one of path | audio_base64
                             optional: language, protected_terms
                             result: words, plus task, text, segments, usage
                                     shaped like POST /v1/audio/alignments

edgespeak_segment_sentences  required: text or segments[]
                             optional: threshold (default 0.35), min_chars, max_chars,
                                       start_margin, end_margin

edgespeak_speech_examples    optional: model, mode, language, id, recipe
                             returns model-specific speech examples and applicability

edgespeak_list_models        no parameters → {models: [{id, owned_by, locality}]}

edgespeak_create_response    required: model, and input or images
                             optional: max_output_tokens, temperature, reasoning, translation
                                       (same shape as top-level translation on /v1/responses:
                                       target_language, language_pair, source_language, style)
                             images: at most 4; decoded total ≤ 20MB

edgespeak_list_voices        no parameters → {voices: [...]}

edgespeak_add_voice          required: audio_path (absolute), ref_text, name,
                                       consent=true
                             optional: language, speaker_description

edgespeak_delete_voice       required: voice_id (user:<uuid>)
                             built-in voices cannot be deleted

edgespeak_create_speech      required: model, input, voice
                             models: select from the current edgespeak_list_models catalog
                             optional: instructions, disable_style, clone_mode, speed, language, seed,
                                       guidance_scale, inference_steps, retry_badcase, clone_recipe,
                                       temperature, top_p, top_k, repetition_penalty,
                                       user_marks, phonetic_spans, control_policy
                             instructions: omitted / "" / null keeps the voice's saved style,
                             non-empty text uses that style for this request
                             disable_style: true speaks without any style;
                             cannot be combined with non-empty instructions
                             clone_mode: quick | ultimate; omitted uses the model default
                             voice=builtin:design designs a voice from the instructions
                             description (required)
                             qwen3-tts-voice-design requires instructions
                             with voice=builtin:auto or builtin:design
                             output: managed local WAV artifact

Every language argument uses the same codes as the HTTP API; see Languages. MCP edgespeak_segment_sentences currently exposes sentence parameters. Use the HTTP API or CLI segment --paragraph-threshold for paragraphs. Speech controls vary by model; check the model catalog and edgespeak_speech_examples before calling. For instructions, clone_mode, and builtin:design, see Style instructions, clone modes, and voice design; for translation, see Set the translation direction.

Tool request and result examples

Use each row’s tool name and arguments in the tools/call request shown above: params:{name,arguments}. Output cells are excerpts of result.structuredContent, with unrelated fields and extra array items omitted; they are not complete JSON-RPC envelopes. When calling, replace example file paths, base64 data, model IDs, and voice IDs with actual values. All paths correspond to the service host. Adding/deleting voices and creating speech write managed local files; execute those only when needed.

Tool nameExample argumentsExample structured result (excerpt)
edgespeak_list_models{}{"models":[{"id":"Qwen/Qwen3.5-4B","owned_by":"EdgeSpeak","locality":"local"}]}
edgespeak_transcribe_file{"path":"/absolute/path/hello.wav"}{"result":{"text":"Hello world."},"truncated":false}
edgespeak_transcribe{"audio_base64":"<base64 audio file bytes>"}{"result":{"text":"Hello world."},"truncated":false}
edgespeak_diarize_file{"path":"/absolute/path/meeting.wav","num_speakers":2}{"result":{"speakers":["SPEAKER_00","SPEAKER_01"],"segments":[{"start":0.4,"end":3.2,"speaker":"SPEAKER_00"}]},"truncated":false}
edgespeak_align{"path":"/absolute/path/hello.wav","text":"Hello world."}{"result":{"words":[{"word":"Hello","start":0.2,"end":0.6,"score":0.98}],"task":"align","text":"Hello world.","segments":[{"id":0,"start":0.2,"end":1.1,"text":"Hello world.","words":[{"word":"Hello","start":0.2,"end":0.6,"score":0.98}]}],"usage":{"type":"duration","seconds":1.2}},"truncated":false}
edgespeak_segment_sentences{"text":"Hello world. Let us begin."}{"metadata":{"sentence_count":2},"result":[{"text":"Hello world.","start":0.0,"end":0.0}],"truncated":false}
edgespeak_speech_examples{}{"examples":[{"model":"openbmb/VoxCPM2","mode":"voice-design","applicable":true,"reason":null}]}
edgespeak_create_response{"model":"Qwen/Qwen3.5-4B","input":"我们下周一开会。","translation":{"target_language":"en"}}{"output":[{"type":"message","role":"assistant","content":[{"type":"output_text","text":"We have a meeting next Monday."}]}]}
edgespeak_list_voices{}{"voices":[{"id":"builtin:bright-girl","available":true}]}
edgespeak_add_voice{"audio_path":"/absolute/path/reference.wav","ref_text":"Hello world.","name":"My voice","language":"en-US","consent":true}{"voice":{"id":"user:00000000-0000-4000-8000-000000000001"}}
edgespeak_create_speech{"model":"Qwen/Qwen3-TTS-0.6B-Base","voice":"builtin:bright-girl","input":"Hello world.","clone_mode":"quick"}{"artifact_path":"/service/artifacts/speech-example.wav","format":"wav","sample_rate":24000,"duration":1.2}
edgespeak_delete_voice{"voice_id":"user:00000000-0000-4000-8000-000000000001"}{"deleted":{"id":"user:00000000-0000-4000-8000-000000000001","name":"My voice"}}

For complete voice and model records, see voice fields and model discovery. The MCP model catalog uses models[] with locality; the HTTP API uses data[] with execution_location. Do not mix the two response formats. For oversized results, see Results.

Results

Text results are returned inline up to 2000 characters; output exceeding 2000 characters spills to a local artifact with an inline preview. Broadcast always returns a managed local WAV artifact path plus generation diagnostics.

≤ 2000 chars  →  { "metadata": …, "result": …, "truncated": false }
> 2000 chars  →  { "metadata": …, "preview": { "head": …, "tail": … },
                   "artifact_path": …, "artifact_json_path": …, "truncated": true }
Broadcast      →  { "artifact_path": …, "format": "wav", "sample_rate": …,
                   "duration": …, "seed_used": …, "warnings": […] }

Privacy

Speech workflows and installed local models keep source audio, voices, generated audio, transcripts, prompts, and images on this device. Only when you explicitly select a model reported as execution_location=remote is that request sent to its configured provider.

Generate with a local model

Start the desktop app, download and load a local model, then use Responses, Chat Completions, the CLI, or MCP.

Call edgespeak_create_response with the following arguments; replace the image placeholder with base64-encoded PNG bytes:

JSON
{
  "model": "Qwen/Qwen3.5-4B",
  "input": "Describe the attached image",
  "images": [{ "mime_type": "image/png", "data_base64": "<base64>" }]
}