dsh-xiaozhi
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
dsh-xiaozhi · drive DSH by voice with the Xiaozhi assistant
Connects the Xiaozhi (小智) voice assistant to DeepSeek Harness (DSH) Web: DSH acts as the MCP tool provider, exposing workspaces, sessions, models, settings and files as tools a voice assistant can call over JSON-RPC 2.0 on a WebSocket.
English · 中文文档 · Install & verify · Tool reference
Connect the Xiaozhi voice assistant to DSH Web: DSH is the MCP tool provider, exposing 35 DSH Web endpoints as 16 voice-friendly tools, with a DSH Web settings page. 把小智(Xiaozhi)语音助手接入 DSH Web:DSH 作为 MCP 工具提供方,把 35 个接口封装成 16 个语音友好工具,自带设置页。
The pre-implementation design proposals (architecture ADR, v2 review, settings UX walkthrough) are archived in docs/design/ with every divergence from the shipped code listed.
1. What it solves
DSH's capabilities live behind HTTP REST endpoints; Xiaozhi only speaks MCP. This plugin sits between them:
you say a sentence
│
▼
┌─────────────┐ MCP (JSON-RPC 2.0 / WebSocket) ┌──────────────────────────┐
│ Xiaozhi │ ◄──────────────────────────────► │ dsh-xiaozhi (Host half) │
│ App / device │ initialize / tools/list / call │ ├ MCP session + registry │
└─────────────┘ │ ├ capability → REST map │
│ └ LocalInvoker (in-proc) │
└───────────┬──────────────┘
│ no network hop
▼
┌──────────────────────────┐
│ DSH Web REST routes (copy)│
└──────────────────────────┘Three deliberate decisions:
DSH is always the MCP server / tool provider. In both transports it answers
initialize,ping,tools/listandtools/call, and never initiates them.Outbound by default (
endpointmode). DSH dials out to the Xiaozhi MCP access point, so it needs no public IP, port forwarding or reverse proxy.In-process invocation, not loopback HTTP. Tool calls go straight to the bundled DSH REST routes through
LocalInvoker, so there is no host/port/auth guessing and no dependency on an external service.
Related MCP server: dsh-trio
2. Quick start (3 steps)
Requirements: DSH Web running (dsh web, default http://127.0.0.1:3080), a Xiaozhi account, and
its MCP access point page open.
Install from this directory:
dsh plugin add https://github.com/toddpan/dsh-xiaozhiOr use "install from a local directory" under Settings → Plugins in DSH Web.
Add a device with the access point: DSH Web → Settings → Xiaozhi → Connection, press Add device, paste the WebSocket address from the Xiaozhi console (like
wss://api.xiaozhi.me/mcp/?token=…), then press Save and reload. Add more rows to bind several Xiaozhi devices/agents at once — each connects and reports its state independently.Check the status tab: the connection should read
connected. The tab auto-refreshes every 3 seconds, so after "Reconnect now" (or a single device's reconnect) the badge flips without a manual refresh. Press Test connection to perform a real handshake.Then say to Xiaozhi: "ask DSH for my session list".
The access point URL carries a token. When the page reads the config back it shows
token=***, and saving treats that sentinel as "unchanged" rather than writing it over the real secret. See §7.
3. Two transports
|
| |
Who connects | DSH dials out to the Xiaozhi access point | The Xiaozhi server connects to DSH |
Public reachability | not needed | needed (or a reverse proxy / same LAN) |
Main settings |
|
|
Fits | the official Xiaozhi MCP access point | a self-hosted |
Both can run at once: mode picks the primary channel, and serverPort > 0 additionally listens on
0.0.0.0.
Multi-device binding: endpoint mode binds several Xiaozhi devices (several agents' MCP access
points) at once. Each device owns one WebSocket connection with its own backoff and heartbeat; the
settings page shows per-device state and offers per-device Reconnect and Test, and removing
a device touches only that device. The list is stored under endpoints (§8); a legacy single-URL
config (endpointUrl) still works — the page shows it as one device and migrates it to the list on
the first save.
Reconnect in endpoint mode uses exponential backoff (reconnectMinMs → reconnectMaxMs, ±20%
jitter) plus a heartbeatMs ping. The Status tab and the log show every attempt.
4. Tool exposure: grouped (default) or flat
Xiaozhi sanitises tool names to [A-Za-z0-9_\-CJK]. Every name this plugin exposes is a fixed
point of that rule (e.g. dsh_session_history), so no platform-side renaming occurs.
Mode | Tools | Notes |
| 16 (fewer with groups disabled) | merged by capability area, an |
| 35 | one tool per endpoint, named after it |
Grouped is the default because a voice model picks the right tool far more reliably from 16 options than from 35; the settings page warns past 24 tools. Full mapping: docs/TOOLS.md.
Groups can be disabled per area (e.g. docs, files). allowWriteTools = false refuses
create/update/delete/send operations with a speakable message while keeping read operations
usable, even inside a grouped tool that mixes both.
5. Capability coverage
All 35 endpoints are reachable, and both tool modes cover 35/35:
Area | # | Endpoints |
System | 1 |
|
Workspaces | 6 |
|
Sessions | 13 |
|
Files | 3 |
|
Conversation | 3 |
|
Models | 5 |
|
Settings | 2 |
|
Docs | 2 |
|
Four of them are degraded under MCP semantics. Read the next section before relying on them.
6. MCP semantic degradations (please read)
tools/call is strictly request/response with no incremental channel, while several source
endpoints stream. This plugin keeps as much semantics as possible and says so, instead of pretending:
Capability | Native form | Over MCP | What it means for you |
|
| DSH collects the whole stream and returns the result text once | The voice side is not incremental; |
| long-lived SSE | collects events for a bounded window (1–30 s) then returns | A peek at recent activity, not a live subscription; poll |
| binary stream | text files return their body (clipped to | Reading binary bytes aloud is meaningless; fetch the real file from the DSH Web UI or the bundled REST layer |
| full OpenAPI JSON | a structure summary ( | Open |
Also:
dsh_say(wait=false)hands a sentence to a session without waiting: it submitsprompt-streamwith a ~1.5 s budget and, on timeout, quietly reports "submitted" plus the session status.Every tool result is clipped to
maxVoiceCharsand delivered as a single text block so speech stays short.
7. Security model
Surface | Default | Protection |
Settings API | loopback only (DSH binds | ① cross-site |
Bundled DSH REST layer | on | Set |
MCP tools | on, writes allowed |
|
| off ( | A port number listens on |
Secret masking: reading the config masks apiKey, serverToken, the token= value inside the
access point URL — including every device URL in endpoints — and every endpointHeaders /
device-headers value (•••••• / ***) while keeping header names. Saving treats those
sentinels as "unchanged" and restores the stored values, so a sentinel can never overwrite a real
secret.
Global endpointHeaders can be added or overwritten from the page but not deleted (the write is
a merge). Edit settings.json by hand to remove a global header; device-level headers are saved
per row, so deleting the line in the device card and saving removes the key.
8. Configuration
Precedence, lowest first:
code defaults (
DEFAULTSinsrc/config.ts)the plugin row's
config(the profile'scordis.patch.yml)overrides saved by the settings page (
<homeDir>/settings.json)
Option | Default | Meaning |
|
| while off, no tool can run |
|
|
|
|
| Xiaozhi MCP device list ( |
|
| (legacy single device) Xiaozhi MCP access point; ignored while |
|
| extra request headers (fallback for every device; a device-level |
|
| server-mode path (must contain |
|
|
|
|
| strongly recommended whenever |
|
|
|
|
| disabled capability areas |
|
| allow write operations |
|
| voice wait limit (must stay below the REST layer's 180000) |
|
| reply clipping length |
|
| list page size |
|
| ping interval |
|
| reconnect backoff bounds |
|
| bundled REST layer prefix (the settings API is fixed at |
|
| mount the bundled DSH REST layer |
|
| auth key for the bundled layer |
|
| allow cross-origin calls to the bundled layer |
|
| default directory for created sessions |
|
| upload limit |
|
| row config only (see below) |
|
| log every tool call |
|
| send |
|
| announced service name |
Why is
homeDirnot on the settings page? It decides where the override file lives, so honouring it from that file is circular — the page would show a new directory while overrides kept being written to the old one.homeDirtherefore comes only from the plugin rowconfig(or theDSH_XIAOZHI_HOMEenvironment variable) and the page shows it read-only.
9. Settings page
DSH Web → Settings → Xiaozhi, five tabs:
Status — connection badge, transport, masked access point, a state line per bound device, client count, reconnects, last error, warnings, public addresses, tool/capability counts, per-group state; with Test connection, Reconnect now and Refresh. The tab auto-refreshes every 3 seconds, so a reconnect updates the badge on its own.
Connection — basics, the Xiaozhi MCP device list (add / rename / remove, per-device Reconnect and Test), tool-group switches, and a collapsed advanced form. Save and reload writes the override file and restarts the runtime; Restore defaults clears every override.
Tools — the tools actually exposed, their read/write nature and capability counts.
Capabilities — all 35 capabilities by area, with method and path.
Logs — the plugin ring log (300 lines) with an optional 5-second auto refresh.
The page styles itself with DSH theme tokens (--dsw-alias-*) only, imports no
dsh-client-ui-primitives, and therefore follows the host in light and dark without clashing.
10. Development
cd dsh-xiaozhi
bash scripts/build.sh # needs a DSH source checkout for tsc (auto-probed)
node --test --test-timeout=30000 "test/*.test.mjs"127 test cases across:
File | Covers |
| MCP messages, tool-name sanitiser fixed points, envelope parsing |
| RFC 6455 framing, mask direction, fragmentation, closing handshake |
| three-layer merge, secret masking, |
| multi-device: |
| all 35 endpoints pinned verbatim; both weavings cover everything; names are sanitiser fixed points |
| in-process invocation: JSON, query strings, request bodies, streaming, 404, 504 timeout |
| handshake → |
| every capability resolves on the real route table; grouped tools end to end |
| browser-half constant parity, bilingual dictionary completeness, helpers, |
| settings API: every route the page calls is reachable with the right method; the three guards; masked-secret stripping |
| doc/code consistency: names, counts and routes cannot drift |
src/dshapi/ is a verbatim copy of @dsh-external/dsh-web-service v0.1.11 (BSD-3-Clause); the
only new file is src/dshapi/service.ts, which assembles it into one router, so an upstream update
stays a clean three-way diff. See NOTICE.
11. Troubleshooting
Symptom | Cause and fix |
Status stays | The device's access point is empty or malformed (must be |
Xiaozhi sees the tools but calls fail | Check |
Xiaozhi sees no tools at all |
|
Ids are hard to say aloud | Grouped tools shorten ids (like |
A LAN self-hosted Xiaozhi cannot connect | In |
Changing | Expected: the settings API is fixed at |
12. License
BSD-3-Clause. Derived from @dsh-external/dsh-web-service v0.1.11 (Copyright © 2026 toddpan 潘祖继)
under the same license. See LICENSE and NOTICE.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
MCP server exposing the Backtest360 engine API as tools for AI agents.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP bridge that exposes DeepSeek Harness (DSH) web UI's cordis RPC API as stdio tools, enabling any MCP client to manage workspaces, create/resume sessions, send messages, and fetch session stats.51MIT
- AlicenseNot gradedqualityCmaintenanceTurns DeepSeek Harness into an MCP server with tools for session management, agent execution, resources, and OAuth, plus browser automation and GitHub/GitLab integration.30 npm20MIT
- FlicenseAqualityCmaintenanceEnables MCP clients like Codex CLI and Claude Code to delegate tasks to a local DeepSeek Harness (dsh), with native Web transport for visible progress, model selection, and persistent long-running jobs, plus an ACP-compatible transport.61-
- AlicenseNot gradedqualityBmaintenanceEnables any MCP client to operate DeepSeek Harness sessions, execute tasks, and manage workspaces through an MCP server running inside the dsh process.409 npm1MIT