Metadata-Version: 2.4
Name: mcp-asr
Version: 0.1.5
Summary: A secure stdio MCP server for OpenAI-compatible ASR endpoints
License-Expression: MIT
Keywords: mcp,asr,speech-to-text,openai-compatible,qwen3-asr
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp==2.0.0
Requires-Dist: aiohttp<4,>=3.11
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Requires-Dist: pytest-asyncio>=0.24; extra == "test"
Provides-Extra: publish
Requires-Dist: build>=1.2; extra == "publish"
Requires-Dist: twine>=6; extra == "publish"
Dynamic: license-file

# mcp-asr

`mcp-asr` 是一个 stdio MCP 语音转写服务，用于调用 OpenAI-compatible
transcription 接口：

```text
Claude / Codex / Agent → stdio MCP → OpenAI-compatible ASR
```

支持普通转写、纯文本输出，以及会议/访谈的说话人对话输出。

## 公共配置

| 配置 | 必填 | 说明 |
|---|---:|---|
| `--url` / `MCP_ASR_URL` | 是 | transcription 完整 URL |
| `--model` / `MCP_ASR_MODEL` | 是 | 普通模型，支持上游 `json` |
| `--dialogue-model` / `MCP_ASR_DIALOGUE_MODEL` | dialogue 模式必填 | 支持 `verbose_json` 和 speaker segments 的模型 |
| `--default-output-format` / `MCP_ASR_DEFAULT_OUTPUT_FORMAT` | 否 | 默认输出形式：`text`、`json` 或 `dialogue`，默认 `json` |
| `MCP_ASR_TOKEN` | 是 | 上游 Token，只从环境变量读取 |

启动参数优先于环境变量。一个模型同时支持普通和说话人转写时，可以把
`--model` 和 `--dialogue-model` 配置为同一个模型名称。

文件是否可访问由宿主沙箱、操作系统权限和 MCP 客户端的用户授权决定；
`mcp-asr` 本身不额外弹出文件授权确认。

## 通过 PyPI 使用

### 安装

```bash
python3 -m venv .venv
.venv/bin/pip install mcp-asr
```

### 手工运行

```bash
MCP_ASR_TOKEN='your-token' \
.venv/bin/mcp-asr \
  --url https://api.example.com/v1/audio/transcriptions \
  --model normal-asr-model \
  --dialogue-model speaker-asr-model \
  --default-output-format json
```

### Claude Code

```json
{
  "mcpServers": {
    "speech-to-text": {
      "type": "stdio",
      "command": "/absolute/path/to/.venv/bin/mcp-asr",
      "args": [
        "--url",
        "https://api.example.com/v1/audio/transcriptions",
        "--model",
        "normal-asr-model",
        "--dialogue-model",
        "speaker-asr-model",
        "--default-output-format",
        "json"
      ],
      "env": {
        "MCP_ASR_TOKEN": "your-token"
      },
      "timeout": 240000
    }
  }
}
```

### Codex

```toml
[mcp_servers.speech-to-text]
command = "/absolute/path/to/.venv/bin/mcp-asr"
args = [
  "--url", "https://api.example.com/v1/audio/transcriptions",
  "--model", "normal-asr-model",
  "--dialogue-model", "speaker-asr-model",
  "--default-output-format", "json",
]
enabled = true
startup_timeout_sec = 20
tool_timeout_sec = 240

[mcp_servers.speech-to-text.env]
MCP_ASR_TOKEN = "your-token"
```

## 通过 npx 使用

npm 包是 PyPI `mcp-asr==0.1.5` 的薄启动器。首次运行会在用户缓存目录创建
Python 虚拟环境并安装固定版本的 PyPI 包。

### 前置条件

- Node.js 18 或更高版本；
- Python 3.10 或更高版本；
- 首次准备时可以访问 PyPI。

### 首次预热

```bash
npx -y mcp-asr@0.1.5 --prepare
```

如需指定 Python：

```bash
MCP_ASR_PYTHON=/path/to/python3 \
npx -y mcp-asr@0.1.5 --prepare
```

