docs: refer to the MCP tools by their new underscore names

Update the README, MCP docs, in-app MCP page, i18n strings, landing copy,
docstrings and comments to match the renamed tools. CHANGELOG entries and
docs/plans are historical and left as they were.
This commit is contained in:
jamiepine
2026-10-04 00:00:54 +00:00
committed by capy-ai-staging[bot]
parent 8990104081
commit 37af180887
26 changed files with 66 additions and 65 deletions
+1 -1
View File
@@ -250,7 +250,7 @@ def _migrate_mcp_bindings(engine, inspector, tables: set[str]) -> None:
"""Drop the legacy ``default_intent`` column and add ``default_personality``.
The intent tri-state (respond / rewrite / compose) has been collapsed
to a boolean: when true, ``voicebox.speak`` rewrites input through the
to a boolean: when true, ``voicebox_speak`` rewrites input through the
profile's personality LLM before TTS.
"""
if "mcp_client_bindings" not in tables:
+1 -1
View File
@@ -272,7 +272,7 @@ class MCPClientBinding(Base):
label = Column(String, nullable=True) # display name
profile_id = Column(String, ForeignKey("profiles.id"), nullable=True)
default_engine = Column(String, nullable=True)
# When true, voicebox.speak routes through the profile's personality LLM
# When true, voicebox_speak routes through the profile's personality LLM
# (rewrite) before TTS by default. Callers can still override per call.
default_personality = Column(Boolean, nullable=False, default=False)
last_seen_at = Column(DateTime, nullable=True)
+6 -6
View File
@@ -49,10 +49,10 @@ claude mcp add voicebox \
| Name | Purpose |
|---|---|
| `voicebox.speak` | Speak text in a voice profile. Returns a generation id you can poll. |
| `voicebox.transcribe` | Whisper transcription of a base64 blob or an absolute local path. |
| `voicebox.list_captures` | Recent captures (dictation / recording / file) with transcripts. |
| `voicebox.list_profiles` | Available voice profiles (cloned + preset). |
| `voicebox_speak` | Speak text in a voice profile. Returns a generation id you can poll. |
| `voicebox_transcribe` | Whisper transcription of a base64 blob or an absolute local path. |
| `voicebox_list_captures` | Recent captures (dictation / recording / file) with transcripts. |
| `voicebox_list_profiles` | Available voice profiles (cloned + preset). |
All tools resolve voice profiles in this precedence:
@@ -69,8 +69,8 @@ Settings → MCP.
npx @modelcontextprotocol/inspector http://127.0.0.1:17493/mcp
```
Point it at the URL, hit "List tools," call `voicebox.list_profiles`
first to confirm wiring, then `voicebox.speak` for end-to-end.
Point it at the URL, hit "List tools," call `voicebox_list_profiles`
first to confirm wiring, then `voicebox_speak` for end-to-end.
## Non-MCP REST surface
+3 -3
View File
@@ -33,7 +33,7 @@ current_client_id: ContextVar[str | None] = ContextVar(
)
# Remote address of the in-flight request. Used by tools that gate
# host-filesystem access to loopback callers (see voicebox.transcribe).
# host-filesystem access to loopback callers (see voicebox_transcribe).
current_remote_addr: ContextVar[str | None] = ContextVar(
"current_remote_addr", default=None
)
@@ -61,12 +61,12 @@ def request_is_loopback() -> bool:
# ignored so the Settings UI's "last heard from" column only reflects
# calls that actually acted on the client's bindings.
#
# - /mcp — FastMCP tool calls (voicebox.speak, voicebox.transcribe, …)
# - /mcp — FastMCP tool calls (voicebox_speak, voicebox_transcribe, …)
# and the /mcp/bindings admin surface. The admin surface is never
# called with the header in practice (the frontend manages bindings
# over plain REST), so the `startswith("/mcp")` match doesn't cause
# false stamps.
# - /speak — REST mirror of voicebox.speak for non-MCP agents (shell
# - /speak — REST mirror of voicebox_speak for non-MCP agents (shell
# scripts, ACP, A2A). Uses the same per-client binding lookup, so its
# callers belong in the last-seen list too.
_STAMPED_PATH_PREFIXES: tuple[str, ...] = ("/mcp", "/speak")
+1 -1
View File
@@ -1,6 +1,6 @@
"""In-memory pub/sub for speaking-pill SSE broadcasts.
MCP ``voicebox.speak`` calls and the REST ``POST /speak`` route publish
MCP ``voicebox_speak`` calls and the REST ``POST /speak`` route publish
start/end events that DictateWindow subscribes to via /events/speak, so the
floating pill surfaces whenever an agent is speaking.
"""
+2 -2
View File
@@ -27,8 +27,8 @@ def build_mcp_server() -> FastMCP:
mcp = FastMCP(
name="voicebox",
instructions=(
"Voicebox is a local voice I/O layer. Use `voicebox.speak` to "
"play text in a voice profile, `voicebox.transcribe` for "
"Voicebox is a local voice I/O layer. Use `voicebox_speak` to "
"play text in a voice profile, `voicebox_transcribe` for "
"audio→text, and the `list_*` tools to discover profiles and "
"captures."
),
+5 -4
View File
@@ -1,8 +1,9 @@
"""Voicebox MCP tool implementations.
Thin wrappers over existing services/routes. Tools are registered with dotted
names (``voicebox.speak`` etc.) so they look natural in agent logs —
the Python function name stays snake_case.
Thin wrappers over existing services/routes. Tools are registered with
underscore-separated names (``voicebox_speak`` etc.): MCP clients such as
Claude Desktop validate tool names against ``^[a-zA-Z0-9_-]{1,64}$`` and
reject the whole tool list if any name contains a dot (#790).
"""
from __future__ import annotations
@@ -202,7 +203,7 @@ def register_tools(mcp: FastMCP) -> None:
name="voicebox_list_profiles",
description=(
"List available voice profiles (both cloned voices and presets). "
"Use the returned `name` with voicebox.speak(profile=...)."
"Use the returned `name` with voicebox_speak(profile=...)."
),
)
async def voicebox_list_profiles() -> dict[str, Any]:
+2 -2
View File
@@ -309,7 +309,7 @@ class GenerationSettingsUpdate(BaseModel):
class MCPClientBindingResponse(BaseModel):
"""Per-MCP-client voice binding — what voice / engine the server should
use when a given client_id calls voicebox.speak without args, plus an
use when a given client_id calls voicebox_speak without args, plus an
opt-in personality-rewrite default."""
client_id: str
@@ -346,7 +346,7 @@ class MCPClientBindingListResponse(BaseModel):
class SpeakRequest(BaseModel):
"""Body for POST /speak — non-MCP REST surface that mirrors voicebox.speak."""
"""Body for POST /speak — non-MCP REST surface that mirrors voicebox_speak."""
text: str = Field(..., min_length=1, max_length=10000)
profile: Optional[str] = Field(
+2 -2
View File
@@ -1,4 +1,4 @@
"""POST /speak — REST wrapper around voicebox.speak for non-MCP callers.
"""POST /speak — REST wrapper around voicebox_speak for non-MCP callers.
Shell scripts, ACP, A2A, or any agent that doesn't speak MCP can hit this
endpoint to play text through a cloned voice. Uses the same profile
@@ -30,7 +30,7 @@ async def speak(
request: Request,
db: Session = Depends(get_db),
):
"""Speak text in a voice profile. Mirrors voicebox.speak (MCP).
"""Speak text in a voice profile. Mirrors voicebox_speak (MCP).
Response shape matches POST /generate — a ``GenerationResponse`` with
``status="generating"`` and an ``id`` the caller polls at
+1 -1
View File
@@ -1,4 +1,4 @@
"""Tests for the voicebox.speak MCP tool's ``model_size`` plumbing (issue #884).
"""Tests for the voicebox_speak MCP tool's ``model_size`` plumbing (issue #884).
The MCP speak path used to build its ``GenerationRequest`` without a
``model_size``, so every agent-triggered generation silently fell back to the