dsh-xiaozhi
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@dsh-xiaozhilist my active sessions"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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-web-mcp
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 /Users/tsbj/feyanggit/DHS-test/dsh-xiaozhiOr use "install from a local directory" under Settings → Plugins in DSH Web.
Paste the access point: DSH Web → Settings → Xiaozhi → Connection, put the WebSocket address from the Xiaozhi console (like
wss://api.xiaozhi.me/mcp/?token=…) into "Xiaozhi MCP access point", then press Save and reload.Check the status tab: the connection should read
connectedwith a client count. 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.
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, and every endpointHeaders value (•••••• / ***) while keeping header
names. Saving treats those sentinels as "unchanged" and drops them, so a sentinel can never
overwrite a real secret.
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 header.
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 access point ( |
|
| extra request headers (merged on write) |
|
| 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, client count, reconnects, last error, warnings, public addresses, tool/capability counts, per-group state; with Test connection, Reconnect now and Refresh.
Connection — basics, 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"114 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, |
| 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 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.
This server cannot be deployed
Maintenance
Related MCP Connectors
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.
Give any MCP-compatible AI assistant a builder for live, hosted web tools and workflows.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to interact with Dash dashboards by exposing them as MCP servers via a WebSocket bridge, with automatic tool registration and human-in-the-loop confirmation.MIT
- AlicenseAqualityBmaintenanceAn 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.67 npm20MIT
- AlicenseNot gradedqualityAmaintenanceEnables local workspace management and status checks through MCP tools over an HTTP endpoint, allowing DeepSeek Harness to interact with the platform.MIT