### 手工运行

```bash
MCP_ASR_TOKEN='your-token' \
npx -y mcp-asr@0.1.5 \
  --url https://api.example.com/v1/audio/transcriptions \
  --model normal-asr-model \
  --dialogue-model speaker-asr-model \
  --default-output-format json
```

也可以通过环境变量提供：

```bash
MCP_ASR_TOKEN='your-token' \
MCP_ASR_URL='https://api.example.com/v1/audio/transcriptions' \
MCP_ASR_MODEL='normal-asr-model' \
MCP_ASR_DIALOGUE_MODEL='speaker-asr-model' \
MCP_ASR_DEFAULT_OUTPUT_FORMAT='json' \
npx -y mcp-asr@0.1.5
```

### Claude Code

```json
{
  "mcpServers": {
    "speech-to-text": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "mcp-asr@0.1.5",
        "--url",
        "https://api.example.com/v1/audio/transcriptions",
        "--model",
        "normal-asr-model",
        "--dialogue-model",
        "speaker-asr-model",
        "--default-output-format",
        "json"
      ],
      "env": {
        "MCP_ASR_TOKEN": "your-token"
      },
      "timeout": 240000
    }
  }
}
```

### Codex

```toml
[mcp_servers.speech-to-text]
command = "npx"
args = [
  "-y",
  "mcp-asr@0.1.5",
  "--url", "https://api.example.com/v1/audio/transcriptions",
  "--model", "normal-asr-model",
  "--dialogue-model", "speaker-asr-model",
  "--default-output-format", "json",
]
enabled = true
startup_timeout_sec = 30
tool_timeout_sec = 240

[mcp_servers.speech-to-text.env]
MCP_ASR_TOKEN = "your-token"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "speech-to-text": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "mcp-asr@0.1.5",
        "--url",
        "https://api.example.com/v1/audio/transcriptions",
        "--model",
        "normal-asr-model",
        "--dialogue-model",
        "speaker-asr-model",
        "--default-output-format",
        "json"
      ],
      "enabled": true,
      "timeout": 240000,
      "environment": {
        "MCP_ASR_TOKEN": "your-token"
      }
    }
  }
}
```

### 可选环境变量

| 环境变量 | 说明 |
|---|---|
| `MCP_ASR_PYTHON` | 指定用于创建虚拟环境的 Python |
| `MCP_ASR_NPX_CACHE_DIR` | 覆盖 npx 持久化缓存目录 |
| `MCP_ASR_TRANSCRIPT_CACHE_DIR` | 覆盖转录结果和导出文件缓存目录 |
| `MCP_ASR_TRANSCRIPT_PAGE_CHARS` | 每页最多展示字符数，默认 `100` |

默认缓存目录：

- macOS：`~/Library/Caches/mcp-asr-npx/`
- Linux：`${XDG_CACHE_HOME:-~/.cache}/mcp-asr-npx/`

## transcribe_audio

| 参数 | 说明 |
|---|---|
| `file_path` | 本地音频路径，与 `audio_base64` 二选一 |
| `audio_base64` | Base64 音频数据，与 `file_path` 二选一 |
| `format` | Base64 音频格式；使用 `audio_base64` 时必填 |
| `language` | 可选；省略、空字符串或 `auto` 表示自动检测 |
| `prompt` | 可选上下文提示 |
| `hotwords` | 可选热词列表，会合并进 prompt |
| `output_format` | `text`、`json` 或 `dialogue`；默认使用服务启动配置 |
| `response_format` | 旧参数兼容：`json` 或 `verbose_json`；不可与 `output_format` 同时使用 |
| `include_timestamps` | 保留时间戳分段；导出 SRT/VTT 需要有效分段 |
| `include_raw` | 保存脱敏后的上游原始 JSON，供 JSON 文件导出使用 |

### 输出选择

| 场景 | `output_format` | 模型和上游格式 |
|---|---|---|
| 普通音频 | `json`，默认 | 普通模型 + `json` |
| 只需要纯文本 | `text` | 普通模型 + `json` |
| 会议、访谈、多人对话 | `dialogue` | 对话模型 + `verbose_json` |

