diff --git a/README.md b/README.md
index a1d9e91a6..0dc03d45e 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,22 @@ See [EMQX Documentation Contributing Guide](./CONTRIBUTING-EN.md) to become a co
## Preview
+
+1. Install uv if you don't have it: https://docs.astral.sh/uv/getting-started/installation/
+
+```
+curl -LsSf https://astral.sh/uv/install.sh | sh
+```
+
+2. Run the following commands to preview the docs in docker:
+
```sh
+# initialize uv
+uv init
+uv add PyYAML
+source .venv/bin/activate
+
+# start the docker daemon before running the following command
./preview.sh ee 8080
```
diff --git a/dir.yaml b/dir.yaml
index 1ca93b7a9..3ea351760 100644
--- a/dir.yaml
+++ b/dir.yaml
@@ -928,30 +928,9 @@
children:
- emqx-ai/mcp-over-mqtt/architecture
- emqx-ai/mcp-over-mqtt/specification
- - title_en: Multimedia Server
- title_cn: 多媒体服务器
- title_ja: Multimedia Server
- path: emqx-ai/multimedia-ai/overview
- collapsed: true
- children:
- - emqx-ai/multimedia-ai/architecture
- - emqx-ai/multimedia-ai/message-protocol
- - title_en: MCP over MQTT & Multimedia Service SDKs
- title_cn: MCP over MQTT 和多媒体服务 SDK
- title_ja: MCP over MQTT & Multimedia Service SDKs
- path: emqx-ai/sdks/overview
- collapsed: true
- children:
- - title_en: Clients Compatible with Multimedia Services
- title_cn: 与多媒体服务适配的客户端
- title_ja: Clients Compatible with Multimedia Services
- path: emqx-ai/sdks/multimedia-ai/overview
- collapsed: true
- children:
- - emqx-ai/sdks/multimedia-ai/webrtc-typescript
- - title_en: MCP over MQTT SDKs
- title_cn: MCP over MQTT SDKs
- title_ja: MCP over MQTT SDKs
+ - title_en: SDKs
+ title_cn: SDKs
+ title_ja: SDKs
collapsed: true
children:
- emqx-ai/sdks/mcp-sdk-erlang
@@ -959,6 +938,69 @@
- emqx-ai/sdks/mcp-sdk-paho-c
- emqx-ai/sdks/mcp-sdk-python
- emqx-ai/sdks/mcp-sdk-typescript
+ - emqx-ai/sdks/mcp-sdk-kotlin
+ - title_en: MCP Bridge
+ title_cn: MCP 桥接
+ title_ja: MCP ブリッジ
+ path: emqx-ai/mcp-bridge/overview
+ collapsed: true
+ children:
+ - emqx-ai/mcp-bridge/quick-start
+ - title_en: Realtime Audio & Video AI
+ title_cn: 实时音视频 AI
+ title_ja: リアルタイム音声&ビデオAI
+ collapsed: true
+ children:
+ - title_en: Quick Start
+ title_cn: 快速开始
+ title_ja: クイックスタート
+ collapsed: true
+ children:
+ - emqx-ai/rtc-services/volcengine-rtc/quick-start
+ - title_en: RTC Services
+ title_cn: RTC 服务
+ title_ja: RTCサービス
+ collapsed: true
+ children:
+ - title_en: Volcengine RTC
+ title_cn: 火山引擎 RTC
+ title_ja: Volcengine RTC
+ path: emqx-ai/rtc-services/volcengine-rtc/overview
+ collapsed: true
+ children:
+ - emqx-ai/rtc-services/volcengine-rtc/installation-and-testing
+ - emqx-ai/rtc-services/volcengine-rtc/api
+ - title_en: Scenarios
+ title_cn: 场景样例
+ title_ja: シナリオ
+ collapsed: true
+ children:
+ - emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice
+ - emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat
+ - emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware
+ - title_en: GPT-Realtime
+ title_cn: GPT-Realtime
+ title_ja: GPT-Realtime
+ path: emqx-ai/rtc-services/gpt-realtime/overview
+ collapsed: true
+ children:
+ - emqx-ai/rtc-services/gpt-realtime/quick-start
+ # - title_en: EMQX Multimedia Server
+ # title_cn: EMQX 多媒体服务器
+ # title_ja: EMQX Multimedia Server
+ # path: emqx-ai/multimedia-ai/overview
+ # collapsed: true
+ # children:
+ # - emqx-ai/multimedia-ai/quick-start
+ # - emqx-ai/multimedia-ai/architecture
+ # - emqx-ai/multimedia-ai/message-protocol
+ # - title_en: SDKs
+ # title_cn: SDKs
+ # title_ja: SDKs
+ # collapsed: true
+ # path: emqx-ai/sdks/multimedia-ai/overview
+ # children:
+ # - emqx-ai/sdks/multimedia-ai/webrtc-typescript
- title_en: Tutorials
title_cn: 实用教程
title_ja: 実用的なチュートリアル
diff --git a/en_US/emqx-ai/mcp-bridge/overview.md b/en_US/emqx-ai/mcp-bridge/overview.md
new file mode 100644
index 000000000..b61d38cea
--- /dev/null
+++ b/en_US/emqx-ai/mcp-bridge/overview.md
@@ -0,0 +1,3 @@
+# MCP 桥接插件
+
+
diff --git a/en_US/emqx-ai/mcp-bridge/quick-start.md b/en_US/emqx-ai/mcp-bridge/quick-start.md
new file mode 100644
index 000000000..653fa36b4
--- /dev/null
+++ b/en_US/emqx-ai/mcp-bridge/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX MCP 桥接插件访问物联网设备
diff --git a/en_US/emqx-ai/multimedia-ai/quick-start.md b/en_US/emqx-ai/multimedia-ai/quick-start.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/en_US/emqx-ai/overview.md b/en_US/emqx-ai/overview.md
index 45587a24a..4a8c21af5 100644
--- a/en_US/emqx-ai/overview.md
+++ b/en_US/emqx-ai/overview.md
@@ -1,9 +1,2 @@
# EMQX AI
-EMQX AI is EMQX's innovative practice in the field of artificial intelligence, dedicated to providing efficient and reliable communication infrastructure for AI applications. It consists of the following two aspects:
-
-- **Message Communication:** Through the MCP over MQTT protocol, EMQX offers lightweight, low-latency tool invocation and message transmission for AI applications, meeting communication needs in scenarios such as model inference, real-time feedback, intelligent data collection, and intelligent control. See [MCP over MQTT](./mcp-over-mqtt/overview.md) for details.
-
-- **Multimedia Streaming:** Based on a WebRTC-powered multimedia server, EMQX provides real-time audio and video streaming capabilities for AI applications, suitable for scenarios like intelligent voice, video analysis, image understanding, and remote collaboration. See [Multimedia AI](./multimedia-ai/overview.md) for details.
-
-By combining these two solutions, EMQX builds a solid communication foundation for AI applications, helping developers quickly create intelligent and real-time AI solutions.
diff --git a/en_US/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png b/en_US/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png
new file mode 100644
index 000000000..3051c2754
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png differ
diff --git a/en_US/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png b/en_US/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png
new file mode 100644
index 000000000..26ac08407
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png differ
diff --git a/en_US/emqx-ai/rtc-services/gpt-realtime/overview.md b/en_US/emqx-ai/rtc-services/gpt-realtime/overview.md
new file mode 100644
index 000000000..484e6ca21
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/gpt-realtime/overview.md
@@ -0,0 +1,2 @@
+# GPT-Realtime 概述
+
diff --git a/en_US/emqx-ai/rtc-services/gpt-realtime/quick-start.md b/en_US/emqx-ai/rtc-services/gpt-realtime/quick-start.md
new file mode 100644
index 000000000..367333d65
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/gpt-realtime/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX + GPT-Realtime 构建实时语音智能体
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/api.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/api.md
new file mode 100644
index 000000000..408ec03cb
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/api.md
@@ -0,0 +1 @@
+# API 参考文档
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png
new file mode 100644
index 000000000..8796d75aa
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png
new file mode 100644
index 000000000..ea224e84e
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png
new file mode 100644
index 000000000..099d6e839
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png
new file mode 100644
index 000000000..724ccf97a
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png
new file mode 100644
index 000000000..6e927370f
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
new file mode 100644
index 000000000..fd0d942fc
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
@@ -0,0 +1 @@
+# 安装与测试
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/overview.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/overview.md
new file mode 100644
index 000000000..45c5ea8e6
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/overview.md
@@ -0,0 +1 @@
+# 火山云语音服务
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/quick-start.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/quick-start.md
new file mode 100644
index 000000000..485ed71b5
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX + 火山引擎 RTC 构建实时语音智能体
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md
new file mode 100644
index 000000000..31b4a6c1e
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md
@@ -0,0 +1 @@
+# 设备感知语音反馈场景
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png
new file mode 100644
index 000000000..6b49440ff
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md
new file mode 100644
index 000000000..e8db4f1ed
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md
@@ -0,0 +1 @@
+# 纯语音对话场景
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png
new file mode 100644
index 000000000..19c93c057
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png differ
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md
new file mode 100644
index 000000000..9f053a91b
--- /dev/null
+++ b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md
@@ -0,0 +1 @@
+# 语音控制硬件场景
diff --git a/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png
new file mode 100644
index 000000000..b0e5438d3
Binary files /dev/null and b/en_US/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png differ
diff --git a/en_US/emqx-ai/sdks/mcp-sdk-kotlin.md b/en_US/emqx-ai/sdks/mcp-sdk-kotlin.md
new file mode 100644
index 000000000..ec84890bb
--- /dev/null
+++ b/en_US/emqx-ai/sdks/mcp-sdk-kotlin.md
@@ -0,0 +1 @@
+# Kotlin SDK
\ No newline at end of file
diff --git a/en_US/emqx-ai/sdks/overview.md b/en_US/emqx-ai/sdks/overview.md
deleted file mode 100644
index 9f3764753..000000000
--- a/en_US/emqx-ai/sdks/overview.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# MCP over MQTT and Multimedia Service SDKs
-
-EMQX provides SDKs for various platforms and programming languages to help developers quickly integrate MCP over MQTT and Multimedia Server features. These SDKs abstract the underlying communication details, allowing developers to focus on implementing business logic.
-
-## Multimedia Service Client Code Examples
-
-EMQX offers client-side examples based on WebRTC and MQTT, demonstrating how to interact with the multimedia server for audio/video calls, speech recognition (ASR), and text-to-speech (TTS).
-
-Developers can use these examples as a reference to quickly integrate multimedia AI capabilities into web applications or devices.
-
-- [TypeScript WebRTC Example](./multimedia-ai/webrtc-typescript.md)
-
-## MCP over MQTT SDKs
-
-EMQX provides SDKs in multiple programming languages, making it easy to integrate MCP over MQTT across different platforms and environments:
-
-- [Erlang SDK](./mcp-sdk-erlang.md)
-- [ESP32 C SDK](./mcp-sdk-esp32-c.md)
-- [C SDK with Paho MQTT](./mcp-sdk-paho-c.md)
-- [Python SDK](./mcp-sdk-python.md)
-- [TypeScript SDK](./mcp-sdk-typescript.md)
diff --git a/gen.py b/gen.py
index 26fe8d301..d62309569 100755
--- a/gen.py
+++ b/gen.py
@@ -43,6 +43,7 @@ def is_edition_match(i, ce_or_ee):
return True
def read_title_from_md(lang, path):
+ #print(f"Reading title from {path} for lang {lang}", file=sys.stderr)
if lang == 'en':
dir = 'en_US'
elif lang == 'cn':
@@ -119,7 +120,6 @@ def move_manual(lang, edition):
# The FullLoader parameter handles the conversion from YAML
# scalar values to Python the dictionary format
all = yaml.load(content, Loader=yaml.FullLoader)
-
move_manual('en', EDITION)
move_manual('cn', EDITION)
move_manual('ja', EDITION)
diff --git a/ja_JP/emqx-ai/mcp-bridge/overview.md b/ja_JP/emqx-ai/mcp-bridge/overview.md
new file mode 100644
index 000000000..7b106628f
--- /dev/null
+++ b/ja_JP/emqx-ai/mcp-bridge/overview.md
@@ -0,0 +1 @@
+# MCP 桥接插件
diff --git a/ja_JP/emqx-ai/mcp-bridge/quick-start.md b/ja_JP/emqx-ai/mcp-bridge/quick-start.md
new file mode 100644
index 000000000..653fa36b4
--- /dev/null
+++ b/ja_JP/emqx-ai/mcp-bridge/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX MCP 桥接插件访问物联网设备
diff --git a/ja_JP/emqx-ai/mcp-over-mqtt/architecture.md b/ja_JP/emqx-ai/mcp-over-mqtt/architecture.md
index 43772dc89..ef844370f 100644
--- a/ja_JP/emqx-ai/mcp-over-mqtt/architecture.md
+++ b/ja_JP/emqx-ai/mcp-over-mqtt/architecture.md
@@ -1,96 +1 @@
# MCP over MQTT Architecture
-
-MCP over MQTT inherits the core concepts of the standard MCP architecture (Host, Client, Server), while introducing a centralized MQTT Broker as the transport layer. The broker enables message routing, service registration and discovery, authentication, and authorization.
-
-This architecture not only preserves MCP’s original context interaction model but also leverages MQTT’s lightweight and broadly applicable design, providing the foundation for many-to-many communication, load balancing, and scalability in IoT and edge computing scenarios.
-
-## Core Components of the MQTT Transport
-
-In the MCP over MQTT architecture, a centralized MQTT Broker is introduced as the message router, while other components (Host, Client, Server) remain consistent with the standard MCP design.
-
-```mermaid
-graph LR
- subgraph "Application Host Process"
- H[Host]
- C1[Client 1]
- C2[Client 2]
- C3[Client 3]
- H --> C1
- H --> C2
- H --> C3
- end
-
- subgraph "MQTT Broker"
- B[Broker]
- C1 --> B
- C2 --> B
- C3 --> B
- end
-
- subgraph "Servers"
- S1[Server A External APIs]
- R1[("Remote Resource A")]
- B --> S1
- S1 <--> R1
- end
-
- subgraph "Servers"
- S2[Server B External APIs]
- R2[("Remote Resource B")]
- B --> S2
- S2 <--> R2
- end
-```
-
-### Host, Client, and Server
-
-The Host, Client, and Server components remain unchanged (see [MCP core concepts](https://modelcontextprotocol.io/docs/learn/architecture#concepts-of-mcp)):
-
-- **Host** acts as a container and coordinator for clients.
-- Each **Client** is created by the Host and maintains an independent connection with a Server.
-- **Server** provides dedicated context and capabilities.
-
-The key difference is that Clients and Servers now communicate through the MQTT Broker, instead of directly. With the broker in place, the relationship between Clients and Servers becomes many-to-many rather than one-to-one.
-
-### Role of the MQTT Broker
-
-The MQTT Broker serves as the centralized message router:
-
-- Forwards messages between Clients and Servers.
-- Supports service registration and discovery (via retained messages).
-- Handles authentication and authorization for Clients and Servers.
-
-## Server Scaling and Load Balancing
-
-To achieve scalability and load balancing, an MCP Server can launch multiple instances (processes). Each instance connects to the broker with a unique `server-id` as its MQTT Client ID, while all instances share the same `server-name`.
-
-**Client interaction flow:**
-
-1. The Client subscribes to the service discovery topic to obtain all available `server-id`s under the target `server-name`.
-2. The Client selects a Server instance based on a custom policy (e.g., random or round-robin) and sends an `initialize` request.
-3. After initialization, the Client communicates with the selected Server instance through a dedicated RPC topic.
-
-```mermaid
-graph LR
-
- C1["MCP Client1"]
- C2["MCP Client2"]
- C3["MCP Client3"]
- C4["MCP Client4"]
-
- subgraph "MCP Server Instances (server-name-a)"
- S1[Server Instance 1]
- S2[Server Instance 2]
- end
-
- C1 <-- "RPC topic of client-1 and server instance 1" --> S1
- C2 <-- "RPC topic of client-2 and server instance 1" --> S1
- C3 <-- "RPC topic of client-3 and server instance 2" --> S2
- C4 <-- "RPC topic of client-4 and server instance 2" --> S2
-
-```
-
-This approach enables high availability and scalability of MCP servers:
-
-- **During scaling up**, existing MCP clients remain connected to old server instances, while new clients can initialize with newly added instances.
-- **During scaling down**, MCP clients can reinitialize and connect to other available server instances.
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/mcp-over-mqtt/overview.md b/ja_JP/emqx-ai/mcp-over-mqtt/overview.md
index 2439102ab..6bfbf8beb 100644
--- a/ja_JP/emqx-ai/mcp-over-mqtt/overview.md
+++ b/ja_JP/emqx-ai/mcp-over-mqtt/overview.md
@@ -1,24 +1 @@
# MCP over MQTT
-
-MCP over MQTT is an implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) that runs on top of the MQTT protocol.
-
-By leveraging MQTT’s lightweight, efficient, and widely adopted characteristics, it extends MCP’s context and tool invocation capabilities to IoT and edge computing scenarios, enabling low-latency, seamless interaction between devices and AI services.
-
-## Why Use MQTT for MCP
-
-MQTT is a lightweight, publish/subscribe messaging protocol that is widely used in IoT and edge computing. It is specifically designed to handle unreliable networks and low-bandwidth environments, making it an ideal choice for communication between edge devices and cloud services.
-
-By using MQTT as the transport layer for MCP, we extend MCP’s applicability to a broader range of scenarios, including edge computing, IoT, and cloud services, wherever MQTT is already in use.
-
-## Key Features
-
-In addition to preserving all the standard MCP capabilities, MCP over MQTT enhances and extends them with the following features:
-
-- **Built-in Service Registration and Discovery**
- MCP clients can automatically discover available MCP servers via the MQTT broker, simplifying service integration.
-- **Load Balancing and Horizontal Scalability**
- MCP servers can be scaled horizontally by deploying multiple instances while maintaining state consistency, improving both availability and throughput.
-- **Centralized Authentication and Authorization**
- By leveraging the MQTT broker’s authentication and access control mechanisms, MCP over MQTT ensures that only authorized clients can access designated MCP services.
-- **Service Name Management and Distribution**
- On top of the standard MCP protocol, EMQX introduces the concept of **MCP service names** for service identification and classification. Administrators can centrally manage and distribute service names in EMQX, simplifying unified management and maintenance in multi-service environments.
diff --git a/ja_JP/emqx-ai/mcp-over-mqtt/specification.md b/ja_JP/emqx-ai/mcp-over-mqtt/specification.md
index 5ba9899ca..33e610415 100644
--- a/ja_JP/emqx-ai/mcp-over-mqtt/specification.md
+++ b/ja_JP/emqx-ai/mcp-over-mqtt/specification.md
@@ -1,498 +1 @@
# Specification
-
-This specification defines the MQTT-specific requirements like MQTT topics and client ID formats. It also outlines the lifecycle of the MQTT transport, including service discovery, initialization, capability list changes, resource updates, and shutdown procedures.
-
-It should be read in conjunction with the [MCP Specification](https://modelcontextprotocol.io/specification/2025-06-18).
-
-## Terminology
-
-- **server-name**: The server name is the identifier of a MCP server, which will be included in the topic.
-
- Multiple connections with the same `server-name` are considered multiple instances of the same MCP server and provide exactly the same service. When the MCP client sends an initialize message, it should select one of them according to a client-side determined strategy.
-
- Multiple MCP servers with different `server-name`s may still provide similar functions. In this case, when the client sends an initialize message, it should select one of them to establish a connection as needed. The selection criteria can be based on the client's permissions, recommendations from a LLM, or the user's choice.
-
- After connected to the MQTT broker, the broker may suggest a `server-name` to the MCP server by including a `MCP-SERVER-NAME` user property in the MQTT CONNECT message. If so, the MCP server **MUST** use this `server-name` as its server name. If the broker does not suggest a `server-name`, the MCP server **SHOULD** use a default `server-name` based on the functionality it provides.
-
- The `server-name` must be a hierarchical topic style separated by `/` so that the client can subscribe to a certain type of MCP server using MQTT topic wildcards, for example: `server-type/sub-type/name`.
-
- The `server-name` should not `+` and `#` characters.
-
- The `server-name` should be unique among all MCP servers.
-
-- **server-name-filter**: The MQTT topic filter to match the `server-name`, it may include `/`, `+` and `#` characters. See descriptions about **server-name** for more details.
-
- After connected to the MQTT broker, the broker may suggest a `server-name-filter` to the MCP client by including a `MCP-SERVER-NAME-FILTERS` user property in the MQTT CONNACK message. If so, the MCP client **MUST** use this `server-name-filter` to subscribe to the server's presence topic. The value of the `MCP-SERVER-NAME-FILTERS` is a JSON array of strings, each string is a MQTT topic filter.
- If the broker does not suggest a `server-name-filter`, the MCP client **SHOULD** use a default `server-name-filter` based on the functionality it provides.
-
-- **server-id**: The MQTT Client ID of a MCP server instance. Any string except `/`, `+` and `#`. It must be globally unique and will also be included in the topic.
-
-- **mcp-client-id**: The MQTT Client ID of the client. Any string except `/`, `+` and `#`. It must be globally unique and will be included in the topic. Each time an initialization request is made, a different client-id must be used.
-
-## Message Topics
-
-MCP over MQTT transmits messages through MQTT topics. This protocol includes the following message topics:
-
-| Topic Name | Topic Name | Description |
-|----------------------------------|---------------------------------------------------------------------|------------------------------------------------------------------------------------|
-| Server's Control Topic | `$mcp-server/{server-id}/{server-name}` | Used for sending and receiving initialization messages and other control messages. |
-| Server's Capability Change Topic | `$mcp-server/capability/{server-id}/{server-name}` | Used for sending and receiving server capability list changed or the resource updated notification. |
-| Server's Presence Topic | `$mcp-server/presence/{server-id}/{server-name}` | Used for sending and receiving server's online/offline status messages. |
-| Client's Presence Topic | `$mcp-client/presence/{mcp-client-id}` | Used for sending and receiving client's online/offline status messages. |
-| Client's Capability Change Topic | `$mcp-client/capability/{mcp-client-id}` | Used for sending and receiving client capability list changed notification. |
-| RPC Topic | `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` | Used for sending and receiving RPC requests/responses, and notification messages. |
-
-## MQTT Protocol Version
-
-The MCP server and client **MUST** use MQTT Protocol version 5.0.
-
-## User Property
-
-For `CONNECT` messages, the following user properties **MUST** be set:
-- `MCP-COMPONENT-TYPE`: `mcp-client` or `mcp-server`.
-- `MCP-META`: A JSON object containing metadata about the MCP component, such as its version, implementation details, and location. This metadata can be used by the broker to suggest a server name to the MCP server or a server name filter to the MCP client.
-
-For `CONNACK` messages sent by the broker, the following user properties **MAY** be set:
-- `MCP-SERVER-NAME`: The broker suggested server name for the MCP server. Only present if it's a MCP server.
-- `MCP-RBAC`: A JSON array of server names and its corresponding role names, which can be used by the MCP client to determine the roles it has for the MCP server. Each element in the array is a JSON object with two fields: `server_name` and `role_name`. Only present if it's a MCP client.
-- `MCP-SERVER-NAME-FILTERS`: The broker suggested server name filters. It's a JSON array of strings, each string is a MQTT topic filter that the MCP client can use to subscribe to the server's presence topic. This allows the client to filter the servers it is interested in based on its permissions or other criteria. Only present if it's a MCP client.
-
-For `PUBLISH` messages, the following user properties **MUST** be set:
-- `MCP-COMPONENT-TYPE`: `mcp-client` or `mcp-server`.
-- `MCP-MQTT-CLIENT-ID`: MQTT client ID of the sender.
-
-## Session Expiry Interval
-
-The session expiry interval **MUST** be set to 0, meaning the session will be cleaned up when the client disconnects.
-
-## MQTT Client ID
-
-### MCP Server
-
-The Client ID of the MCP server can be any string except `/`, `+` and `#`, referred to as `server-id`.
-
-### MCP Client
-
-The Client ID of the MCP client, referred to as `mcp-client-id`, can be any string except `/`, `+` and `#`, each time an initialization request is made, a different client-id must be used.
-
-## MQTT Topics and Topic Filters
-
-### MCP Server Subscriptions
-
-| Topic Filter | Explanation |
-|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
-| `$mcp-server/{server-id}/{server-name}` | The control topic of the MCP server to receive control messages. |
-| `$mcp-client/capability/{mcp-client-id}` | The MCP client’s capability change topic to receive capability list changed notification of the clients. |
-| `$mcp-client/presence/{mcp-client-id}` | The MCP client’s presence topic to receive the disconnected notification of the clients. |
-| `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` | The RPC topic to receive RPC requests, RPC responses, and notifications from a MCP client. |
-
-::: info
-- The server **MUST** set the **No Local** option for the RPC topic (`$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`) subscription to avoid receiving its own messages.
-:::
-
-### MCP Server Publications
-
-| Topic Name | Messages |
-|------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
-| `$mcp-server/capability/{server-id}/{server-name}` | capability list changed or resource updated notification. |
-| `$mcp-server/presence/{server-id}/{server-name}` | Presence messages for the MCP server. See [ServiceDiscovery](#service-discovery) for more details |
-| `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` | RPC requests, responses and notifications. |
-
-::: info
-- The server **MUST** set the **RETAIN** flag to `True` for the topic `$mcp-server/presence/{server-id}/{server-name}` when publishing the server presence message.
-- When connecting to the MQTT broker, the server **MUST** set `$mcp-server/presence/{server-id}/{server-name}` as the will topic with an empty payload to clear the retain message in case of an unexpected disconnection.
-:::
-
-
-### MCP Client Subscriptions
-
-| Topic Filter | Explanation |
-|--------------------------------------------------------------------|------------------------------------------------------------------------------------------------|
-| `$mcp-server/capability/{server-id}/{server-name-filter}` | The capability change topic to receive capability list changed or resource updated notification of the MCP server. |
-| `$mcp-server/presence/+/{server-name-filter}` | The presence topic to receive the presence message of the MCP server. |
-| `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}` | The RPC topic to receive PRC requests, responses and notifications sent by the MCP server. |
-
-::: tip Note
-
-The client **MUST** set the **No Local** option for the RPC topic (`$mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}`) subscription to avoid receiving its own messages.
-:::
-
-### MCP Client Publications
-
-| Topic Name | Messages |
-|------------------------------------------------------|--------------------------------------------------------------------|
-| `$mcp-server/{server-id}/{server-name}` | Send control messages like the initialize request. |
-| `$mcp-client/capability/{mcp-client-id}` | Send client capability list changed notification |
-| `$mcp-client/presence/{mcp-client-id}` | Send disconnected notification for the MCP client. |
-| `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` | The RPC topic to send RPC requests/responses to a specific server. |
-
-::: tip Note
-
-When connecting to the MQTT broker, the client **MUST** set `$mcp-client/presence/{mcp-client-id}` as the will topic with a "disconnected" notification as the payload to notify the server in case of an unexpected disconnection.
-:::
-
-## Service Discovery
-
-### Service Registration
-
-After the MCP server starts, it registers its service with the MQTT broker. The presence topic for service discovery and registration is: `$mcp-server/presence/{server-id}/{server-name}`.
-
-The MCP server **MUST** publish a "server/online" notification to the service presence topic when they start, with the **RETAIN** flag set to `True`.
-
-The "server/online" notification **SHOULD** provide only limited information about the server to avoid the message size being too large. The client can request more detailed information after initialization.
-
-- A brief description of the MCP server's functionality to help clients determine which MCP servers they need to initialize.
-- Some metadata, such as roles and permissions, to help clients understand the access control policies of the MCP server. The `rbac` field in the metadata can include roles, each with a name, description, allowed methods, allowed tools, and allowed resources, which maybe used by the MQTT broker to implement role-based access control (RBAC) for the MCP server.
-
-```json
-{
- "jsonrpc": "2.0",
- "method": "notifications/server/online",
- "params": {
- "server_name": "example/server",
- "description": "This is a brief description about the functionalities provided by this MCP server to allow clients to choose as needed. If tools are provided, it explains what tools are available but does not include tool parameters to reduce message size.",
- "meta": {
- "rbac": {
- "roles": [
- {
- "name": "admin",
- "description": "Administrator role with full access",
- "allowed_methods": [
- "notifications/initialized",
- "ping", "tools/list", "tools/call", "resources/list", "resources/read",
- "resources/subscribe", "resources/unsubscribe"
- ],
- "allowed_tools": "all",
- "allowed_resources": "all"
- },
- {
- "name": "user",
- "description": "User role with limited access",
- "allowed_methods": [
- "notifications/initialized",
- "ping", "tools/list", "tools/call", "resources/list", "resources/read"
- ],
- "allowed_tools": [
- "get_vehicle_status", "get_vehicle_location"
- ],
- "allowed_resources": [
- "file:///vehicle/telemetry.data"
- ]
- }
- ]
- }
- }
- }
-}
-```
-
-More detailed information, such as parameter details of the tools, **SHOULD** only be fetched by the client when needed, by sending `**/list` requests to the server.
-
-The client can subscribe to the `$mcp-server/presence/+/{server-name-filter}` topic at any time, where `{server-name-filter}` is a filter for the server name.
-
-For example, if the server name is `{server-type}/{sub-type}/{name}`, and the client determines through its permissions that it can only access MCP servers of type `{server-type}/{sub-type}`, it can subscribe to `$mcp-server/presence/+/{server-type}/{sub-type}/#`, thereby subscribing to the service presence topic for all MCP servers of the `{sub-type}` type at once.
-
-Although the client can subscribe to `$mcp-server/presence/+/#` to get all types of MCP servers, the administrator might restrict it through ACL (Access Control List) on the MQTT broker to only send and receive messages on RPC topics like `$mcp-rpc/{mcp-client-id}/{server-id}/{server-type}/{sub-type}/#`. Therefore, subscribing to overly broad topics is not useful. By designing the `{server-name-filter}` appropriately, the client can reduce interference from irrelevant information.
-
-### Service Unregistration
-
-When connecting to the MQTT broker, the server must set `$mcp-server/presence/{server-id}/{server-name}` as the will topic, with an empty payload will message, to clear the registration information in case of an unexpected disconnection.
-
-Before actively disconnecting from the MQTT broker, the server **MUST** send an empty payload message to the `$mcp-server/presence/{server-id}/{server-name}` topic to clear the registration information.
-
-On the `$mcp-server/presence/{server-id}/{server-name}` topic:
-
-- When the client receives a `server/online` notification, it should record the `{server-id}` as one of the instances of that `{server-name}`.
-- When the client receives an empty payload message, it should clear the cached `{server-id}`. As long as any instance of that `{server-name}` is online, the client should consider the MCP server to be online.
-
-The message flow for service registration and unregistration is as follows:
-
-```mermaid
-sequenceDiagram
- participant MCP_Server as MCP Server
- participant MQTT_Broker as MQTT Broker
- participant MCP_Client as MCP Client
-
- MCP_Server ->> MQTT_Broker: Register Service Topic: $mcp-server/presence/{server-id}/{server-name} Retain: True
- Note right of MQTT_Broker: Store Retained Messages
-
- MCP_Client ->> MQTT_Broker: Subscribe Services Topic Filter: $mcp-server/presence/+/ {server-name-filter}
-
- MQTT_Broker ->> MCP_Client: Description of Service Topic: $mcp-server/presence/{server-id}/{server-name} Payload: "notifications/server/online"
- Note left of MCP_Client: Record the server-id for a server-name.
-
- MCP_Server ->> MQTT_Broker: Unregister Service Topic: $mcp-server/presence/{server-id}/{server-name} Retain: True Payload: Empty
- Note right of MQTT_Broker: Clean Retained Messages
-
- MQTT_Broker ->> MCP_Client: Description of Service Topic: $mcp-server/presence/{server-id}/{server-name} Payload: Empty
- Note left of MCP_Client: Remove the server-id
-```
-
-## Initialization
-
-This section only describes the MQTT transport specific parts of the initialization phase, please see [Lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#initialization) for more details.
-
-The initialization phase **MUST** be the first interaction between client and server.
-
-The client **MUST** subscribe to the RPC topic (`$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`) before sending the initialization request, with the **No Local** subscription option.
-
-The server **MUST** subscribe to the RPC topic (`$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`) before responding to the initialization response, with the **No Local** subscription option.
-
-```mermaid
-sequenceDiagram
- participant MCP_Client as MCP Client
- participant MCP_Server as MCP Server
-
- Note right of MCP_Client: Subscribe the server's RPC topic
- MCP_Client ->> MCP_Server: Initialize Request Topic: $mcp-server/{server-id}/{server-name}
- Note left of MCP_Server: Subscribe the client's RPC topic
- MCP_Server ->> MCP_Client: Initialize Response Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
- MCP_Client ->> MCP_Server: Initialized Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
- MCP_Client ->> MCP_Server: RPC Req/Resp/Notification Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
- MCP_Server ->> MCP_Client: RPC Req/Resp/Notification Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
-```
-
-The client **MUST** initiate this phase by sending an `initialize` request to the topic `$mcp-server/{server-id}/{server-name}` containing:
-
-- Protocol version supported
-- Client capabilities
-- Client implementation information
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "method": "initialize",
- "params": {
- "protocolVersion": "2024-11-05",
- "capabilities": {
- "roots": {
- "listChanged": true
- },
- "sampling": {}
- },
- "clientInfo": {
- "name": "ExampleClient",
- "version": "1.0.0"
- }
- }
-}
-```
-
-The server **MUST** respond with its own capabilities to the topic `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` and information:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "result": {
- "protocolVersion": "2024-11-05",
- "capabilities": {
- "logging": {},
- "prompts": {
- "listChanged": true
- },
- "resources": {
- "subscribe": true,
- "listChanged": true
- },
- "tools": {
- "listChanged": true
- }
- },
- "serverInfo": {
- "name": "ExampleServer",
- "version": "1.0.0"
- }
- }
-}
-```
-
-After successful initialization, the client **MUST** send an initialized notification to indicate it is ready to begin normal operations, to the topic `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`:
-
-```json
-{
- "jsonrpc": "2.0",
- "method": "notifications/initialized"
-}
-```
-
-## Capability List Changed
-
-Before initiating the Initialize request, the MCP client **MUST** subscribe to the MCP server's capability list changed topic: `$mcp-server/capability/{server-id}/{server-name-filter}`, where `{server-name-filter}` is a filter for the server name.
-
-Before the MCP server responds to the initialization request, it **MUST** first subscribe to the MCP client's capability list changed topic: `$mcp-client/capability/{mcp-client-id}`.
-
-If there are subsequent capability list updates:
-
-- The server will send a notification to: `$mcp-server/capability/{server-id}/{server-name}`
-- The client will send a notification to: `$mcp-client/capability/{mcp-client-id}`
-
-The payload of the capability list changed notification depends on the specific capability that has changed. For example "notifications/tools/list_changed" for tools. After receiving a capability list change notification, the client or server needs to retrieve the updated capability list. See the specific capability documentation for details.
-
-```mermaid
-
-sequenceDiagram
- participant MCP_Client as MCP Client
- participant MCP_Server as MCP Server
-
- Note right of MCP_Client: Client subscribes the server's capability change topic
- MCP_Client ->> MCP_Server: Initialize
-
- Note left of MCP_Server: Server subscribes the client's capability change topic
- MCP_Server ->> MCP_Client: Initialize Response
- MCP_Client ->> MCP_Server: Initialized
-
- MCP_Server -->> MCP_Client: Capability List Changed Topic: $mcp-server/capability/{server-id}/{server-name}
-
- MCP_Client ->> MCP_Server: List Capability Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
-
- MCP_Server -->> MCP_Client: List Capability Response $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
-```
-
-## Resource Update
-
-The MCP protocol specifies that the client can subscribe to changes of a specific resource.
-
-If the server provides the capability to subscribe to resources, the client can subscribe to the resource changes before sending the initialized notification.
-
-The topic for the client to subscribe to resource changes is: `$mcp-server/capability/{server-id}/{server-name}`.
-
-When a resource changes, the server **SHOULD** send a notification to `$mcp-server/capability/{server-id}/{server-name}`.
-
-```mermaid
-
-sequenceDiagram
- participant MCP_Client as MCP Client
- participant MCP_Server as MCP Server
-
- MCP_Client ->> MCP_Server: Initialize
- MCP_Server ->> MCP_Client: Initialize Response
- Note right of MCP_Client: Client subscribes the server's resource update topic
- MCP_Client ->> MCP_Server: Initialized
-
- MCP_Client ->> MCP_Server: List Resources Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name}
-
- MCP_Server -->> MCP_Client: List Resources Response Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} URIs: [{resource-uri}, {resource-uri}, ...]
-
- MCP_Server -->> MCP_Client: Resource Updated Topic: $mcp-server/capability/{server-id}/{server-name} URI: {resource-uri}
-
- MCP_Client ->> MCP_Server: Read Resource Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} URI: {resource-uri}
-
- MCP_Server -->> MCP_Client: Read Resource Response Topic: $mcp-rpc/{mcp-client-id}/{server-id}/{server-name} URI: {resource-uri}
-```
-
-## Shutdown
-
-### Server Disconnect
-
-The server **MUST** connect with a will message to notify the client when it disconnects unexpectedly, the will topic is `$mcp-server/presence/{server-id}/{server-name}` and the payload is empty.
-
-Before a MCP server disconnects from the MQTT broker, the server **MUST** send an empty message to the presence topic `$mcp-server/presence/{server-id}/{server-name}`.
-
-The MCP server may want to 'de-initialize' with a MCP client but still keep the connection with the MQTT broker, in this case it **MUST** send a "disconnected" notification to the rpc topic `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` and then unsubscribe from the following topics:
-- `$mcp-client/capability/{mcp-client-id}`
-- `$mcp-client/presence/{mcp-client-id}`
-- `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`
-
-The message format for the MCP server's "disconnected" notification is:
-
-```json
-{
- "jsonrpc": "2.0",
- "method": "notifications/disconnected"
-}
-```
-
-When a MCP client receives an empty payload message on the server's presence topic or a "disconnected" notification on the rpc topic, it **MUST** consider the server to be offline and clear the cached `{server-id}` for that `{server-name}` and unsubscribe from the following topics:
-- `$mcp-server/capability/{server-id}/{server-name-filter}`
-- `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}`
-
-### Client Disconnect
-
-The server **MUST** subscribe to the client's presence topic (`$mcp-client/presence/{mcp-client-id}`) before sending the initialization response.
-
-The client **MUST** connect with a will message to notify the server when it disconnects unexpectedly, the will topic is `$mcp-client/presence/{mcp-client-id}` and the payload is a "disconnected" notification.
-
-Before the client disconnects from the MQTT broker, it **MUST** send a "disconnected" notification to the topic `$mcp-client/presence/{mcp-client-id}`.
-
-The client may want to 'de-initialize' with a MCP server but still keep the connection with the MQTT broker, in this case it **MUST** send a "disconnected" notification to the rpc topic `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}` and then unsubscribe from the following topics:
-- `$mcp-server/capability/{server-id}/{server-name-filter}`
-- `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name-filter}`
-
-After the MCP server receives the "disconnected" notification, it **MUST** unsubscribe from the following topics:
-- `$mcp-client/capability/{mcp-client-id}`
-- `$mcp-client/presence/{mcp-client-id}`
-- `$mcp-rpc/{mcp-client-id}/{server-id}/{server-name}`
-
-The message format for the MCP client's "disconnected" notification is:
-
-```json
-{
- "jsonrpc": "2.0",
- "method": "notifications/disconnected"
-}
-```
-
-## Health Checks
-
-The client or the server **MAY** send `ping` requests to the server at any time to check the health of their counterpart.
-
-- If the client does not receive a `ping` response from the server within a reasonable time, it **MUST** send a "disconnected" notification to the topic `$mcp-client/presence/{mcp-client-id}` and disconnect itself.
-- If the server does not receive a `ping` response from the client within a reasonable time, it **MUST** send any other PRC requests to the client.
-
-For more information, see [Ping](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/ping).
-
-## Timeouts
-
-All RPC requests are sent asynchronously via MQTT messages, so timeout issues need to be considered. The timeout duration may vary for different RPC requests, but it should be configurable.
-
-Below are the recommended default timeout values for each type of RPC request in this protocol:
-
-- "initialize": 30 seconds
-- "ping": 10 seconds
-- "roots/list": 30 seconds
-- "resources/list": 30 seconds
-- "tools/list": 30 seconds
-- "prompts/list": 30 seconds
-- "prompts/get": 30 seconds
-- "sampling/createMessage": 60 seconds
-- "resources/read": 30 seconds
-- "resources/templates/list": 30 seconds
-- "resources/subscribe": 30 seconds
-- "tools/call": 60 seconds
-- "completion/complete": 60 seconds
-- "logging/setLevel": 30 seconds
-
-
-
-## Error Handling
-
-Implementations **SHOULD** be prepared to handle these error cases:
-
-- Protocol version mismatch
-- Failure to negotiate required capabilities
-- Initialize request timeout
-- Shutdown timeout
-
-Implementations **SHOULD** implement appropriate timeouts for all requests, to prevent
-hung connections and resource exhaustion.
-
-Example initialization error:
-
-```json
-{
- "jsonrpc": "2.0",
- "id": 1,
- "error": {
- "code": -32602,
- "message": "Unsupported protocol version",
- "data": {
- "supported": ["2025-03-26"],
- "requested": "1.0.0"
- }
- }
-}
-```
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/multimedia-ai/architecture.md b/ja_JP/emqx-ai/multimedia-ai/architecture.md
index 98c535bc8..cfc3b6624 100644
--- a/ja_JP/emqx-ai/multimedia-ai/architecture.md
+++ b/ja_JP/emqx-ai/multimedia-ai/architecture.md
@@ -1,62 +1 @@
# Multimedia Server Architecture
-
-The EMQX Multimedia Server uses WebRTC to establish peer-to-peer audio and video data transmission with clients, while MQTT is used to carry general messages and WebRTC signaling.
-
-Developers can build AI agent programs in Python, which communicate with the Multimedia Server via Standard Input/Output (STDIO), enabling more sophisticated business logic and AI-driven workflows.
-
-The following diagram illustrates the overall architecture of an AI system built with the Multimedia Server:
-
-```mermaid
-flowchart LR
- Device <-- WebRTC --> MediaServer
- MediaServer <-- STDIO --> AIAgent
- MediaServer <--> ASRTTS
- AIAgent <--> LLM
-
- Device[Device]
- MediaServer[Multimedia Server]
- AIAgent[AI Agent]
- ASRTTS[ASR/TTS]
- LLM[LLM]
-```
-
-## Components
-
-- **Device**: Exchanges audio and video data with the Multimedia Server via WebRTC.
-- **Multimedia Server**: Processes audio and video streams from devices, provides Automatic Speech Recognition (ASR) and Text-to-Speech (TTS) services, and communicates with the AI Agent.
-- **AI Agent**: Receives ASR results from the Multimedia Server over STDIO. It encapsulates the core business logic of the AI application, calls the Large Language Model (LLM) for natural language understanding, and uses Multimedia Server APIs to send text or audio streams back to devices.
-- **ASR/TTS**: External AI service providers that offer speech recognition and text-to-speech capabilities.
-- **LLM**: Large Language Model, responsible for natural language processing and text generation.
-
-## Workflow
-
-The diagram below shows how the components interact in a typical workflow:
-
-```mermaid
-sequenceDiagram
- actor Device
- participant Media as Multimedia Server
- participant Agent as AI Agent
- participant LLM
-
- Device ->>+ Media: WebRTC Audio
- Media ->> Media: Run ASR
- Media ->> Agent: ASR Result
- Agent ->> LLM: Process Input with MCP Tools
- LLM ->> Agent: LLM Output
- Agent ->> Agent: Apply Business Logic
- Agent ->> Media: TTS Request
- Media ->> Media: Run TTS
- Media ->> Device: WebRTC Audio
- Device ->> Media: WebRTC Video
- Agent ->> Media: Image Analysis Request
- Media ->> Media: Run Image Analysis
- Media ->> Agent: Image Analysis Result
- Agent ->> LLM: Summarize Analysis Result
- LLM ->> Agent: Summary
- Agent ->> Media: TTS Request
- Media ->> Device: WebRTC Audio
- Agent ->> Agent: Additional Processing
- Agent ->> Media: Send Control Message
- Media ->> Device: MQTT Message
-```
diff --git a/ja_JP/emqx-ai/multimedia-ai/message-protocol.md b/ja_JP/emqx-ai/multimedia-ai/message-protocol.md
index 9b6ccd1ab..ff3bd2517 100644
--- a/ja_JP/emqx-ai/multimedia-ai/message-protocol.md
+++ b/ja_JP/emqx-ai/multimedia-ai/message-protocol.md
@@ -1,378 +1 @@
# Multimedia AI Messaging Protocol
-
-This document describes the message protocol used for interaction between the multimedia server, clients (devices), and AI agents.
-
-## WebRTC Signaling via MQTT
-
-After establishing the MQTT connection, the client needs to use the following MQTT topic to set up the WebRTC connection:
-
-- `$webrtc//multimedia_proxy`: The MQTT topic for signaling messages between the client and the multimedia proxy for WebRTC connection setup. The client should subscribe to this topic to receive signaling messages from the multimedia proxy.
-
-- `$webrtc/`: The MQTT topic for the device to receive signaling messages.
-
-The client should send `offer` and `candidate` messages to the `$webrtc//multimedia_proxy` topic and wait for `answer` and `candidate` messages from the multimedia proxy on the `$webrtc/` topic to establish the WebRTC connection.
-
-The format of the signaling messages for setting up the WebRTC connections:
-
-```json
-{
- "type": "sdp_offer",
- "data": {
- "sdp": ,
- "type": "offer"
- }
-}
-```
-
-```json
-{
- "type": "sdp_answer",
- "data": {
- "sdp": ,
- "type": "answer"
- }
-}
-```
-
-```json
-{
- "type": "ice_candidate",
- "data": {
- "candidate": ,
- "sdpMid": ,
- "sdpMLineIndex": ,
- "usernameFragment":
- }
-}
-```
-
-The `data` field above can be generated using the [RTCPeerConnection API](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection) in the browser, for example:
-
-```javascript
-// Create an offer
-const offer = await pc.createOffer();
-await pc.setLocalDescription(offer);
-const message = {
- type: "sdp_offer",
- data: offer
-};
-// Send the message to the multimedia proxy via MQTT
-mqttClient.publish(`$webrtc/${deviceId}/multimedia_proxy`, JSON.stringify(message));
-```
-
-```javascript
-// Handle the answer from the multimedia proxy
-mqttClient.on('message', (topic, message) => {
- const msg = JSON.parse(message.toString());
- if (msg.type === 'sdp_answer') {
- const answer = msg.data;
- pc.setRemoteDescription(new RTCSessionDescription(answer));
- } else if (msg.type === 'ice_candidate') {
- const candidate = new RTCIceCandidate(msg.data);
- pc.addIceCandidate(candidate);
- }
-});
-```
-
-The multimedia proxy will send the `webrtc_terminated` message to the client when the WebRTC connection is terminated:
-
-```json
-{
- "type": "webrtc_terminated",
- "reason": "reason for termination"
-}
-```
-
-
-## Send General Messages via MQTT
-
-The multimedia server and devices exchange general messages through the following MQTT topics:
-
-- **`$message/`**: Topic for the multimedia server to send general messages to a device.
-- **`$message//multimedia_proxy`**: Topic for a device to send arbitrary messages to the multimedia server. These messages are forwarded to the AI Agent via the `message_from_device` method.
-
-### Messages Sent from Multimedia Server to Devices
-
-The multimedia server can publish the following message types on the `$message/` topic:
-
-A `asr_response` message is sent when ASR results are available:
-
-```json
-{
- "type": "asr_response",
- "format": "merged" | "raw",
- "results":
-}
-```
-
-A `tts_begin` message is sent when a TTS task is started:
-
-```json
-{
- "type": "tts_begin",
- "task_id": "task_id"
-}
-```
-
-A `tts_text` message is sent when a text is converted to speech and the text should also be sent to the device:
-
-```json
-{
- "type": "tts_text",
- "task_id": "task_id",
- "text": "text"
-}
-```
-
-A `tts_complete` message is sent when the TTS task is completed:
-
-```json
-{
- "type": "tts_complete",
- "task_id": "task_id"
-}
-```
-
-A `tts_terminate` message is sent when the TTS task is finished or terminated:
-
-```json
-{
- "type": "tts_terminate",
- "task_id": "task_id"
-}
-```
-
-A `message` message is sent to device when the agent sends an arbitrary message to the device (by the `message_to_device` method):
-
-```json
-{
- "type": "message",
- "payload":
-}
-```
-
-### Messages Sent from Devices to the Multimedia Server
-
-Devices can publish arbitrary messages to the **`$message//multimedia_proxy`** topic.
- The multimedia server will forward these messages to the AI Agent:
-
-```json
-{
- "type": "message",
- "payload":
-}
-```
-
-
-## Interaction Protocol between Multimedia Server and AI Agent
-
-Using AI agents can can extend the capabilities of the Multimedia Server, for example by processing ASR results according to business logic or sending custom messages to devices.
-
-The multimedia proxy interacts with AI agents using a simple JSON RPC 2.0 based protocol. The messages are sent over Standard Input/Output (STDIO). Messages are delimited by newlines (`\n`), and MUST NOT contain embedded newlines.
-
-- **Initialization**:
- After the STDIO connection is established, the agent must send an initialization message to the multimedia proxy, to negotiate the protocol version and configuration:
-
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "method": "init",
- "params": {
- "protocol_version": "1.0",
- "configs": {
- "asr": {
- // If enabled, multimedia proxy will send merged ASR text (based on the timestamps of the sentences) every time a new ASR result is available, otherwise it is the agent's responsibility to merge the ASR results.
- "auto_merge": false
- }
- }
- }
- }
- ```
-
- The multimedia proxy will respond with an acknowledgment:
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "result": "ok"
- }
- ```
-
-- **ASR Result**:
- The multimedia proxy sends the ASR results as notifications to the AI agents in the following format:
- ```json
- {
- "jsonrpc": "2.0",
- "method": "asr_result",
- "params": {
- // The current device ID
- "device_id": "device_id",
- "text": "Recognized text"
- }
- }
- ```
-
-- **TTS and Send**:
-
- The AI Agent can request the Multimedia Server to perform **TTS** and send the audio to a target device.
-
- 1. The agent sends a `tts_and_send_start` message to initiate the task.
- 2. The agent sends one or more `tts_and_send` messages to provide the text to be synthesized.
- - Multiple texts for the same task can be sent in batches or sequentially, but must use the same `task_id`.
- 3. Finally, the agent sends a `tts_and_send_finish` message to signal the end of the task.
-
- The start message:
- ```json
- {
- "jsonrpc": "2.0",
- "id": "3",
- "method": "tts_and_send_start",
- "params": {
- // The device ID to send the audio to
- "device_id": "device_id",
- //
- "task_id": "aaa",
- "text": "Text to be converted to speech"
- }
- }
- ```
-
- The texts to be converted to speech can be sent in one batch:
- ```json
- [
- {
- "jsonrpc": "2.0",
- "id": "4",
- "method": "tts_and_send",
- "params": {
- // The device ID to send the audio to
- "device_id": "device_id",
- //
- "task_id": "aaa",
- "text": "Text to be converted to speech"
- }
- },
- {
- "jsonrpc": "2.0",
- "id": "5",
- "method": "tts_and_send",
- "params": {
- // The device ID to send the audio to
- "device_id": "device_id",
- //
- "task_id": "aaa",
- "text": ", and more text can be send in one batch"
- }
- },
- {
- "jsonrpc": "2.0",
- "id": "6",
- "method": "tts_and_send_finish",
- "params": {
- // The device ID to send the audio to
- "device_id": "device_id",
- // The task ID of the TTS task
- "task_id": "aaa"
- }
- }
- ]
- ```
-
- The `tts_and_send_start` and `tts_and_send_finish` messages can be sent either in the same batch as `tts_and_send` messages or separately.
-
- The Multimedia Server confirms each message with `"ok"` or returns an error:
-
- ```json
- [
- {
- "jsonrpc": "2.0",
- "id": "4",
- "result": "ok"
- },
- {
- "jsonrpc": "2.0",
- "id": "5",
- "result": "ok"
- },
- {
- "jsonrpc": "2.0",
- "id": "6",
- "result": "ok"
- }
- ]
- ```
-
-- **Image Analysis**:
- The AI agents can request the multimedia proxy to perform image analysis:
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "method": "image_analysis",
- "params": {
- // The ID of the device to capture images from
- "device_id": "device_id",
- // The count of images to capture and analyze
- "image_count": 2,
- "capture_interval": 1000, // Interval in milliseconds between captures
- "image_format": "jpeg", // Format of the captured images
- "user_prompt": "Analyze the images and provide insights"
- }
- }
- ```
-
- The multimedia proxy will respond with the analysis results:
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "result": {
- "analysis_result": "Analysis result"
- }
- }
- ```
-
-- **Forward Messages Received from Device**:
- The Multimedia Server forwards messages received on the `$message//multimedia_proxy` topic to the AI Agent using the `message_from_device` method:
-
- ```json
- {
- "jsonrpc": "2.0",
- "method": "message_from_device",
- "params": {
- // The ID of the device that sent the message
- "device_id": "device_id",
- "payload": "payload"
- }
- }
- ```
-
-- **Send Message to Device**:
- The AI Agent can send arbitrary messages to devices through the Multimedia Server:
-
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "method": "message_to_device",
- "params": {
- // The ID of the device to send the message to
- // The message will be sent to the device via the `$message/` MQTT topic
- "device_id": "device_id",
- // Or you can specify the topic manually to send message to any device
- // If specified, the `device_id` field will be ignored
- "topic": "topic/to/device",
- "payload": "payload"
- }
- }
- ```
-
- The Multimedia Server responds with a confirmation:
- ```json
- {
- "jsonrpc": "2.0",
- "id": "unique_id",
- "result": "ok"
- }
- ```
diff --git a/ja_JP/emqx-ai/multimedia-ai/overview.md b/ja_JP/emqx-ai/multimedia-ai/overview.md
index d543bea2d..245a1d316 100644
--- a/ja_JP/emqx-ai/multimedia-ai/overview.md
+++ b/ja_JP/emqx-ai/multimedia-ai/overview.md
@@ -1,33 +1 @@
# EMQX Multimedia Server
-
-The EMQX Multimedia Server is a high-performance audio and video processing platform built on WebRTC technology. It can receive RTP/SRTP audio and video streams from clients and integrates multiple AI capabilities, including Automatic Speech Recognition (ASR), Text-to-Speech (TTS), and Image Understanding. By leveraging large language models (LLMs), the EMQX Multimedia Server enables advanced voice interactions and tool invocation, providing robust technical support for AI applications that require audio and video capabilities.
-
-## Key Features
-
-- **Real-time Audio and Video Processing**
- Supports high-quality audio and video streaming with low latency and high reliability.
-- **Automatic Speech Recognition (ASR)**
- Converts speech to text with high accuracy, suitable for voice assistants, intelligent customer service, and more.
-- **Text-to-Speech (TTS)**
- Generates natural-sounding speech in multiple languages and voice styles, enhancing interactive experiences.
-- **Image Understanding**
- Integrates image recognition and analysis to support diverse visual processing tasks such as object detection and scene analysis.
-- **LLM Integration**
- Harnesses large model capabilities to enable complex voice conversations and tool invocation, meeting diverse business needs.
-- **Flexible Architecture**
- Designed for scalability and customization, supporting horizontal expansion. Developers can flexibly integrate services from different providers, including TTS, ASR, image processing, and LLMs.
-- **High Reliability**
- Built on a distributed architecture to ensure high availability and system stability under large-scale workloads.
-- **Low Latency**
- Optimized network transmission and model processing pipelines deliver smooth real-time interactions.
-
-## Use Cases
-
-The EMQX Multimedia Server can be applied to a wide range of AI-driven scenarios, including:
-
-- **Emotional Companionship**
- Provides personalized companion services through conversational AI and emotion recognition technologies.
-- **Intelligent Customer Service**
- Enables efficient voice-based interactions with ASR and TTS, improving customer service quality.
-- **Smart Device Control**
- Facilitates intuitive device control through voice commands and image recognition.
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/multimedia-ai/quick-start.md b/ja_JP/emqx-ai/multimedia-ai/quick-start.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/ja_JP/emqx-ai/overview.md b/ja_JP/emqx-ai/overview.md
index 45587a24a..e6c2fbbbb 100644
--- a/ja_JP/emqx-ai/overview.md
+++ b/ja_JP/emqx-ai/overview.md
@@ -1,9 +1 @@
# EMQX AI
-
-EMQX AI is EMQX's innovative practice in the field of artificial intelligence, dedicated to providing efficient and reliable communication infrastructure for AI applications. It consists of the following two aspects:
-
-- **Message Communication:** Through the MCP over MQTT protocol, EMQX offers lightweight, low-latency tool invocation and message transmission for AI applications, meeting communication needs in scenarios such as model inference, real-time feedback, intelligent data collection, and intelligent control. See [MCP over MQTT](./mcp-over-mqtt/overview.md) for details.
-
-- **Multimedia Streaming:** Based on a WebRTC-powered multimedia server, EMQX provides real-time audio and video streaming capabilities for AI applications, suitable for scenarios like intelligent voice, video analysis, image understanding, and remote collaboration. See [Multimedia AI](./multimedia-ai/overview.md) for details.
-
-By combining these two solutions, EMQX builds a solid communication foundation for AI applications, helping developers quickly create intelligent and real-time AI solutions.
diff --git a/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png b/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png
new file mode 100644
index 000000000..3051c2754
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png b/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png
new file mode 100644
index 000000000..26ac08407
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/gpt-realtime/overview.md b/ja_JP/emqx-ai/rtc-services/gpt-realtime/overview.md
new file mode 100644
index 000000000..484e6ca21
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/gpt-realtime/overview.md
@@ -0,0 +1,2 @@
+# GPT-Realtime 概述
+
diff --git a/ja_JP/emqx-ai/rtc-services/gpt-realtime/quick-start.md b/ja_JP/emqx-ai/rtc-services/gpt-realtime/quick-start.md
new file mode 100644
index 000000000..367333d65
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/gpt-realtime/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX + GPT-Realtime 构建实时语音智能体
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/api.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/api.md
new file mode 100644
index 000000000..408ec03cb
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/api.md
@@ -0,0 +1 @@
+# API 参考文档
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png
new file mode 100644
index 000000000..8796d75aa
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png
new file mode 100644
index 000000000..ea224e84e
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png
new file mode 100644
index 000000000..099d6e839
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png
new file mode 100644
index 000000000..724ccf97a
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png
new file mode 100644
index 000000000..6e927370f
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
new file mode 100644
index 000000000..fd0d942fc
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
@@ -0,0 +1 @@
+# 安装与测试
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/overview.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/overview.md
new file mode 100644
index 000000000..45c5ea8e6
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/overview.md
@@ -0,0 +1 @@
+# 火山云语音服务
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/quick-start.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/quick-start.md
new file mode 100644
index 000000000..070a48f98
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/quick-start.md
@@ -0,0 +1 @@
+# 使用 EMQX + 火山引擎 RTC 构建实时语音智能体
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md
new file mode 100644
index 000000000..23b9a8cac
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md
@@ -0,0 +1 @@
+# 设备感知语音反馈场景
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png
new file mode 100644
index 000000000..6b49440ff
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/device-triggered-voice.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md
new file mode 100644
index 000000000..e8db4f1ed
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.md
@@ -0,0 +1 @@
+# 纯语音对话场景
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png
new file mode 100644
index 000000000..19c93c057
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-chat.png differ
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md
new file mode 100644
index 000000000..409f49a4c
--- /dev/null
+++ b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.md
@@ -0,0 +1 @@
+# 语音控制硬件场景
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png
new file mode 100644
index 000000000..b0e5438d3
Binary files /dev/null and b/ja_JP/emqx-ai/rtc-services/volcengine-rtc/scenarios/voice-control-hardware.png differ
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-erlang.md b/ja_JP/emqx-ai/sdks/mcp-sdk-erlang.md
index 06048b30c..4d523339d 100644
--- a/ja_JP/emqx-ai/sdks/mcp-sdk-erlang.md
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-erlang.md
@@ -1,189 +1 @@
# Erlang SDK
-
-This document demonstrates how to use the [MCP over MQTT Erlang SDK](https://github.com/emqx/mcp-mqtt-erl) to create a simple MCP over MQTT server and client.
-
-## Example
-
-### Create a Simple MCP Client
-
-```erlang
--module(mcp_mqtt_erl_client_demo).
-
--behaviour(mcp_mqtt_erl_client_session).
-
--export([
- client_name/0,
- client_version/0,
- client_capabilities/0,
- received_non_mcp_message/3
-]).
--export([start_link/0]).
-
-%% The client name, version, and capabilities. These details will be sent to the server during MCP initialization.
-client_name() ->
- <<"emqx_tools/cli_demo">>.
-
-client_version() ->
- <<"1.0">>.
-
-client_capabilities() -> #{}.
-
-%% Callback for non-MCP messages
-received_non_mcp_message(MqttClient, Msg, State) ->
- io:format("~p Received non-MCP message: ~p~n", [MqttClient, Msg]),
- State.
-
-%% Start the MCP over MQTT client
-start_link() ->
- mcp_mqtt_erl_client:start_link(
- #{
- server_name_filter => <<"#">>,
- callback_mod => ?MODULE,
- broker_address => {"127.0.0.1", 1883},
- mqtt_options => #{
- clientid => <<"emqx_tools_cli_demo">>,
- username => <<"emqx">>,
- password => <<"public">>
- }
- }).
-```
-
-Here, `server_name_filter` is used to subscribe to the MQTT topic filter for MCP servers, and `mqtt_options` are options passed to the underlying MQTT client.
-
-### Create a Simple MCP Server
-
-Below is a simple MCP server implementation that supports two tools: `tool1` and `tool2`.
-
-```erlang
--module(mcp_mqtt_erl_server_demo).
-
--behaviour(mcp_mqtt_erl_server_session).
-
--include_lib("mcp_mqtt_erl/include/mcp_mqtt_erl_types.hrl").
--include_lib("mcp_mqtt_erl/include/emqx_mcp_tools.hrl").
-
--export([
- start_link/2
-]).
-
--export([
- server_name/0,
- server_id/2,
- server_version/0,
- server_capabilities/0,
- server_instructions/0,
- server_meta/0
-]).
-
--export([
- initialize/2,
- list_resources/1,
- read_resource/2,
- call_tool/3,
- list_tools/1
-]).
-
--type loop_data() :: #{
- server_id => binary(),
- client_info => map(),
- client_capabilities => map(),
- mcp_client_id => binary(),
- _ => any()
-}.
-
--spec start_link(integer(), mcp_mqtt_erl_server:config()) -> gen_statem:start_ret().
-start_link(Idx, Conf) ->
- mcp_mqtt_erl_server:start_link(Idx, Conf).
-
-server_version() ->
- <>.
-
-server_name() ->
- <<"emqx_tools/info_apis">>.
-
-server_id(ClientIdPrefix, Idx) ->
- Idx1 = integer_to_binary(Idx),
- Node = atom_to_binary(node()),
- <>.
-
-server_capabilities() ->
- #{
- resources => #{
- subscribe => true,
- listChanged => true
- },
- tools => #{
- listChanged => true
- }
- }.
-
-server_instructions() ->
- <<"">>.
-
-server_meta() ->
- #{
- authorization => #{
- roles => [<<"admin">>, <<"user">>]
- }
- }.
-
--spec initialize(binary(), client_params()) -> {ok, loop_data()}.
-initialize(ServerId, #{client_info := ClientInfo, client_capabilities := Capabilities, mcp_client_id := McpClientId}) ->
- io:format("initialize --- server_id: ~p, client_info: ~p, client_capabilities: ~p, mcp_client_id: ~p~n", [ServerId, ClientInfo, Capabilities, McpClientId]),
- {ok, #{
- server_id => ServerId,
- client_info => ClientInfo,
- client_capabilities => Capabilities,
- mcp_client_id => McpClientId
- }}.
-
--spec call_tool(binary(), map(), loop_data()) -> {ok, call_tool_result() | [call_tool_result()], loop_data()}.
-call_tool(ToolName, Args, LoopData) ->
- io:format("call_tool --- tool_name: ~p, args: ~p~n", [ToolName, Args]),
- Result = #{
- type => text,
- text => <<"This is the result of the tool call">>
- },
- {ok, Result, LoopData}.
-
--spec list_tools(loop_data()) -> {ok, [tool_def()], loop_data()}.
-list_tools(LoopData) ->
- io:format("list_tools --- ~n", []),
- Tools = [
- #{
- name => <<"tool1">>,
- description => <<"This is tool 1">>,
- inputSchema => #{
- type => <<"object">>,
- properties => #{
- arg1 => #{
- type => <<"string">>,
- description => <<"Argument 1">>
- },
- arg2 => #{
- type => <<"integer">>,
- description => <<"Argument 2">>
- }
- }
- }
- },
- #{
- name => <<"tool2">>,
- description => <<"This is tool 2">>,
- inputSchema => #{
- type => <<"object">>,
- properties => #{
- arg1 => #{
- type => <<"string">>,
- description => <<"Argument 1">>
- },
- arg2 => #{
- type => <<"boolean">>,
- description => <<"Argument 2">>
- }
- }
- }
- }
- ],
- {ok, Tools, LoopData}.
-```
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-esp32-c.md b/ja_JP/emqx-ai/sdks/mcp-sdk-esp32-c.md
index b16694429..d72aa035c 100644
--- a/ja_JP/emqx-ai/sdks/mcp-sdk-esp32-c.md
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-esp32-c.md
@@ -1,59 +1 @@
# ESP32 C SDK
-
-This guide demonstrates how to use the [MCP over MQTT C SDK for ESP32](https://github.com/mqtt-ai/esp-mcp-over-mqtt) to create a simple MCP over MQTT server.
- Currently, only the MCP server is supported. You can create an MCP client using the Python SDK for interaction.
-
-The SDK uses the MQTT library included in ESP-IDF, making it suitable for ESP32 devices. Therefore, it must be used within the ESP-IDF environment.
-
-## Create an MCP Server
-
-Following the instructions in the [ESP32 C SDK README](https://github.com/mqtt-ai/esp-mcp-over-mqtt), create a new file named `mcp_server_example.c` in your ESP-IDF project and add the following code:
-
-```c
-#include "mcp_server.h"
-
-const char* get_temperature_callback(int n_args, property_t *args) {
- // Read sensor data
- float temp = read_temperature_sensor();
-
- // Return JSON formatted result
- static char result[64];
- snprintf(result, sizeof(result), "{\"temperature\": %.2f}", temp);
- return result;
-}
-
-// Define MCP tools
-mcp_tool_t my_tools[] = {
- {
- .name = "get_temperature",
- .description = "Get device temperature",
- .property_count = 0,
- .properties = NULL,
- .call = get_temperature_callback
- }
-};
-
-// Initialize MCP server
-mcp_server_t *server = mcp_server_init(
- "esp32_sensor", // Server name
- "ESP32 Sensor MCP Server", // Description
- "mqtt://broker.example.com",// MQTT Broker URI
- "esp32_client_001", // Client ID
- "username", // Username
- "password", // Password
- NULL // Certificate (optional)
-);
-
-// Register tools
-mcp_server_register_tool(server, 1, my_tools);
-
-// Start server
-mcp_server_run(server);
-```
-
-## Use MCP Server in an ESP-IDF Project
-
-For detailed usage, see the [ESP32 MCP Demo](https://github.com/mqtt-ai/esp32-mcp-mqtt-tutorial/tree/main/samples/blog_3) project.
- This example demonstrates how to integrate the MCP over MQTT C SDK for ESP32 into an ESP-IDF project, set up an MCP server, and interact with it using an MCP client implemented in the Python SDK.
-
-After building the project with ESP-IDF and flashing it onto the ESP32 device, the MCP server will start automatically.
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-kotlin.md b/ja_JP/emqx-ai/sdks/mcp-sdk-kotlin.md
new file mode 100644
index 000000000..11511f4fd
--- /dev/null
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-kotlin.md
@@ -0,0 +1 @@
+# Kotlin SDK
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-paho-c.md b/ja_JP/emqx-ai/sdks/mcp-sdk-paho-c.md
index f0a99587d..735b60e16 100644
--- a/ja_JP/emqx-ai/sdks/mcp-sdk-paho-c.md
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-paho-c.md
@@ -1,65 +1 @@
# C SDK with Paho MQTT
-
-This guide demonstrates how to use the [MCP over MQTT C SDK with Paho MQTT](https://github.com/mqtt-ai/paho-mcp-over-mqtt) to create a simple **MCP over MQTT server**.
- Currently, only the MCP server is supported. You can use the Python SDK to create an MCP client for interaction.
-
-## Create an MCP Server
-
-Following the instructions in the [C SDK with Paho MQTT README](https://github.com/mqtt-ai/paho-mcp-over-mqtt), after installing the dependencies and SDK, create a file named `demo_mcp_server.c` and add the following code:
-
-```c
-#include "mcp_server.h"
-
-// Callback function to get temperature
-const char* get_temperature_callback(int n_args, property_t *args) {
- // Read sensor data
- float temp = read_temperature_sensor();
-
- // Return JSON formatted result
- static char result[64];
- snprintf(result, sizeof(result), "{\"temperature\": %.2f}", temp);
- return result;
-}
-
-// Define MCP tools
-mcp_tool_t my_tools[] = {
- {
- .name = "get_temperature",
- .description = "Get device temperature",
- .property_count = 0,
- .properties = NULL,
- .call = get_temperature_callback
- }
-};
-
-// Initialize MCP server
-mcp_server_t *server = mcp_server_init(
- "sensor", // Server name
- "Sensor MCP Server", // Description
- "mqtt://broker.example.com", // MQTT Broker URI
- "client_001", // Client ID
- "username", // Username
- "password", // Password
- NULL // Certificate (optional)
-);
-
-// Register tools
-mcp_server_register_tool(server, 1, my_tools);
-
-// Start server
-mcp_server_run(server);
-```
-
-## Create and Run an MCP Client with Python SDK
-
-Refer to the [Python SDK](./mcp-sdk-python.md) documentation to create an MCP client that connects to the MCP server created above and invokes the `get_temperature` tool.
-
-## Build and Compile the MCP Server with CMake
-
-You can follow the **CMake examples** provided in the [paho-mcp-over-mqtt repository](https://github.com/mqtt-ai/paho-mcp-over-mqtt).
-
-After building, run the generated executable to start the MCP server:
-
-```bash
-./demo_mcp_server
-```
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-python.md b/ja_JP/emqx-ai/sdks/mcp-sdk-python.md
index 3795c53d3..3cdf7ae3f 100644
--- a/ja_JP/emqx-ai/sdks/mcp-sdk-python.md
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-python.md
@@ -1,130 +1 @@
# Python SDK
-
-This guide demonstrates how to use the [MCP over MQTT Python SDK](https://github.com/emqx/mcp-python-sdk) to create a simple MCP over MQTT server and client.
-
-## Create a Demo Project
-
-Let's use [uv](https://docs.astral.sh/uv/) to create a demo project:
-
-```bash
-uv init mcp_over_mqtt_demo
-cd mcp_over_mqtt_demo
-```
-
-## Create a Simple MCP Server
-
-In the `mcp_over_mqtt_demo` project, create a simple MCP server that exposes a calculator tool and some resources. Create a file named `demo_mcp_server.py` and add the following code:
-
-```python
-# demo_mcp_server.py
-from mcp.server.fastmcp import FastMCP
-
-# Create an MCP server
-mcp = FastMCP(
- "demo_mcp_server/calculator",
- log_level="DEBUG",
- mqtt_server_description="A simple FastMCP server that exposes a calculator tool",
- mqtt_options={
- "host": "broker.emqx.io",
- },
-)
-
-# Add an addition tool
-@mcp.tool()
-def add(a: int, b: int) -> int:
- """Add two numbers"""
- return a + b
-
-# Add a dynamic greeting resource
-@mcp.resource("greeting://{name}")
-def get_greeting(name: str) -> str:
- """Get a personalized greeting"""
- return f"Hello, {name}!"
-```
-
-## Create a Simple MCP Client
-
-In the same project, create a simple MCP client that connects to the server and lists available tools and resources. Create a file named `demo_mcp_client.py` and add the following code:
-
-```python
-# demo_mcp_client.py
-import logging
-import anyio
-import mcp.client.mqtt as mcp_mqtt
-from mcp.shared.mqtt import configure_logging
-
-configure_logging(level="INFO")
-logger = logging.getLogger(__name__)
-
-async def on_mcp_server_discovered(client, server_name):
- logger.info(f"Discovered {server_name}, connecting ...")
- await client.initialize_mcp_server(server_name)
-
-async def on_mcp_connect(client, server_name, connect_result):
- success, init_result = connect_result
- if success == 'error':
- logger.error(f"Failed to connect to {server_name}: {init_result}")
- return
- logger.info(f"Connected to {server_name}, success={success}, init_result={init_result}")
- capabilities = init_result.capabilities
- if capabilities.prompts:
- prompts = await client.list_prompts(server_name)
- logger.info(f"Prompts of {server_name}: {prompts}")
- if capabilities.resources:
- resources = await client.list_resources(server_name)
- logger.info(f"Resources of {server_name}: {resources}")
- resource_templates = await client.list_resource_templates(server_name)
- logger.info(f"Resources templates of {server_name}: {resource_templates}")
- if capabilities.tools:
- toolsResult = await client.list_tools(server_name)
- tools = toolsResult.tools
- logger.info(f"Tools of {server_name}: {tools}")
- if tools[0].name == "add":
- result = await client.call_tool(server_name, name = tools[0].name, arguments={"a": 1, "b": 2})
- logger.info(f"Calling the tool as add(a=1, b=2), result: {result}")
-
-async def on_mcp_disconnect(client, server_name):
- logger.info(f"Disconnected from {server_name}")
-
-async def main():
- async with mcp_mqtt.MqttTransportClient(
- "test_client",
- auto_connect_to_mcp_server = True,
- on_mcp_server_discovered = on_mcp_server_discovered,
- on_mcp_connect = on_mcp_connect,
- on_mcp_disconnect = on_mcp_disconnect,
- mqtt_options = mcp_mqtt.MqttOptions(
- host="broker.emqx.io",
- )
- ) as client:
- client.start()
- while True:
- ## Simulate other works while the MQTT transport client is running in the background...
- await anyio.sleep(20)
-
-if __name__ == "__main__":
- anyio.run(main)
-```
-
-## Run the Demo
-
-1. Install the required dependencies:
-
-```bash
-uv add git+https://github.com/emqx/mcp-python-sdk --branch main
-uv add "mcp[cli]"
-```
-
-2. Now run the client:
-
-```bash
-uv run demo_mcp_client.py
-```
-
-3. Open a new terminal and run the server:
-
-```bash
-uv run mcp run --transport mqtt ./demo_mcp_server.py
-```
-
-Even if the client starts before the server, it will discover the server and connect to it. The client will list available tools and resources, and call the `add` tool with parameters `a=1` and `b=2`.
diff --git a/ja_JP/emqx-ai/sdks/mcp-sdk-typescript.md b/ja_JP/emqx-ai/sdks/mcp-sdk-typescript.md
index dcf18fbd9..0f9407892 100644
--- a/ja_JP/emqx-ai/sdks/mcp-sdk-typescript.md
+++ b/ja_JP/emqx-ai/sdks/mcp-sdk-typescript.md
@@ -1,383 +1 @@
# TypeScript SDK
-
-This guide demonstrates how to use [@emqx-ai/mcp-mqtt-sdk](https://github.com/emqx/mcp-typescript-sdk) to create an MCP over MQTT server and client.
- The SDK supports both browser and Node.js environments and provides complete TypeScript type safety.
-
-For convenience, this tutorial runs the demo in a Node.js environment. However, you can easily integrate it into a browser environment and use it with frameworks like Vue or React.
-
-## Create a Demo Project
-
-First, create a new Node.js project (Node.js >= 18 required):
-
-```bash
-mkdir mcp_typescript_demo
-cd mcp_typescript_demo
-npm init -y
-```
-
-## Install Dependencies
-
-Install the TypeScript MCP SDK:
-
-```bash
-# Using npm
-npm install @emqx-ai/mcp-mqtt-sdk
-npm install -D typescript @types/node ts-node
-
-# Or using yarn
-yarn add @emqx-ai/mcp-mqtt-sdk
-yarn add -D typescript @types/node ts-node
-
-# Or using pnpm
-pnpm add @emqx-ai/mcp-mqtt-sdk
-pnpm add -D typescript @types/node ts-node
-```
-
-## Create a Simple MCP Server
-
-In the `mcp_typescript_demo` project, create a simple MCP server exposing calculator tools and resources.
- Create a file named `demo_mcp_server.ts` and add the following code:
-
-```typescript
-// demo_mcp_server.ts
-import { McpMqttServer } from "@emqx-ai/mcp-mqtt-sdk";
-
-// Create MCP server
-const server = new McpMqttServer({
- host: "mqtt://broker.emqx.io:1883",
- serverId: "demo-calculator-server",
- serverName: "demo_server/calculator",
- name: "Calculator MCP Server",
- version: "1.0.0",
- description: "A simple calculator MCP server",
- capabilities: {
- tools: { listChanged: true },
- resources: { listChanged: true },
- },
-});
-
-// Add addition tool
-server.tool(
- "add",
- "Add two numbers",
- {
- type: "object",
- properties: {
- a: { type: "number", description: "The first number" },
- b: { type: "number", description: "The second number" },
- },
- required: ["a", "b"],
- },
- async (params: Record) => {
- const { a, b } = params as { a: number; b: number };
- const result = a + b;
- return {
- content: [
- {
- type: "text",
- text: `${a} + ${b} = ${result}`,
- },
- ],
- };
- },
-);
-
-// Add multiplication tool
-server.tool(
- "multiply",
- "Multiply two numbers",
- {
- type: "object",
- properties: {
- a: { type: "number", description: "The first number" },
- b: { type: "number", description: "The second number" },
- },
- required: ["a", "b"],
- },
- async (params: Record) => {
- const { a, b } = params as { a: number; b: number };
- const result = a * b;
- return {
- content: [
- {
- type: "text",
- text: `${a} × ${b} = ${result}`,
- },
- ],
- };
- },
-);
-
-// Add personalized greeting resources
-const names = ["Alice", "Bob", "Charlie", "Diana", "World"];
-names.forEach((name) => {
- server.resource(
- `greeting://${name}`,
- `Personalized greeting - ${name}`,
- async () => {
- return {
- contents: [
- {
- uri: `greeting://${name}`,
- mimeType: "text/plain",
- text: `Hello, ${name}! Welcome to our calculator service.`,
- },
- ],
- };
- },
- {
- description: `Generate a personalized greeting message for ${name}`,
- mimeType: "text/plain",
- },
- );
-});
-
-// Add server status resource
-server.resource(
- "status://server",
- "Server status",
- async () => {
- return {
- contents: [
- {
- uri: "status://server",
- mimeType: "application/json",
- text: JSON.stringify(
- {
- name: "Calculator MCP Server",
- status: "running",
- uptime: process.uptime(),
- availableTools: ["add", "multiply"],
- timestamp: new Date().toISOString(),
- },
- null,
- 2,
- ),
- },
- ],
- };
- },
- {
- description: "Server runtime status information",
- mimeType: "application/json",
- },
-);
-
-// Event handling
-server.on("ready", () => {
- console.log("Calculator MCP Server started");
-});
-
-server.on("error", (error) => {
- console.error("Server error:", error);
-});
-
-// Start server
-async function startServer() {
- try {
- await server.start();
- } catch (error) {
- console.error("Failed to start server:", error);
- process.exit(1);
- }
-}
-
-// Graceful shutdown
-process.on("SIGINT", async () => {
- console.log("Shutting down server...");
- await server.stop();
- process.exit(0);
-});
-
-startServer();
-```
-
-## Create a Simple MCP Client
-
-In the same project, create a simple MCP client that connects to the server and lists available tools and resources.
-Create a file named `demo_mcp_client.ts` and add the following code:
-
-```typescript
-// demo_mcp_client.ts
-import { McpMqttClient } from "@emqx-ai/mcp-mqtt-sdk";
-
-// Create MCP client
-const client = new McpMqttClient({
- host: "mqtt://broker.emqx.io:1883",
- name: "Demo MCP Client",
- version: "1.0.0",
-});
-
-async function onServerDiscovered(server: any) {
- console.log(`Discovered server ${server.name}, connecting...`);
- await client.initializeServer(server.serverId);
-}
-
-async function onServerConnected(server: any, initResult: any) {
- if (!initResult) {
- console.error(`Failed to connect to ${server.name}`);
- return;
- }
-
- console.log(`Connected to ${server.name}`);
- const capabilities = initResult.capabilities;
-
- // List tools
- if (capabilities.tools) {
- try {
- const tools = await client.listTools(server.serverId);
- console.log(
- `${server.name} tools:`,
- tools.map((t) => t.name),
- );
-
- // Test addition tool
- if (tools.some((t) => t.name === "add")) {
- const result = await client.callTool(server.serverId, "add", {
- a: 1,
- b: 2,
- });
- console.log("Result of add(a=1, b=2):", result.content[0]?.text);
- }
-
- // Test multiplication tool
- if (tools.some((t) => t.name === "multiply")) {
- const result = await client.callTool(server.serverId, "multiply", {
- a: 3,
- b: 4,
- });
- console.log("Result of multiply(a=3, b=4):", result.content[0]?.text);
- }
- } catch (error) {
- console.error("Tool operation error:", error);
- }
- }
-
- // List and read resources
- if (capabilities.resources) {
- try {
- const resources = await client.listResources(server.serverId);
- console.log(
- `${server.name} resources:`,
- resources.map((r) => r.uri),
- );
-
- // Read server status
- if (resources.some((r) => r.uri === "status://server")) {
- const status = await client.readResource(
- server.serverId,
- "status://server",
- );
- console.log("Server status:", status.contents[0]?.text);
- }
-
- // Read dynamic greeting resource
- const greeting = await client.readResource(
- server.serverId,
- "greeting://Alice",
- );
- console.log("Greeting resource:", greeting.contents[0]?.text);
- } catch (error) {
- console.error("Resource operation error:", error);
- }
- }
-}
-
-async function onServerDisconnected(serverId: string) {
- console.log(`Disconnected from server ${serverId}`);
-}
-
-// Register event handlers
-client.on("serverDiscovered", onServerDiscovered);
-client.on("serverInitialized", (server) => {
- // For demo purposes, mock the initialization result
- onServerConnected(server, { capabilities: { tools: true, resources: true } });
-});
-client.on("serverDisconnected", onServerDisconnected);
-client.on("error", (error) => {
- console.error("Client error:", error);
-});
-
-// Start client
-async function startClient() {
- try {
- await client.connect();
- console.log("Demo MCP Client started");
-
- // Keep running
- while (true) {
- // Simulate other work while MQTT client runs in the background
- await new Promise((resolve) => setTimeout(resolve, 20000));
- }
- } catch (error) {
- console.error("Failed to start client:", error);
- process.exit(1);
- }
-}
-
-// Graceful shutdown
-process.on("SIGINT", async () => {
- console.log("Shutting down client...");
- await client.disconnect();
- process.exit(0);
-});
-
-startClient();
-```
-
-## Configure the Project
-
-Since the SDK uses ES modules, configure your project to support modern JavaScript module syntax.
-
-Add module type and scripts to `package.json`:
-
-```json
-{
- "type": "module",
- "scripts": {
- "start:server": "ts-node --esm demo_mcp_server.ts",
- "start:client": "ts-node --esm demo_mcp_client.ts"
- }
-}
-```
-
-Create a `tsconfig.json` file:
-
-```json
-{
- "compilerOptions": {
- "target": "ES2022",
- "module": "ESNext",
- "moduleResolution": "node",
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": false,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true
- },
- "ts-node": {
- "esm": true
- }
-}
-```
-
-## Run the Demo
-
-1. Start the client:
-
-```bash
-npm run start:client
-```
-
-2. Open a new terminal and start the server:
-
-```bash
-npm run start:server
-```
-
-Even if the client starts before the server, it will discover and connect once the server becomes available.
-The client will list available tools, call the `add` tool with parameters `a=1` and `b=2`, and call the `multiply` tool with parameters `a=3` and `b=4`.
-
-## Conclusion
-
-With this end-to-end demo, you’ve successfully created a fully functional MCP over MQTT system. Now, large models such as DeepSeek, Claude, GPT, and Gemini can discover and invoke your exposed calculator tools via the MCP protocol, enabling seamless integration and intelligent interaction with external services.
\ No newline at end of file
diff --git a/ja_JP/emqx-ai/sdks/overview.md b/ja_JP/emqx-ai/sdks/overview.md
deleted file mode 100644
index 9f3764753..000000000
--- a/ja_JP/emqx-ai/sdks/overview.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# MCP over MQTT and Multimedia Service SDKs
-
-EMQX provides SDKs for various platforms and programming languages to help developers quickly integrate MCP over MQTT and Multimedia Server features. These SDKs abstract the underlying communication details, allowing developers to focus on implementing business logic.
-
-## Multimedia Service Client Code Examples
-
-EMQX offers client-side examples based on WebRTC and MQTT, demonstrating how to interact with the multimedia server for audio/video calls, speech recognition (ASR), and text-to-speech (TTS).
-
-Developers can use these examples as a reference to quickly integrate multimedia AI capabilities into web applications or devices.
-
-- [TypeScript WebRTC Example](./multimedia-ai/webrtc-typescript.md)
-
-## MCP over MQTT SDKs
-
-EMQX provides SDKs in multiple programming languages, making it easy to integrate MCP over MQTT across different platforms and environments:
-
-- [Erlang SDK](./mcp-sdk-erlang.md)
-- [ESP32 C SDK](./mcp-sdk-esp32-c.md)
-- [C SDK with Paho MQTT](./mcp-sdk-paho-c.md)
-- [Python SDK](./mcp-sdk-python.md)
-- [TypeScript SDK](./mcp-sdk-typescript.md)
diff --git a/zh_CN/emqx-ai/assets/overview1.png b/zh_CN/emqx-ai/assets/overview1.png
new file mode 100644
index 000000000..9b2325a3d
Binary files /dev/null and b/zh_CN/emqx-ai/assets/overview1.png differ
diff --git a/zh_CN/emqx-ai/assets/overview2.png b/zh_CN/emqx-ai/assets/overview2.png
new file mode 100644
index 000000000..52b237ec9
Binary files /dev/null and b/zh_CN/emqx-ai/assets/overview2.png differ
diff --git a/zh_CN/emqx-ai/assets/overview3.png b/zh_CN/emqx-ai/assets/overview3.png
new file mode 100644
index 000000000..268121be0
Binary files /dev/null and b/zh_CN/emqx-ai/assets/overview3.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-mcp-bridge.png b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-mcp-bridge.png
new file mode 100644
index 000000000..85ddd7450
Binary files /dev/null and b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-mcp-bridge.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-model-providers.png b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-model-providers.png
new file mode 100644
index 000000000..3efca79ba
Binary files /dev/null and b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-config-model-providers.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices-chat.png b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices-chat.png
new file mode 100644
index 000000000..9df78f1f5
Binary files /dev/null and b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices-chat.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices.png b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices.png
new file mode 100644
index 000000000..9f8511658
Binary files /dev/null and b/zh_CN/emqx-ai/mcp-bridge/assets/cherry-studio-mcp-control-devices.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/assets/mcp-bridge-config.png b/zh_CN/emqx-ai/mcp-bridge/assets/mcp-bridge-config.png
new file mode 100644
index 000000000..e0571eb57
Binary files /dev/null and b/zh_CN/emqx-ai/mcp-bridge/assets/mcp-bridge-config.png differ
diff --git a/zh_CN/emqx-ai/mcp-bridge/overview.md b/zh_CN/emqx-ai/mcp-bridge/overview.md
new file mode 100644
index 000000000..94ebbd239
--- /dev/null
+++ b/zh_CN/emqx-ai/mcp-bridge/overview.md
@@ -0,0 +1,96 @@
+# MCP 桥接插件
+
+[EMQX MCP 桥接插件](https://github.com/emqx/emqx_mcp_bridge) 是一个用于将 EMQX 与 MCP(Model Context Protocol)设备进行集成的插件。通过该插件,用户可以使用支持 MCP 的大模型或者 AI 智能体来访问和控制物联网设备。
+
+## MCP 桥接插件是如何工作的
+
+MCP 桥接插件安装并运行在 EMQX 内部,启动后它将会暴露一个 HTTP 端点,将 Streamable HTTP 或者 SSE 协议的 MCP 连接转换为 MQTT 协议。
+
+物联网设备通过 MQTT 协议连接到 EMQX 服务器,而支持 MCP 的大模型或者 AI 智能体则连接到 MCP 桥接插件的 HTTP 端点。
+
+```mermaid
+graph LR
+ subgraph "EMQX"
+ MB[MCP Bridge Plugin]
+ end
+ subgraph "AI Agents"
+ M1[LLM / MCP Client]
+ M1 --> |MCP-HTTP| MB
+ end
+ subgraph "Devices"
+ D1[Device 1]
+ D2[Device 2]
+ D3[Device 3]
+ MB --> |MQTT| D1
+ MB --> |MQTT| D2
+ MB --> |MQTT| D3
+ end
+```
+
+### 使用 MCP over MQTT 协议访问设备
+
+设备端可以选择使用 MCP over MQTT 协议,作为 MCP Server 直接暴露自己的工具和能力,插件将会将这些设备注册上来的工具按工具类型 (MCP over MQTT 协议里的 Server Name 概念在 MCP 插件中将会被映射为工具类型) 分类汇总,生成统一的工具列表供 MCP Client 使用。就是说,同类型的多个设备向 EMQX 注册的工具,会被桥接插件聚合为单个逻辑工具供模型调用。
+
+这种方式适合一个客户端访问单个或几个设备的场景,例如智能家居、工业控制、语音玩具等。这种场景下,用户通常只需要访问自己名下的设备,不需要批量访问大量设备。
+
+由于多个同类型的设备的工具会被聚合为单个逻辑工具,因此 MCP 桥接会在工具的定义中注入一个 `target-mqtt-client-id` 的必选参数。AI 智能体在调用工具时,需要根据业务逻辑确定需要访问的设备 ID,填入该参数,从而将 MCP 请求路由到具体的设备上。
+
+```mermaid
+graph LR
+ subgraph "EMQX"
+ MB[MCP Bridge Plugin]
+ end
+ subgraph "AI Agents"
+ M1[LLM / MCP Client]
+ M1 --> |MCP tools/call target-mqtt-client-id: aec1| MB
+ end
+ subgraph "Devices"
+ D1[Light: aec1]
+ D2[Light: ec82]
+ D3[Fan: 3cfa]
+ MB --> |MCP over MQTT| D1
+ MB -.-> |MCP over MQTT| D2
+ MB -.-> |MCP over MQTT| D3
+ end
+```
+
+### 使用标准 MQTT 协议访问设备
+
+设备端也可以不使用 MCP over MQTT 协议,而是使用标准的 MQTT 协议连接到 EMQX。这种情况下,用户可以通过在 MCP 桥接中编码实现 MCP 工具,从而间接访问这些普通 MQTT 设备。
+
+这种方式适合需要更加灵活地访问设备的场景,例如智慧城市、车联网、工业物联网等。在 MCP 桥接插件中,可以编码实现任意的业务逻辑,比如访问用户自定义的外部服务或接口,或者访问外部数据库获取设备上报的数据等等。
+
+关于如何实现 MCP 工具的编码示例,请参考[创建自定义 MCP 工具](https://github.com/emqx/emqx_mcp_bridge?tab=readme-ov-file#create-custom-mcp-tools)。
+
+```mermaid
+graph LR
+ subgraph "AI Agents"
+ M1[LLM / MCP Client]
+ end
+ subgraph "Devices"
+ D1[Device 1]
+ D2[Device 2]
+ D3[Device 3]
+ end
+ subgraph EMQX["EMQX"]
+ direction BT
+ MB[MCP Bridge Plugin]
+ CM[User Provided Module Tools: tool1,tool2,...]
+ MB --> |MQTT| D1
+ MB -.-> |MQTT| D2
+ MB -.-> |MQTT| D3
+ M1 --> |MCP tools/call userid=ee| MB
+ end
+ subgraph TSDB["Time Series Database"]
+ R1[Records: t1,device1,status1 t2,device2,status2 ...]
+ end
+ subgraph "User Defined Service"
+ UDS[HTTP API]
+
+ end
+ CM --> |query| TSDB
+ TSDB --> |result| CM
+ CM --> |Get device of userid=ee| UDS
+ UDS --> |Device 1| CM
+```
+
diff --git a/zh_CN/emqx-ai/mcp-bridge/quick-start.md b/zh_CN/emqx-ai/mcp-bridge/quick-start.md
new file mode 100644
index 000000000..b2b9a458a
--- /dev/null
+++ b/zh_CN/emqx-ai/mcp-bridge/quick-start.md
@@ -0,0 +1,154 @@
+# 使用 EMQX MCP 桥接访问物联网设备
+
+本指南介绍如何使用 EMQX MCP 桥接 EMQX 与支持 MCP 的模型或者 AI 智能体进行集成,从而实现对物联网设备的访问和控制。
+
+## 前置条件
+
+- 已经安装并运行 EMQX 服务器,版本要求 5.7.0 及以上。
+
+## 安装和配置 MCP 桥接插件
+
+1. 从 https://github.com/emqx/emqx_mcp_bridge/releases 下载最新版本的 MCP 桥接插件。
+
+2. 按照 [安装插件](../../extensions/plugin-management.md#通过-cli-安装插件) 的步骤将插件安装到 EMQX 服务器中。
+
+3. 配置插件:
+
+ 使用浏览器访问 http://localhost:18083/#/plugins/ 地址,点击 MCP 桥接插件进入配置页面,这里可以修改插件的监听地址,配置证书等参数。点击保存后配置会被自动应用,无需手动重启插件。
+
+ 注意,如果将监听地址配置为 `https://your-hostname:9909/mcp`,MCP 插件会在指定的端口上启动两个 HTTP 端点:
+ - `/sse`:用于 SSE 协议的 MCP 连接。
+ - `/mcp`:用于 Streamable HTTP 协议的 MCP 连接。
+ 如果希望仅支持 SSE 协议,可以将监听地址配置为 `https://your-hostname:9909/sse`。
+
+ 另外,某些模型或者 AI 智能体可能要求 MCP 服务器必须使用 HTTPS 协议进行连接,这时需要为 MCP 桥接插件配置有效且可信任的 SSL 证书,并且保证 URL 可以公网访问。
+
+ 将 `获取目标 MQTT 客户端 ID 的方式` 配置为 `工具参数`,这样 MCP 客户端就可以在调用时以参数的方式传递设备的 MQTT Client ID,而不必在建立 HTTP 连接的时候,使用 HTTP 头指定一个固定的 Client ID。
+
+ 
+
+## 使用 MCP over MQTT SDK 模拟设备
+
+首先参照 [安装 MCP SDK](../sdks/mcp-sdk-python.md) 文档下载安装 MCP SDK for Python:
+
+```bash
+uv init smart_light
+cd smart_light
+uv add git+https://github.com/emqx/mcp-python-sdk --branch main
+uv add "mcp[cli]"
+source .venv/bin/activate
+```
+
+在项目中添加一个 `smart_light.py` 文件,代码如下:
+
+```python
+# smart_light.py
+import os
+from mcp.server.fastmcp import FastMCP
+
+status = "off"
+
+# Create server
+mcp = FastMCP(
+ "devices/light",
+ log_level="DEBUG",
+ mqtt_server_description="A simple FastMCP server that controls a light device. You can turn the light on and off, and change its brightness.",
+ mqtt_client_id = os.getenv("MQTT_CLIENT_ID"),
+ mqtt_options={
+ "username": "aaa",
+ "host": "localhost",
+ "port": 1883,
+ },
+)
+
+@mcp.tool()
+def change_brightness(level: int) -> str:
+ """Change the brightness of the light, level should be between 0 and 100"""
+ if 0 <= level <= 100:
+ return f"Changed brightness to {level}"
+ return "Invalid brightness level. Please provide a level between 0 and 100."
+
+@mcp.tool()
+def turn_on() -> str:
+ """Turn the light on"""
+ global status
+ if status == "on":
+ return "OK, but the light is already on"
+ status = "on"
+ return "Light turned on"
+
+@mcp.tool()
+def turn_off() -> str:
+ """Turn the light off"""
+ global status
+ if status == "off":
+ return "OK, but the light is already off"
+ status = "off"
+ return "Light turned off"
+```
+
+上面的 Python 代码将会启动一个 MCP over MQTT 协议的 MCP 服务器模拟智能电灯设备,提供 MCP 工具执行开关操作或调节亮度。注意我们指定了服务名为 `devices/light`。
+
+然后在两个终端窗口,使用以下命令, 启动两个 MCP 服务器模拟两个设备,设备 ID 分别为 `abc123` 和 `abc456`:
+
+```bash
+MQTT_CLIENT_ID=abc123 mcp run -t mqtt ./smart_light.py
+```
+
+```bash
+MQTT_CLIENT_ID=abc456 mcp run -t mqtt ./smart_light.py
+```
+
+## 使用 Cherry Studio 客户端测试
+
+这里我们选择支持 MCP 的 Cherry Studio 客户端作为 MCP Client 来测试 EMQX MCP 桥接插件。
+
+1. 参考 [Cherry Studio 文档](https://docs.cherry-ai.com/) 安装 Cherry Studio 客户端。
+
+2. 在 `Model Provider` 页面添加 LLM 提供商,填写大模型的端点地址和 API Key 等信息。
+
+
+
+3. 在 `MCP` 页面,添加 MCP 服务器,填写如下信息。
+
+- Name: `MQTT MCP Tools`
+- Type: 可以使用 SSE 或者 `Streamable HTTP`,这里我们选择 `Streamable HTTP`
+- URL: 使用 MCP 桥接提供的 `Streamable HTTP` 地址:`http://localhost:9909/mcp`
+- Headers: 为了避免太多无关的工具干扰大模型的使用,这里我们仅仅加载 `devices/light` 这一类工具,我们可以添加如下 Header 来过滤工具:
+
+```
+Tool-Types=devices/light
+```
+
+这里 `devices/light` 是上面的 Python 设备端代码中指定的 MCP 服务器名称。
+
+Cherry Studio 支持 HTTP 和 SSE 协议,如果是本地测试,这里我们可以填写 `http://localhost:9909/mcp`。
+
+
+
+4. 创建一个新的助手 “Device Assistant”,并在其中创建一个新的对话主题 “MQTT Device Control”。然后分别设置助手和对话主题的系统提示词:
+
+```
+你是一个设备助手,只能回答与设备访问和控制相关的问题,除此之外的问题,直接回答:“我只是一个设备助手,不会回答其他的问题哦”。
+```
+
+```
+我有如下设备:
+- 客厅的电灯,设备 ID 为:abc123
+- 卧室的电灯,设备 ID 为:abc456
+```
+
+并且在对话设置中,启用 MCP 工具:`MQTT MCP Tools` 服务器。
+
+
+
+5. 现在,我们需要选择一个支持工具调用的模型(例如:`qwen-flash`),然后就可以在对话框中输入指令,测试通过自然语言控制设备的功能了:
+
+```
+打开客厅的灯。
+将卧室的亮度设置为 75%。
+```
+
+我们可以看到,设备助手能够通过系统提示词找到指定的设备 ID,然后调用 MCP 工具控制对应的设备:
+
+
diff --git a/zh_CN/emqx-ai/multimedia-ai/quick-start.md b/zh_CN/emqx-ai/multimedia-ai/quick-start.md
new file mode 100644
index 000000000..939dc44cd
--- /dev/null
+++ b/zh_CN/emqx-ai/multimedia-ai/quick-start.md
@@ -0,0 +1,65 @@
+# 快速开始
+
+本指南介绍如何使用 Docker Compose 部署一个基于 EMQX 多媒体服务器的 AI Agent 演示项目,该项目会在浏览器页面上展示一个可实时语音交互的智能玩偶形象。
+
+该项目主要展示以下技术要点:
+
+- **实时语音流传输 + 实时 ASR + LLM + 实时 TTS:** 该项目使用 WebRTC 传输语音流,将前端的语音流实时推送给 ASR 模型流式转为文字,再使用 LLM 流式生成文字回复,最后使用 TTS 将文字回复流式转为语音,EMQX 多媒体服务会使用 WebRTC 流式推送给前端。
+- **MCP over MQTT:** 前端使用 [MCP over MQTT TypeScript SDK](../sdks/mcp-sdk-typescript.md) 提供了拍照、表情切换、音量调节等 MCP 工具,AI Agent 无需了解前端(或者设备)的具体实现细节和调用方式,实现了与前端逻辑的解耦。
+- **MQTT 实时消息通信:** 前端页面可以通过 MQTT 直接与 AI Agent 通信,以实现拍打、抚摸玩偶头像等交互功能。
+
+## 下载 EMQX 多媒体代理项目代码
+
+```bash
+git clone https://github.com/emqx/emqx-multimedia-proxy
+cd emqx-multimedia-proxy
+```
+
+## 准备环境变量
+
+创建 `docker/.env` 文件,内容如下:
+
+```
+DASHSCOPE_API_KEY='sk-xxxxx'
+```
+
+其中,`DASHSCOPE_API_KEY` 是您在阿里云大模型服务平台上创建的 API KEY,请参考 [获取阿里云大模型 API Key](https://help.aliyun.com/zh/model-studio/get-api-key?) 了解如何获取该密钥。
+
+## 通过 Docker Compose 启动项目
+
+```bash
+make compose-run
+```
+
+服务启动后,Demo 页面的默认访问地址为:`http://localhost:4000/index.html`。
+
+## 项目组成部分
+
+上面的 `make compose-run` 命令将会启动三个服务实例:一个多媒体演示项目,一个 EMQX 服务,以及一个 PostgreSQL 数据库实例。
+
+### 多媒体演示项目实例
+
+多媒体演示项目实例是从 `emqx/media-server:latest` 镜像拉取并启动的,其中包含了以下三个组件:
+1. EMQX 多媒体服务器:负责处理来自设备的音视频数据,集成阿里云模型平台提供的 ASR(自动语音识别)、TTS(文本转语音)等功能,并与 AI Agent 进行通信。
+2. AI Agent:通过 STDIO 或 WebSocket 接受多媒体服务器传递的 ASR 结果(文本),包含了 AI 应用的核心业务逻辑,调用 LLM(大语言模型)处理文本自然语言,并调用多媒体服务提供的 API 将文字转为音频流推送给前端页面。
+3. Demo 前端页面:展示语音玩偶形象,使用 WebRTC 技术与多媒体服务器点对点音频交互,提供 MCP 工具实现拍照、表情切换、音量调节等功能。
+
+代码仓库地址:
+- [EMQX 多媒体服务器](https://github.com/emqx/emqx-multimedia-proxy)
+- [AI Agent 和 Demo 前端页面](https://github.com/emqx/mcp-ai-companion-demo)
+
+### EMQX 服务实例
+
+作为 MQTT 消息中间件,负责多媒体服务器与前端页面之间的消息传递和信令交换。
+
+### PostgreSQL 数据库实例
+
+作为多媒体服务的后端数据库,未来将会用于存储用户数据和会话信息,但演示程序目前尚未使用。
+
+:::tip 提示
+为避免访问出现权限问题,请使用 Chrome 浏览器访问 Demo 页面。由于浏览器对 WebRTC 协议的安全策略,默认无法访问非 TLS 站点以及自签名证书的 TLS 站点,所以需要在 chrome://flags/#unsafely-treat-insecure-origin-as-secure 中将 `http://localhost:4000` 和 `https://localhost:443` 添加为安全站点。
+:::
+
+:::tip 注意
+若要使用拍照功能,需要将多媒体服务器部署在可以公网访问的环境中。这是因为拍照功能的工作过程是,前端首先将图片上传到多媒体服务器,多媒体服务器随后会为视觉模型提供一个该图片文件的下载地址,模型分析该图片并返回结果。所以在本地部署测试的情况下,视觉模型可能无法访问该地址导致图像分析失败。
+:::
diff --git a/zh_CN/emqx-ai/overview.md b/zh_CN/emqx-ai/overview.md
index a6377ed77..31852c60f 100644
--- a/zh_CN/emqx-ai/overview.md
+++ b/zh_CN/emqx-ai/overview.md
@@ -1,10 +1,122 @@
-# EMQX AI
+# EMQX 助力构建智能物联网系统
-EMQX AI 是 EMQX 在人工智能领域的创新实践,致力于为 AI 应用提供高效、可靠的通信基础设施,主要包括以下两个方向:
+## 背景
-- **消息通信:** 通过 MCP over MQTT 协议,EMQX 为 AI 应用提供了轻量、低延迟的工具调用和消息传递方式,满足 AI 应用在模型推理、实时反馈、智能化数据采集和智能化控制等场景下的通信需求。详见 [MCP over MQTT](./mcp-over-mqtt/overview.md)。
+随着大模型技术的迅猛演进,AI 正在深入重塑各行各业,而物联网行业也迎来前所未有的变革。过去的智能硬件大多是围绕固定功能设计,更多扮演“被动执行者”。但如今,设备正逐步具备感知、理解、交互与行动的综合能力,从单一的工具演化为真正具备自主性与智能判断的智能体。这一变化正在推动众多场景发生颠覆性的升级。
-- **多媒体流传输:** 通过基于 WebRTC 的多媒体服务器,EMQX 为 AI 应用提供了实时音视频流的传输能力,适用于智能语音、视频分析、图像理解、远程协作等场景。详见[多媒体服务器](./multimedia-ai/overview.md)。
+在情感陪伴领域,曾经只会播放声音或做简单动作的电子玩具,正演变为能够识别情绪、理解语境并提供暖心反馈的智能伙伴;在智能家居市场,智能单品逐渐让位于能够全屋协同的智能生态,用户期待通过自然语言完成对家中设备的无缝控制;在机器人行业,具身智能机器人(无论是家用服务机器人、工业机器人还是人形机器人)都在快速发展,它们需要实时观察环境、理解意图并即时行动;在汽车领域,智能汽车已经成为移动的智能空间,车载 AI 助手能够处理复杂的交通场景,并以连续自然的语音交互提升驾驶体验。
-以上两个方案相结合,为 AI 应用构建了坚实的通信底座,助力开发者快速搭建智能化、实时化的 AI 应用。
+
+## 实时、准确和丰富的上下文感知与多媒体交互是 AI 硬件的核心
+
+尽管大模型具备强大的推理和生成能力,但其表现依赖于所提供的上下文质量。当系统无法准确理解当下情境、大环境变化或用户真实需求时,模型可能出现幻觉、答非所问等问题。人类在缺乏信息时也会“盲人摸象”,但掌握完整上下文后往往能做出准确判断。对于智能硬件而言,让 AI “理解真实世界”是提升交互稳定性与可信度的关键。因此,一个可靠的 AI 智能体需要具备以下三类核心能力:
+
+1. 多源数据:让 AI 具备真实世界的理解
+
+来自不同来源的数据构成 AI 的“世界模型”:
+
+- 环境数据:温度、湿度、亮度、重力等物理信息,为系统提供实时状态;
+- 云端知识:地图、天气、交通、充电桩等信息,让设备具备更广阔的认知;
+- 第三方上下文:内容服务、知识库等,使设备能理解更复杂的问题与需求。
+
+数据源越丰富,系统越能精准定义 “现在正在发生什么” 与 “用户真正需要什么”。
+
+2. 实时事件感知:让 AI 在毫秒级理解变化
+
+事件是构建上下文的锚点,是驱动 LLM/VLM 的关键入口:
+
+- 环境突变:如房间亮度急剧变化
+- 状态变化:例如玩具突然倾倒
+- 特殊场景:汽车锁车后,后座压力传感器异常
+
+能否在毫秒级捕捉事件,决定了系统智能反应的快与准。
+
+3. 多媒体交互:让 AI 具备自然的人机沟通能力
+
+多模态交互是从“语音助手”走向“智能体验”的关键飞跃:
+
+- 语音:情感化表达、自然语调、多语言支持
+- 视频:面部表情、场景识别与实时视觉反馈
+- 控制能力:通过语音 + 视觉理解结合,实现更智能的场景驱动
+
+## 构建智能硬件的六个要素
+
+我们从输入和输出两个方面,通过六个角度定义出构建合格的智能硬件所必需有的要素。
+
+### 输入能力
+
+- 可感知:智能体可以通过各种方式(传感器)来感知这个物理世界:通过温度传感器了解环境温度,使用定位知道自己所处位置,利用重力加速感应知道自己的运行状态等。
+- 听得见:通过麦克风采集环境声音和用户语音,实现噪声抑制、回声消除,然后通过支持多种语言的语音识别技术,让设备能够「听见」用户的自然语言。
+- 看得见:通过摄像头采集视觉信息,实现图像识别、目标检测、人脸识别和手势识别,让设备能够「看懂」周围环境和用户行为。
+
+### 输出能力
+
+- 能理解:通过集成 LLM/VLM 模型,实现语义理解、情感识别和上下文记忆,让设备能够理解用户意图并保持对话连贯性。
+- 说得出:通过扬声器输出高质量语音,支持多音色合成、情感化表达和情境化语调,让设备能够自然流畅地与用户交流。
+- 能行动:通过 MCP 协议控制各种设备功能,实现音量调节、摄像头开启、多设备协调等操作,让设备能够执行用户指令并做出相应行动。
+
+## 以 EMQX 和 RTC 服务为核心的智能物联网架构
+
+
+
+EMQX 端到端解决方案采用分层架构,将设备层、通信层、处理层与应用层整合为一个流畅协作的系统。从传感器采集、边缘处理、实时通信(MQTT + WebRTC)、到云端大模型,形成闭环的“感知 → 理解 → 行动”链路。这一架构既适用于轻量设备,也能支撑复杂场景如机器人与车载系统。
+
+### 可感知:EMQX 提供构建 AI 世界模型所需的 “实时上下文”
+
+感知是所有智能行为的前提。人类的输入主要来自视觉、听觉与触觉,真正用于表达的语言只占生活中 6%〜10% 的时间。对于 AI 智能体而言,如果缺乏实时的世界感知,它就只是一段算法,而不是生活在物理世界中的实体。
+
+EMQX 为设备提供完善的“实时上下文基础设施”:
+
+- 毫秒级数据链路:从设备到云端的消息转发延迟仅毫秒级,确保每个事件都能即时处理;
+- 全场景 SDK:从低功耗 MCU 到 Linux 设备,提供统一接入方式,简化传感器接入;
+- 海量设备管理能力:支持海量设备并发连接、消息处理与状态追踪,适用于从玩具到车载的各种大规模场景。
+
+#### 扩展阅读
+
+- [使用 EMQX 构建感知 -> 控制反馈能力](rtc-services/volcengine-rtc/scenarios/device-triggered-voice.md)
+
+### 听得到、看得见、说得出:音、视频流数据接入与处理
+
+WebRTC 是实时音视频交互领域的核心技术,其低延迟、高兼容性特性使其成为智能硬件进行多模态交互的首选方案。
+
+- 语音输入:让设备真正“听懂”用户。高质量麦克风配合智能降噪、回声消除,使系统能够在复杂环境中保持语音的清晰度。实时 ASR 技术将语音转为文字,支持多语言识别,为后续语义理解打下基础。
+
+- 视觉输入:让设备拥有“眼睛”。摄像头提供高清画面,结合目标识别、人脸识别和动作理解,让设备可以“看见”用户的状态与动作。手势交互让体验更加自然,无需触碰即可操作。
+
+- 语音输出:让沟通更加自然。现代 TTS 提供多音色、多情绪合成能力,可根据场景自动调整语调与节奏,让机器的表达更加拟人化与亲切。自然语音反馈让设备真正成为能“沟通”的智能伙伴。
+
+#### 扩展阅读:
+
+- [基于火山引擎构建音视频接入](rtc-services/volcengine-rtc/overview.md)
+
+### 能理解:接入 LLM / VLM
+
+LLM 负责语言理解与生成,VLM 负责视觉与语言的融合。它们让智能设备不仅能“听到、看到”,还能真正“理解”。相比传统规则引擎,现代大模型具备强大的推理、记忆与泛化能力,可适用于高度复杂与开放式的交互场景。
+
+扩展阅读:
+
+- [阿里千问模型](https://www.aliyun.com/product/tongyi)
+- [火山云豆包大模型](https://www.volcengine.com/product/doubao)
+
+### 能行动:MCP 设备控制 - AI 与设备的桥梁
+
+
+
+MCP(Model Context Protocol)让 AI 能够自然、规范、动态地调用设备能力。
+
+- MCP Server:部署在设备端,负责注册设备能力,如摄像头控制、音量控制、机械结构动作指令等;
+- MCP Client:运行在云端或边缘节点,将 AI 的决策转换为可执行的设备控制命令;
+- MCP Hosts:嵌入 AI 应用,负责将用户意图转换为工具调用,并与设备进行双向协作。
+
+通过 MCP,AI 获得了动作能力,设备也获得了统一的控制接口,使多设备协同与复杂场景控制成为可能。
+
+#### 扩展阅读:
+
+- [MCP over MQTT 协议概述](./mcp-over-mqtt/overview.md)
+
+#### 智能体交互典型场景
+
+- 纯语音对话:以语音为唯一输入,基于 WebRTC 即可实现实时、高品质互动。
+- 语音 / 视频控制设备:通过麦克风或摄像头操作设备功能,需要集成 WebRTC 与 MQTT 以确保稳定控制链路。
+- 感知驱动的控制与多媒体交互:设备从传感器获取事件,再由 AI 决策,结合语音与视频输出,实现沉浸式的智能体验。与第二种场景类似,也需要集成 WebRTC 与 MQTT。
diff --git a/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png b/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png
new file mode 100644
index 000000000..3051c2754
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/diagram-speech-to-speech.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png b/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png
new file mode 100644
index 000000000..26ac08407
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/gpt-realtime/assets/traditional-models-pipeline.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/gpt-realtime/overview.md b/zh_CN/emqx-ai/rtc-services/gpt-realtime/overview.md
new file mode 100644
index 000000000..99e2fddd4
--- /dev/null
+++ b/zh_CN/emqx-ai/rtc-services/gpt-realtime/overview.md
@@ -0,0 +1,21 @@
+# GPT-Realtime 概述
+
+GPT-Realtime 是 OpenAI 开发的能够实时接收语音输入并生成语音输出的多模态实时模型。该模型使用语音数据集进行训练,使用上更加贴近人类的语音交流习惯。
+
+该模型具有以下特点:
+- **协议上:** 支持 WebRTC, WebSocket 和 SIP 协议,实时处理文字和语音输入并流式给出回答。
+- **对话体验上:** 延迟低、语音合成自然流畅、对话中可以处理多次被打断的情况,更加贴近人类对话体验。
+- **函数调用和工具能力:** 支持工具调用和 MCP 工具。
+- **开发体验上:** 在 WebRTC 协议方面,支持两种级别的集成方式:Voice Agents SDK(封装更高层次的能力,开箱即用)和 WebRTC SDK(更底层的音视频传输能力,可自定义程度高)。
+
+## 其他串联多种类型模型的 RTC 实时语音方案
+
+在传统的 RTC 实时语音方案中,通常需要将多种类型的模型串联起来完成语音交互功能:首先将语音转录为文字,再输入给大模型处理,最后将大模型的输出合成为语音推送给用户。
+
+
+
+## GPT-Realtime 将多种能力集成在单一模型中
+
+GPT-Realtime 模型不再需要串联多种类型的模型,而是将整个过程都在单个模型内部完成,因此它的端到端延迟非常低。
+
+
diff --git a/zh_CN/emqx-ai/rtc-services/gpt-realtime/quick-start.md b/zh_CN/emqx-ai/rtc-services/gpt-realtime/quick-start.md
new file mode 100644
index 000000000..f3c16a9bb
--- /dev/null
+++ b/zh_CN/emqx-ai/rtc-services/gpt-realtime/quick-start.md
@@ -0,0 +1,167 @@
+# 使用 EMQX + GPT-Realtime 构建实时语音智能体
+
+本指南介绍如何使用 GPT-Realtime 模型和 EMQX 快速构建一个实时语音智能体应用。
+
+## 获取临时 API Key
+
+要在浏览器中使用原生 WebRTC 的方式连接 GPT-Realtime,我们需要先获取一个临时的 API Key。我们可以通过 OpenAI 的 REST API 获取该 Key:
+
+```bash
+export OPENAI_API_KEY="sk-xxxxxx"
+curl -s -X POST https://api.openai.com/v1/realtime/client_secrets -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"session": {"type": "realtime", "model": "gpt-realtime"}}' | jq .value
+```
+
+## 实现实时语音聊天
+
+以下代码展示了如何使用原生 WebRTC 的方式连接 GPT-Realtime 模型,实现实时语音聊天功能:
+
+```javascript
+// Put the obtained ephemeral key here
+const EPHEMERAL_KEY = "ek_xxxxxx";
+
+// Create a peer connection
+const pc = new RTCPeerConnection();
+
+// Set up to play remote audio from the model
+audioElement.current = document.createElement("audio");
+audioElement.current.autoplay = true;
+pc.ontrack = (e) => (audioElement.current.srcObject = e.streams[0]);
+
+// Add local audio track for microphone input in the browser
+const ms = await navigator.mediaDevices.getUserMedia({
+ audio: true,
+});
+pc.addTrack(ms.getTracks()[0]);
+
+// Set up data channel for sending and receiving events
+const dc = pc.createDataChannel("oai-events");
+
+// Start the session using the Session Description Protocol (SDP)
+const offer = await pc.createOffer();
+await pc.setLocalDescription(offer);
+
+const sdpResponse = await fetch("https://api.openai.com/v1/realtime/calls", {
+ method: "POST",
+ body: offer.sdp,
+ headers: {
+ Authorization: `Bearer ${EPHEMERAL_KEY}`,
+ "Content-Type": "application/sdp",
+ },
+});
+
+const answer = {
+ type: "answer",
+ sdp: await sdpResponse.text(),
+};
+await pc.setRemoteDescription(answer);
+
+// Listen for server events
+dc.addEventListener("message", (e) => {
+ const event = JSON.parse(e.data);
+ console.log("Received event:", event);
+});
+```
+
+上述代码除了创建 WebRTC 语音通道之外,还创建了一个 Data Channel 用于发送和接收 GPT-Realtime 模型的事件。这里我们将所有接收到的事件打印到了控制台,如果测试过程中出现收不到语音等问题,可以在控制台查看具体的错误信息。
+
+## 使用 MCP 控制设备
+
+### 1. 安装、配置 MCP 桥接插件,并启动 MCP Server 以模拟设备
+
+首先我们需要启动 EMQX 并安装 MCP 桥接插件,并启动一个 MCP Server 来模拟智能电灯。具体步骤请参考[使用 EMQX MCP 桥接访问物联网设备](../../mcp-bridge/quick-start.md)。
+
+注意必须在公网环境中启动 EMQX,并且给 MCP 桥接插件配置有效的 SSL 证书,以便 GPT-Realtime 可以通过 HTTPS 访问 MCP 服务。
+
+### 2. 修改前端代码以使用 MCP 工具
+
+为了使用 MCP 工具,我们需要增加一个处理 GPT-Realtime 事件的函数 `handle_event()`。
+
+```javascript
+// Listen for server events
+dc.addEventListener("message", (e) => {
+ const event = JSON.parse(e.data);
+ handle_event(event);
+});
+```
+
+在该函数中,我们需要处理 session.created 事件,以便在会话创建时发送 session.update 事件来启用 MCP 工具。MCP 服务器的地址填写 `https://your-emqx-host:port/mcp`:
+
+```javascript
+function handle_event(event) {
+ if (event.type === "session.created") {
+ // Send client events
+ const session_update_event = {
+ type: "session.update",
+ session: {
+ type: "realtime",
+ model: "gpt-realtime",
+ // can be set to "text"
+ output_modalities: ["audio"],
+ tools: [
+ {
+ type: "mcp",
+ server_label: "mqtt_mcp_bridge",
+ server_description: "EMQX MCP over MQTT Bridge",
+ server_url: "https://your-emqx-host:port/mcp",
+ require_approval: "never",
+ }
+ ],
+ tool_choice: "auto",
+ // You can still set direct session fields; these override prompt fields if they overlap:
+ instructions: "I have a smart light and its client ID is abc123"
+ }
+ };
+ dc.send(JSON.stringify(session_update_event));
+ } else if (event.type === "response.done") {
+ console.log("Received response done:", event);
+ } else {
+ console.log("Received event:", event);
+ }
+}
+```
+
+现在,我们在浏览器中访问前端页面与 GPT-Realtime 进行语音对话时,模型就可以通过 MCP 工具访问和控制物联网设备了。
+
+::: tip 注意
+GPT-Realtime 仅支持通过 HTTPS 访问 MCP 服务器,请确保:
+- MCP 插件安装了有效的、非自签名的 SSL 证书
+- URL 必须使用域名而不是 IP 地址,并且确保可以公网访问。
+:::
+
+::: tip 注意
+GPT-Realtime 需要使用 Streamable HTTP 来访问 MCP 服务器,所以要访问 EMQX MCP 桥接插件的 `/mcp` 路径,而不是 `/sse` 路径。
+:::
+
+## 给模型发送消息
+
+前面的代码中,我们使用系统提示词提前告诉了模型我们设备的 Client ID:
+
+```javascript
+const session_update_event = {
+ type: "session.update",
+ session: {
+ ...
+ instructions: "I have a smart light and its client ID is abc123"
+ }
+};
+```
+
+GPT-Realtime 还支持在对话过程中,通过 WebRTC Data Channel 给模型发送消息,给模型添加上下文信息:
+
+```javascript
+// Send client events
+const event = {
+ type: "conversation.item.create",
+ item: {
+ type: "message",
+ role: "user",
+ content: [
+ {
+ type: "input_text",
+ text: "I have a smart light and its client ID is abc123",
+ },
+ ],
+ },
+};
+dc.send(JSON.stringify(event));
+```
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/api.md b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/api.md
new file mode 100644
index 000000000..2b85ea45e
--- /dev/null
+++ b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/api.md
@@ -0,0 +1,590 @@
+# API 参考文档
+
+本文档介绍火山引擎实时对话式 AI 的核心 API,包括 StartVoiceChat、UpdateVoiceChat、StopVoiceChat 及相关配置参数。
+
+---
+
+## StartVoiceChat
+
+启动语音会话,返回 RTC 连接凭证。
+
+**请求地址**:`POST https://rtc.volcengineapi.com?Action=StartVoiceChat&Version=2024-12-01`
+
+**请求头**:需要使用 AccessKey 进行签名,参考 [认证代理服务](./installation-and-testing.md#认证代理服务)。
+
+### 请求参数
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `AppId` | string | 是 | RTC 应用 ID |
+| `RoomId` | string | 是 | 房间 ID |
+| `TaskId` | string | 是 | 任务 ID,用于标识会话 |
+| `AgentConfig` | object | 是 | 智能体配置 |
+| `Config` | object | 是 | 会话配置,包含 ASR、TTS、LLM 等参数 |
+
+### AgentConfig
+
+智能体配置:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `TargetUserId` | string[] | 是 | 目标用户 ID 列表 |
+| `UserId` | string | 是 | 智能体用户 ID |
+| `WelcomeMessage` | string | 否 | 欢迎语 |
+| `EnableConversationStateCallback` | boolean | 否 | 启用会话状态回调 |
+| `AnsMode` | number | 否 | 降噪模式(0-3) |
+| `VoicePrint` | object | 否 | 声纹识别配置 |
+
+**VoicePrint 配置**:
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `Mode` | number | 声纹识别模式(0: 关闭, 1: 开启) |
+| `IdList` | string[] | 声纹 ID 列表 |
+
+### Config
+
+会话配置,包含以下子配置:
+
+```json
+{
+ "ASRConfig": { ... },
+ "TTSConfig": { ... },
+ "LLMConfig": { ... },
+ "InterruptMode": 0
+}
+```
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `ASRConfig` | object | 语音识别配置 |
+| `TTSConfig` | object | 语音合成配置 |
+| `LLMConfig` | object | 大模型配置 |
+| `InterruptMode` | number | 打断模式(0: 语义打断, 1: 手动打断) |
+
+### 响应
+
+```json
+{
+ "ResponseMetadata": {
+ "RequestId": "20250104123456789abcdef01234567",
+ "Action": "StartVoiceChat",
+ "Version": "2024-12-01",
+ "Service": "rtc",
+ "Region": "cn-north-1"
+ },
+ "Result": {
+ "AppId": "your-app-id",
+ "RoomId": "room-uuid",
+ "UserId": "user-uuid",
+ "Token": "rtc-token..."
+ }
+}
+```
+
+| 字段 | 说明 |
+|------|------|
+| `Result.AppId` | RTC 应用 ID |
+| `Result.RoomId` | RTC 房间 ID |
+| `Result.UserId` | RTC 用户 ID |
+| `Result.Token` | RTC 访问令牌(24 小时有效) |
+
+官方文档:[StartVoiceChat](https://www.volcengine.com/docs/6348/1404673)
+
+---
+
+## StopVoiceChat
+
+停止语音会话,释放资源。
+
+**请求地址**:`POST https://rtc.volcengineapi.com?Action=StopVoiceChat&Version=2024-12-01`
+
+### 请求参数
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `AppId` | string | 是 | RTC 应用 ID |
+| `RoomId` | string | 是 | 房间 ID |
+| `TaskId` | string | 是 | 任务 ID |
+
+### 响应
+
+```json
+{
+ "ResponseMetadata": {
+ "RequestId": "20250104123456789abcdef01234567",
+ "Action": "StopVoiceChat",
+ "Version": "2024-12-01"
+ },
+ "Result": {}
+}
+```
+
+官方文档:[StopVoiceChat](https://www.volcengine.com/docs/6348/1404672)
+
+---
+
+## UpdateVoiceChat
+
+更新进行中的语音会话,支持打断、Function calling、自定义播报等操作。
+
+**请求地址**:`POST https://rtc.volcengineapi.com?Action=UpdateVoiceChat&Version=2024-12-01`
+
+### 请求参数
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `AppId` | string | 是 | RTC 应用 ID |
+| `RoomId` | string | 是 | 房间 ID |
+| `TaskId` | string | 是 | 任务 ID |
+| `Command` | string | 是 | 操作命令 |
+| `Message` | string | 否 | 播报内容(最长 200 字符) |
+| `InterruptMode` | number | 否 | 播报优先级 |
+
+### Command 命令类型
+
+| Command | 说明 |
+|---------|------|
+| `Interrupt` | 打断当前智能体输出 |
+| `ExternalTextToSpeech` | 自定义文本转语音播报 |
+| `FunctionCallResult` | 返回 Function calling 结果 |
+
+### InterruptMode 优先级
+
+用于 `ExternalTextToSpeech` 命令时指定播报优先级:
+
+| 值 | 说明 |
+|----|------|
+| 1 | 高优先级:终止当前交互,立即播放 |
+| 2 | 中优先级:等待当前交互结束后播放 |
+| 3 | 低优先级:如果正在交互则丢弃 |
+
+### 使用示例
+
+**打断智能体**:
+
+```json
+{
+ "AppId": "your-app-id",
+ "RoomId": "room-uuid",
+ "TaskId": "task-id",
+ "Command": "Interrupt"
+}
+```
+
+**自定义播报**:
+
+```json
+{
+ "AppId": "your-app-id",
+ "RoomId": "room-uuid",
+ "TaskId": "task-id",
+ "Command": "ExternalTextToSpeech",
+ "Message": "您有一条新消息",
+ "InterruptMode": 1
+}
+```
+
+### 响应
+
+```json
+{
+ "ResponseMetadata": {
+ "RequestId": "20250104123456789abcdef01234567",
+ "Action": "UpdateVoiceChat",
+ "Version": "2024-12-01"
+ },
+ "Result": {}
+}
+```
+
+官方文档:[UpdateVoiceChat](https://www.volcengine.com/docs/6348/1404671)
+
+---
+
+## ASRConfig
+
+语音识别配置:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `Provider` | string | 是 | 服务提供商,固定 `volcano` |
+| `ProviderParams` | object | 是 | 提供商参数 |
+| `VADConfig` | object | 否 | 语音活动检测配置 |
+| `VolumeGain` | number | 否 | 音量增益(0.0-1.0),默认 `0.5` |
+| `TurnDetectionMode` | number | 否 | 轮次检测模式 |
+| `InterruptConfig` | object | 否 | 打断配置 |
+
+### ProviderParams
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `AppId` | string | ASR 应用 ID |
+| `Mode` | string | 识别模式:`smallmodel`(小模型)、`bigmodel`(大模型) |
+| `Cluster` | string | 服务集群,默认 `volcengine_streaming_common` |
+| `context` | string | 热词上下文(JSON 格式) |
+| `boosting_table_id` | string | 热词表 ID |
+| `correct_table_id` | string | 纠错表 ID |
+
+### VADConfig
+
+语音活动检测配置:
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `SilenceTime` | number | 静音判定时长(毫秒),默认 `600` |
+| `SpeechTime` | number | 语音判定时长(毫秒) |
+| `PrefixTime` | number | 前缀时长(毫秒) |
+| `SuffixTime` | number | 后缀时长(毫秒) |
+| `Sensitivity` | number | 灵敏度 |
+| `AIVAD` | boolean | 是否启用 AI VAD |
+
+### InterruptConfig
+
+打断配置:
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `InterruptSpeechDuration` | number | 打断语音时长(毫秒),默认 `400` |
+| `InterruptKeywords` | string[] | 语义打断关键词列表 |
+
+**示例配置**:
+
+```json
+{
+ "Provider": "volcano",
+ "ProviderParams": {
+ "AppId": "your-asr-app-id",
+ "Mode": "smallmodel",
+ "Cluster": "volcengine_streaming_common"
+ },
+ "VADConfig": {
+ "SilenceTime": 600
+ },
+ "VolumeGain": 0.5,
+ "TurnDetectionMode": 0,
+ "InterruptConfig": {
+ "InterruptSpeechDuration": 400,
+ "InterruptKeywords": ["停", "暂停", "等一下", "stop", "wait"]
+ }
+}
+```
+
+---
+
+## TTSConfig
+
+语音合成配置:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `Provider` | string | 是 | 服务提供商,固定 `volcano` |
+| `ProviderParams` | object | 是 | 提供商参数 |
+| `IgnoreBracketText` | number[] | 否 | 忽略的括号类型 |
+
+### ProviderParams
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `app` | object | 应用配置 |
+| `audio` | object | 音频配置 |
+| `ResourceId` | string | TTS 资源 ID |
+| `Additions` | object | 附加配置 |
+
+**app 配置**:
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `appid` | string | TTS 应用 ID |
+| `token` | string | TTS 应用 Token |
+| `cluster` | string | 服务集群,默认 `volcano_tts` |
+
+**audio 配置**:
+
+| 参数 | 类型 | 说明 | 范围 |
+|------|------|------|------|
+| `voice_type` | string | 音色类型 | 见下方音色列表 |
+| `speed_ratio` | number | 语速比例 | 0.5-2.0,默认 `1.0` |
+| `pitch_ratio` | number | 音调比例 | 0.5-2.0,默认 `1.0` |
+| `volume_ratio` | number | 音量比例 | 0.5-2.0,默认 `1.0` |
+| `emotion` | string | 情感类型 | `happy`、`sad`、`angry`、`neutral` |
+| `emotion_strength` | number | 情感强度 | 0.0-1.0,默认 `0.8` |
+
+**常用音色**:
+
+| 音色 ID | 说明 |
+|---------|------|
+| `BV033_streaming` | 女声,温柔 |
+| `BV001_streaming` | 男声,磁性 |
+| `BV700_streaming` | 女声,甜美 |
+| `BV406_streaming` | 男声,沉稳 |
+
+更多音色参考:[火山引擎 TTS 音色列表](https://www.volcengine.com/docs/6561)
+
+**示例配置**:
+
+```json
+{
+ "Provider": "volcano",
+ "ProviderParams": {
+ "app": {
+ "appid": "your-tts-app-id",
+ "token": "your-tts-token",
+ "cluster": "volcano_tts"
+ },
+ "audio": {
+ "voice_type": "BV033_streaming",
+ "speed_ratio": 1.2,
+ "pitch_ratio": 1.1,
+ "volume_ratio": 1.0,
+ "emotion": "happy",
+ "emotion_strength": 0.8
+ },
+ "ResourceId": "your-resource-id"
+ }
+}
+```
+
+---
+
+## LLMConfig
+
+大模型配置:
+
+| 参数 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `Mode` | string | 是 | 模式:`ArkV3`(方舟)或 `CustomLLM`(自定义) |
+| `Url` | string | CustomLLM 必填 | CustomLLM 回调地址 |
+| `APIKey` | string | 否 | API 认证密钥 |
+| `EndPointId` | string | ArkV3 必填 | 方舟模型端点 ID |
+| `ModelName` | string | 否 | 模型名称 |
+| `SystemMessages` | string[] | 否 | 系统提示词列表 |
+| `UserPrompts` | object[] | 否 | 预设对话历史 |
+| `Temperature` | number | 否 | 采样温度(0.0-1.0),默认 `0.5` |
+| `TopP` | number | 否 | 核采样概率(0.0-1.0),默认 `0.9` |
+| `MaxTokens` | number | 否 | 最大生成 token 数,默认 `256` |
+| `HistoryLength` | number | 否 | 保留的历史轮数,默认 `15` |
+| `EnableRoundId` | boolean | 否 | 启用轮次 ID |
+| `VisionConfig` | object | 否 | 视觉理解配置 |
+| `Custom` | string | 否 | 自定义参数(JSON 字符串),透传给 CustomLLM |
+
+### VisionConfig
+
+视觉理解配置:
+
+| 参数 | 类型 | 说明 |
+|------|------|------|
+| `Enable` | boolean | 是否启用视觉理解 |
+| `SnapshotConfig` | object | 截图配置 |
+
+### UserPrompts
+
+预设对话历史,用于引导对话风格:
+
+```json
+[
+ { "Role": "assistant", "Content": "你好!有什么可以帮助你的?" },
+ { "Role": "user", "Content": "你好" }
+]
+```
+
+**CustomLLM 模式示例**:
+
+```json
+{
+ "Mode": "CustomLLM",
+ "Url": "https://your-server.com/chat-stream",
+ "APIKey": "your-api-key",
+ "ModelName": "qwen-flash",
+ "Temperature": 0.5,
+ "TopP": 0.9,
+ "MaxTokens": 256,
+ "HistoryLength": 15,
+ "EnableRoundId": true,
+ "VisionConfig": {
+ "Enable": false
+ },
+ "UserPrompts": [
+ { "Role": "assistant", "Content": "嗨~我是助手,很高兴见到你!" }
+ ]
+}
+```
+
+**ArkV3 模式示例**:
+
+```json
+{
+ "Mode": "ArkV3",
+ "EndPointId": "your-endpoint-id",
+ "Temperature": 0.7,
+ "MaxTokens": 512
+}
+```
+
+---
+
+## CustomLLM 回调
+
+使用 CustomLLM 模式时,火山引擎会将用户语音识别结果回调到自定义服务。
+
+### 回调流程
+
+```
+用户语音 → 火山引擎 ASR → CustomLLM 服务 → 火山引擎 TTS → 用户
+```
+
+### 请求格式
+
+火山引擎发送到 CustomLLM 服务的请求:
+
+```http
+POST /chat-stream HTTP/1.1
+Authorization: Bearer YOUR_API_KEY
+Content-Type: application/json
+
+{
+ "messages": [
+ {"role": "system", "content": "你是一个智能助手"},
+ {"role": "user", "content": "你好"}
+ ],
+ "stream": true,
+ "temperature": 0.7,
+ "max_tokens": 256,
+ "device_id": "custom-device-id"
+}
+```
+
+**请求字段**:
+
+| 字段 | 说明 |
+|------|------|
+| `messages` | 对话历史,OpenAI 格式 |
+| `stream` | 固定 `true`,流式响应 |
+| `temperature` | 采样温度 |
+| `max_tokens` | 最大生成长度 |
+| `device_id` | 自定义参数,从 `LLMConfig.Custom` 透传 |
+
+### 响应格式
+
+响应需遵循 OpenAI SSE 格式:
+
+```
+data: {"id":"resp-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}],"model":"qwen-flash","created":1704355200}
+
+data: {"id":"resp-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}],"model":"qwen-flash","created":1704355200}
+
+data: {"id":"resp-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":"stop"}],"model":"qwen-flash","created":1704355200}
+
+data: [DONE]
+```
+
+**响应要点**:
+
+- 必须返回 SSE 流式响应
+- Content-Type: `text/event-stream`
+- 每行以 `data: ` 开头
+- 最后一行为 `data: [DONE]`
+
+官方文档:[CustomLLM 接入](https://www.volcengine.com/docs/6348/1399966)
+
+---
+
+## RTC Token
+
+客户端加入 RTC 房间需要 Token。Token 由服务端使用 AppKey 生成。
+
+### Token 结构
+
+```
+Token = Version + AppId + Base64(Message + Signature)
+```
+
+- **Version**:固定值 `001`
+- **AppId**:24 位应用标识符
+- **Message**:二进制编码的负载(RoomId、UserId、过期时间、权限等)
+- **Signature**:使用 AppKey 进行 HMAC-SHA256 签名
+
+### Token 权限
+
+| 权限 | 说明 |
+|------|------|
+| `PrivPublishStream` | 发布音视频流 |
+| `PrivSubscribeStream` | 订阅音视频流 |
+
+### 有效期
+
+默认 24 小时(86400 秒)。过期后需重新生成。
+
+### 生成示例
+
+```typescript
+import { AccessToken } from './rtctoken'
+
+const token = new AccessToken(appId, appKey, roomId, userId)
+const expireAt = Math.floor(Date.now() / 1000) + 24 * 3600
+token.addPrivilege('PrivPublishStream', expireAt)
+token.addPrivilege('PrivSubscribeStream', expireAt)
+token.expireTime(expireAt)
+const tokenString = token.serialize()
+```
+
+Token 生成库参考 [安装与测试 - 生成 RTC Token](./installation-and-testing.md#生成-rtc-token)。
+
+---
+
+## 错误码
+
+### 响应格式
+
+```json
+{
+ "ResponseMetadata": {
+ "RequestId": "xxx",
+ "Action": "StartVoiceChat",
+ "Error": {
+ "Code": "InvalidParameter",
+ "Message": "参数 AppId 不能为空"
+ }
+ }
+}
+```
+
+### 公共错误码
+
+| 错误码 | HTTP 状态码 | 说明 |
+|--------|------------|------|
+| `MissingParameter` | 400 | 缺少必要参数(如 Action、Version) |
+| `InvalidParameter` | 400 | 参数格式错误或无效 |
+| `MissingRequestInfo` | 400 | 缺少请求信息(如 X-Date 头) |
+| `InvalidTimestamp` | 400 | 请求过期或时间戳无效,检查 UTC 时间格式 |
+| `InvalidAuthorization` | 400 | Authorization 头格式错误 |
+| `InvalidCredential` | 400 | Credential 格式错误 |
+| `InvalidAccessKey` | 401 | AccessKey 无效或格式错误 |
+| `SignatureDoesNotMatch` | 401 | 签名验证失败,检查 SecretKey |
+| `InvalidSecretToken` | 401 | STS 临时凭证过期或无效 |
+| `AccessDenied` | 403 | IAM 权限不足 |
+| `ServiceNotFound` | 404 | 服务不存在 |
+| `InvalidActionOrVersion` | 404 | API Action 或 Version 不存在 |
+| `FlowLimitExceeded` | 429 | 请求频率超限,降低 QPS |
+| `InternalError` | 500 | 内部错误 |
+| `InternalServiceError` | 502 | 服务网关错误 |
+| `ServiceUnavailableTemp` | 503 | 服务暂时不可用 |
+| `InternalServiceTimeout` | 504 | 服务超时 |
+
+### 业务错误码
+
+| 错误码 | 说明 |
+|--------|------|
+| `RoomNotExist` | 房间不存在 |
+| `TaskNotExist` | 任务不存在 |
+| `InvalidToken` | RTC Token 无效或过期 |
+
+官方文档:[公共错误码](https://www.volcengine.com/docs/6369/68677)
+
+---
+
+## 相关资源
+
+- [安装与测试](./installation-and-testing.md)
+- [火山引擎实时对话式 API 文档](https://www.volcengine.com/docs/6348/1315560) - 官方完整文档
+- [火山引擎实时音视频文档](https://www.volcengine.com/docs/6348)
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png
new file mode 100644
index 000000000..8796d75aa
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/chat-example.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png
new file mode 100644
index 000000000..ea224e84e
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mcp-tool-example.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png
new file mode 100644
index 000000000..099d6e839
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/mqtt-settings.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png
new file mode 100644
index 000000000..724ccf97a
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/voice-connected.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png
new file mode 100644
index 000000000..6e927370f
Binary files /dev/null and b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/assets/web-ui-initial.png differ
diff --git a/zh_CN/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
new file mode 100644
index 000000000..1a1982db7
--- /dev/null
+++ b/zh_CN/emqx-ai/rtc-services/volcengine-rtc/installation-and-testing.md
@@ -0,0 +1,361 @@
+# 安装与测试
+
+本文档介绍如何集成火山云语音服务并完成基础测试。火山引擎提供多端 SDK,本文以 Web 端(`@volcengine/rtc`)为例说明集成流程。
+
+## 前置准备
+
+开始集成前,请确保已完成火山引擎服务开通和凭证配置。详细步骤参考[快速开始 - 火山引擎凭证](./quick-start.md#4-火山引擎凭证)。
+
+需要准备的凭证:
+
+| 凭证 | 用途 |
+|------|------|
+| `AppId` / `AppKey` | RTC 房间连接和 Token 生成 |
+| `AccessKeyId` / `SecretKey` | OpenAPI 请求签名 |
+| `ASR AppId` | 语音识别服务 |
+| `TTS AppId` / `TTS Token` / `TTS ResourceId` | 语音合成服务 |
+
+## 认证代理服务
+
+客户端加入 RTC 房间需要 Token,而 Token 由 `AppKey` 生成;启动语音会话需要调用 `StartVoiceChat` API,而该 API 需要 `AccessKey` 签名。这些密钥都不能暴露给客户端,因此需要搭建一个代理服务来处理认证。
+
+代理服务负责:
+- 使用 `AppKey` 生成 RTC Token
+- 使用 `AccessKey` 调用火山引擎 OpenAPI
+- 将 Token 和房间信息返回给客户端
+
+### 生成 RTC Token
+
+Token 使用 `AppKey` 通过 HMAC-SHA256 算法生成。火山引擎提供各语言的生成库:
+
+| 语言 | 参考实现 |
+|------|----------|
+| Go | [AccessToken.go](https://github.com/volcengine/rtc-aigc-demo/blob/main/server/rtc-aigc-demo/internal/pkg/rtctoken/token.go) |
+| Python | [access_token.py](https://github.com/volcengine/rtc-aigc-demo/blob/main/server/rtc-aigc-demo-python/src/rtctoken/access_token.py) |
+| Node.js / Bun | [token.ts](https://github.com/emqx/mcp-ai-companion-demo/tree/volcengine/rtc/volc-server/src/lib/token.ts) |
+
+```typescript
+import { AccessToken, Privileges } from './rtctoken'
+
+const token = new AccessToken(appId, appKey, roomId, userId)
+token.addPrivilege(Privileges.PrivPublishStream, expireTime)
+const tokenString = token.serialize() // 返回给客户端
+```
+
+### 调用火山引擎 OpenAPI
+
+`StartVoiceChat`、`StopVoiceChat` 等 API 需要使用 `AccessKeyId` 和 `SecretKey` 签名。使用官方 OpenAPI SDK 可以自动处理签名:
+
+```bash
+# Node.js / Bun
+npm install @volcengine/openapi
+
+# Python
+pip install volcengine-python-sdk
+
+# Go
+go get github.com/volcengine/volc-sdk-golang
+```
+
+```typescript
+// Node.js 示例
+import { Signer } from '@volcengine/openapi'
+
+const signer = new Signer({
+ accessKeyId: process.env.ACCESS_KEY_ID,
+ secretKey: process.env.SECRET_KEY,
+}, 'rtc')
+
+const response = await signer.fetch('https://rtc.volcengineapi.com', {
+ method: 'POST',
+ query: { Action: 'StartVoiceChat', Version: '2024-12-01' },
+ body: { AppId: appId, RoomId: roomId, ... },
+})
+// response 包含 Token、RoomId、UserId 等信息,返回给客户端
+```
+
+详细签名规范参考:[火山引擎 V4 签名算法](https://www.volcengine.com/docs/6369/67269)
+
+### API 设计示例
+
+代理服务需要暴露接口供客户端调用:
+
+```typescript
+// 启动语音会话 - 返回 Token 和房间信息
+POST /api/voice/start
+Request: { sceneId: string }
+Response: { roomId: string, token: string, userId: string, appId: string }
+
+// 停止语音会话
+POST /api/voice/stop
+Request: { roomId: string }
+Response: { success: boolean }
+```
+
+服务端实现中,这些接口内部调用火山引擎 OpenAPI(`StartVoiceChat`、`StopVoiceChat`),并将返回的 Token 等信息透传给客户端。
+
+## Web 端集成
+
+火山引擎提供 `@volcengine/rtc` SDK 用于 Web 端集成。客户端与服务端的交互流程如下:
+
+
+
+### 安装 SDK
+
+```bash
+npm install @volcengine/rtc
+```
+
+如需 AI 降噪功能,SDK 已内置 `@volcengine/rtc/extension-ainr` 扩展。
+
+### 基础集成流程
+
+#### 1. 调用服务端 API 获取 Token
+
+使用 RTC SDK 前,先调用服务端接口启动语音会话,获取 Token 和房间信息:
+
+```typescript
+// 调用服务端 API 获取认证信息
+const response = await fetch('/api/voice/start', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ sceneId: 'your-scene-id' }),
+})
+
+const { appId, roomId, token, userId } = await response.json()
+```
+
+#### 2. 创建 RTC 引擎
+
+```typescript
+import VERTC, { RoomProfileType, MediaType } from '@volcengine/rtc'
+
+// 使用服务端返回的 appId 创建引擎实例
+const engine = VERTC.createEngine(appId)
+```
+
+#### 3. 注册事件监听
+
+```typescript
+// 监听错误
+engine.on(VERTC.events.onError, (event) => {
+ console.error('RTC error:', event.errorCode)
+})
+
+// 监听远端用户发布流(AI 语音回复)
+engine.on(VERTC.events.onUserPublishStream, async (event) => {
+ const { userId, mediaType } = event
+ // 订阅远端音频流
+ await engine.subscribeStream(userId, mediaType)
+})
+
+// 监听二进制消息(字幕、状态等)
+engine.on(VERTC.events.onRoomBinaryMessageReceived, (event) => {
+ const { message } = event
+ // message 为 ArrayBuffer,需解析 TLV 格式
+ // 包含 ASR 识别结果、TTS 文本、智能体状态等
+})
+```
+
+#### 4. 加入房间
+
+```typescript
+// 使用步骤 1 获取的 token、roomId、userId 加入房间
+await engine.joinRoom(
+ token,
+ roomId,
+ {
+ userId: userId,
+ extraInfo: JSON.stringify({
+ call_scene: 'RTC-AIGC',
+ user_name: userId,
+ }),
+ },
+ {
+ isAutoPublish: false,
+ isAutoSubscribeAudio: false,
+ roomProfileType: RoomProfileType.chat,
+ }
+)
+```
+
+#### 5. 开启麦克风并发布音频
+
+```typescript
+// 开启麦克风采集
+await engine.startAudioCapture()
+
+// 发布音频流到房间
+await engine.publishStream(MediaType.AUDIO)
+```
+
+此时语音交互已经开始,用户说话会被 ASR 识别,LLM 处理后通过 TTS 播放回复。
+
+#### 6. 离开房间
+
+```typescript
+// 停止发布
+await engine.unpublishStream(MediaType.AUDIO)
+
+// 停止采集
+await engine.stopAudioCapture()
+
+// 离开房间
+await engine.leaveRoom()
+
+// 销毁引擎
+VERTC.destroyEngine(engine)
+
+// 调用服务端 API 停止语音会话
+await fetch('/api/voice/stop', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ roomId }),
+})
+```
+
+### AI 降噪(可选)
+
+火山引擎 RTC SDK 内置 AI 降噪扩展,可有效过滤环境噪音:
+
+```typescript
+import RTCAIAnsExtension, { AnsMode } from '@volcengine/rtc/extension-ainr'
+
+// 创建并注册扩展
+const aiAnsExtension = new RTCAIAnsExtension()
+engine.registerExtension(aiAnsExtension)
+
+// 检查是否支持
+const supported = await aiAnsExtension.isSupported()
+if (supported) {
+ // 设置降噪模式:LOW / MEDIUM / HIGH
+ await aiAnsExtension.setAnsMode(AnsMode.MEDIUM)
+ // 启用降噪
+ aiAnsExtension.enable()
+}
+```
+
+### 获取远端音频流
+
+订阅远端流后,可获取 MediaStream 用于播放:
+
+```typescript
+import { StreamIndex } from '@volcengine/rtc'
+
+// 获取远端用户的音频轨道
+const audioTrack = engine.getRemoteStreamTrack(userId, StreamIndex.STREAM_INDEX_MAIN, 'audio')
+
+// 创建 MediaStream 并播放
+const stream = new MediaStream()
+if (audioTrack) {
+ stream.addTrack(audioTrack)
+}
+
+// 绑定到 audio 元素播放
+const audioElement = document.querySelector('audio')
+audioElement.srcObject = stream
+```
+
+## 其他端 SDK
+
+火山引擎 RTC SDK 支持软件应用和硬件设备两类场景。
+
+### 软件应用
+
+详见:[集成实时对话式 AI(软件应用)](https://www.volcengine.com/docs/6348/1310560)
+
+| 平台 | SDK | 文档 |
+|------|-----|------|
+| Web | `@volcengine/rtc` | [Web SDK 文档](https://www.volcengine.com/docs/6348/104398) |
+| iOS | VolcEngineRTC | [iOS SDK 文档](https://www.volcengine.com/docs/6348/70080) |
+| Android | VolcEngineRTC | [Android SDK 文档](https://www.volcengine.com/docs/6348/70082) |
+| Windows | VolcEngineRTC | [Windows SDK 文档](https://www.volcengine.com/docs/6348/70084) |
+| macOS | VolcEngineRTC | [macOS SDK 文档](https://www.volcengine.com/docs/6348/70086) |
+| Linux | VolcEngineRTC | [Linux SDK 文档](https://www.volcengine.com/docs/6348/113623) |
+| Flutter | volc_engine_rtc | [Flutter SDK 文档](https://www.volcengine.com/docs/6348/113661) |
+| Electron | @volcengine/rtc | [Electron SDK 文档](https://www.volcengine.com/docs/6348/112063) |
+
+### 硬件设备
+
+详见:[集成实时对话式 AI(嵌入式硬件)](https://www.volcengine.com/docs/6348/1438400)
+
+支持嵌入式 Linux、RTOS、Android 等硬件平台。硬件端 SDK 需联系火山引擎技术支持获取。
+
+## 测试验证
+
+### 验证 RTC 连接
+
+成功加入房间后,可通过事件确认:
+
+```typescript
+engine.on(VERTC.events.onUserJoined, (event) => {
+ console.log('User joined:', event.userInfo.userId)
+})
+```
+
+### 验证语音识别
+
+对着麦克风说话,通过 `onRoomBinaryMessageReceived` 事件接收二进制消息。消息采用 TLV 格式编码,包含:
+
+- **字幕消息**:ASR 识别结果和 LLM 回复文本
+- **状态消息**:智能体状态(listening / thinking / speaking)
+- **Function Call**:工具调用请求
+
+### 验证语音合成
+
+AI 回复会通过远端音频流播放。确保:
+
+1. 已监听 `onUserPublishStream` 事件
+2. 已调用 `subscribeStream` 订阅远端音频
+3. 已将音频轨道绑定到 `