File size: 4,513 Bytes
a9536c4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | # -*- coding: utf-8 -*-
"""
MCP 服务器 - 为 Claude Code 提供 AI 翻唱工具
"""
import asyncio
import json
from pathlib import Path
from typing import Any
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
from mcp.tools import (
list_models,
convert_voice,
download_model,
get_model_status
)
# 创建 MCP 服务器
server = Server("rvc-voice-conversion")
@server.list_tools()
async def list_tools() -> list[Tool]:
"""列出可用工具"""
return [
Tool(
name="list_voice_models",
description="列出所有可用的 RVC 语音模型",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="convert_voice",
description="使用 RVC 模型进行 AI 翻唱",
inputSchema={
"type": "object",
"properties": {
"input_path": {
"type": "string",
"description": "输入音频文件的绝对路径"
},
"output_path": {
"type": "string",
"description": "输出音频文件的绝对路径"
},
"model_name": {
"type": "string",
"description": "要使用的语音模型名称"
},
"pitch_shift": {
"type": "number",
"description": "音调偏移 (半音),正数升调,负数降调",
"default": 0
},
"index_ratio": {
"type": "number",
"description": "索引混合比率 (0-1)",
"default": 0.5
}
},
"required": ["input_path", "output_path", "model_name"]
}
),
Tool(
name="download_base_models",
description="下载 RVC 所需的基础模型 (HuBERT, RMVPE)",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
),
Tool(
name="get_model_status",
description="获取基础模型的下载状态",
inputSchema={
"type": "object",
"properties": {},
"required": []
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
"""执行工具调用"""
if name == "list_voice_models":
models = list_models()
result = {
"models": models,
"count": len(models)
}
return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
elif name == "convert_voice":
result = convert_voice(
input_path=arguments["input_path"],
output_path=arguments["output_path"],
model_name=arguments["model_name"],
pitch_shift=arguments.get("pitch_shift", 0),
index_ratio=arguments.get("index_ratio", 0.5),
filter_radius=arguments.get("filter_radius", 3),
rms_mix_rate=arguments.get("rms_mix_rate", 0.25),
protect=arguments.get("protect", 0.33)
)
return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
elif name == "download_base_models":
result = download_model()
return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False, indent=2))]
elif name == "get_model_status":
status = get_model_status()
return [TextContent(type="text", text=json.dumps(status, ensure_ascii=False, indent=2))]
else:
return [TextContent(type="text", text=f"未知工具: {name}")]
async def main():
"""启动 MCP 服务器"""
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())
|