普通音频：

```json
{
  "file_path": "/path/to/audio.wav",
  "output_format": "json"
}
```

会议音频：

```json
{
  "file_path": "/path/to/meeting.wav",
  "output_format": "dialogue"
}
```

只需要文本：

```json
{
  "file_path": "/path/to/audio.wav",
  "output_format": "text"
}
```

用户也可以直接告诉 Agent：“这是会议录音，请区分发言人”。工具 schema 会提示
Agent 选择 `dialogue`；没有会议、访谈或区分发言人的意图时默认使用 `json`。

### 分页返回结构

ASR 始终先完成整段音频识别，并将完整结果保存到转录缓存。工具响应中只有
`content[0].text` 承载用于阅读的转录文本；`structuredContent` 不再重复返回
`text`、`dialogue` 或 `segments`。

- `text` / `json`：展示普通连续正文；
- `dialogue`：展示 `speaker（start秒）：text` 对话正文；
- 内容不超过每页上限时返回全文；
- 内容超过上限时返回第一页和 `next_cursor`。

```json
{
  "output_format": "dialogue",
  "transcript_id": "tr_0123456789abcdef0123456789abcdef",
  "transcription_complete": true,
  "duration": 660.28,
  "segment_count": 198,
  "total_characters": 10428,
  "page_characters": 4986,
  "has_more": true,
  "is_first_page": true,
  "is_last_page": false,
  "next_cursor": 4986
}
```

`transcription_complete=true` 表示 ASR 已完整完成。`has_more=true` 时必须使用
`read_transcript` 读取后续页，不应再次调用 `transcribe_audio`。默认每页最多
100 个 Unicode 字符，可通过 `MCP_ASR_TRANSCRIPT_PAGE_CHARS` 或
`--transcript-page-chars` 调整。普通正文优先在句子边界分页，dialogue 优先保持完整行。

## read_transcript

分页读取已经完成的转录结果，不调用 ASR：

```json
{
  "transcript_id": "tr_0123456789abcdef0123456789abcdef",
  "cursor": 4986
}
```

返回的正文仍只位于 `content[0].text`；继续使用 `next_cursor`，直到
`has_more=false`。

## export_transcript

把已有结果导出为完整文件，不调用 ASR：

```json
{
  "transcript_id": "tr_0123456789abcdef0123456789abcdef",
  "format": "vtt",
  "filename": "meeting.vtt"
}
```

支持格式：

| 格式 | 内容 |
|---|---|
| `txt` | 普通模式导出连续正文；dialogue 模式导出带说话人的对话稿 |
| `json` | 完整普通正文和规范化 segments；请求 `include_raw` 时也保存脱敏 raw |
| `srt` | SubRip 字幕，时间使用 `00:00:00,000` |
| `vtt` | WebVTT 字幕，包含 `WEBVTT` 文件头 |

SRT/VTT 要求缓存结果中存在有效的 `start`、`end` 和 `text` 分段，否则返回
`subtitle_unavailable`，不会自动重新请求 ASR。导出响应只返回简短状态和文件路径，
不会把完整文件再次内嵌到 MCP 响应。

默认转录缓存目录：

- macOS：`~/Library/Caches/mcp-asr/transcripts/`；
- Linux：`${XDG_CACHE_HOME:-~/.cache}/mcp-asr/transcripts/`；
- Windows：`%LOCALAPPDATA%\mcp-asr\transcripts\`。

可通过 `MCP_ASR_TRANSCRIPT_CACHE_DIR` 或 `--transcript-cache-dir` 覆盖。

### 使用限制

- `file_path` 可以指向 MCP Server 进程有权限访问的任意本地音频；
- 最大音频大小为 25 MB；
- 支持 `flac`、`mp3`、`mp4`、`mpeg`、`mpga`、`m4a`、`ogg`、`opus`、
  `aac`、`wav`、`webm`；
- MCP 工具调用不能直接指定模型或 URL。
