语音日历管理工具

一个基于Express的应用程序,通过语音识别和MCP协议提供日历管理功能,支持与CalDAV服务器交互和OpenAI兼容的API调用。

  • by WaltteriWe
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 WaltteriWe/mcp-labs-26

使用说明

mcp 实验室

语音+MCP日历演示。

此项目是一个小型Express应用程序,它:

  • 托管MCP服务器(流式HTTP传输),该服务器公开由CalDAV服务器支持的日历工具
  • 托管一个HTTP“MCP客户端”端点,该端点向OpenAI兼容的聊天完成API发送提示,并让模型调用这些MCP工具
  • 提供简单的浏览器UI(在 public/)记录音频,转录它(Whisper API),并将结果提示发送到MCP客户端端点

需求

  • Node.js 18+(建议使用Node 20+)
  • CalDAV服务器+凭据(或接受默认值,但工具没有用)
  • 与OpenAI兼容的API终结点,用于:
    • 聊天完成(/v1/chat/completions)
    • 音频转录(/v1/audio/transcriptions)

在这个实验室里, OPENAI_PROXY_URL 通常指向代理服务(不是直接指向OpenAI)。代理负责向传出请求添加任何所需的身份验证(例如API密钥)。

因为身份验证是由代理处理的,所以服务器使用直接的HTTP请求(通过 fetchData)而不是官方的OpenAI SDK。

快速开始

  1. 安装

    npm install
    
  2. 创建 .env

    cp .env-sample .env
    

    然后编辑 .env 并设置 OPENAI_PROXY_URL 到您的代理/基本URL(例如。 http://localhost:1234 或您部署的代理)。

  3. 运行开发服务器

    npm run dev
    
  4. 打开演示UI

    • 访问 http://localhost:3000/
    • 点击“开始录制”,说出命令,然后点击“停止录制”
    • 点击“发送”

环境变量

创建一个 .env 项目根目录中的文件。

服务器

  • PORT (可选,默认值: 3000)
  • NODE_ENV (可选,例如。 development)

MCP客户端+支持OpenAI的API

  • MCP_SERVER_URL (必填)
    • 例子: http://localhost:3000/api/v1/mcp
    • 这可以指向同一个服务器实例。
  • OPENAI_PROXY_URL (必填)
    • OpenAI兼容代理的基本URL(应用程序调用 /v1/chat/completions 和 /v1/audio/transcriptions 下面)
    • 例子: http://localhost:1234
  • OPENAI_MODEL (可选,默认值: gpt-4o)

音频转录(耳语)

  • OPENAI_TRANSCRIPTION_MODEL (可选,默认值: whisper-1)

CalDAV(日历备份存储)

  • CALDAV_SERVER_URL (可选,默认值: http://localhost:5232/)
  • CALDAV_USERNAME (可选,默认值: username)
  • CALDAV_PASSWORD (可选,默认值: password)

Radical(开发CalDAV服务器)

对于本地开发,您可以在不进行身份验证的情况下运行最小的Radicale CalDAV服务器。

macOS/Linux

  1. 安装Radical
python3 -m pip install --user radicale
  1. 创建本地配置+数据文件夹
mkdir -p radicale-data/collections
cat > radicale.config <<'EOF'
[server]
hosts = 127.0.0.1:5232

[auth]
type = none

[storage]
filesystem_folder = ./radicale-data/collections
EOF
  1. 运行 激进
radicale --config ./radicale.config

Windows(PowerShell)

  1. 安装Radical
py -m pip install --user radicale
  1. 创建本地配置+数据文件夹
New-Item -ItemType Directory -Force -Path .\radicale-data\collections | Out-Null
@'
[server]
hosts = 127.0.0.1:5232

[auth]
type = none

[storage]
filesystem_folder = ./radicale-data/collections
'@ | Set-Content -Encoding UTF8 .\radicale.config
  1. 运行 激进
py -m radicale --config .\radicale.config
  1. 将此应用程序指向Radical

在 .env:

  • CALDAV_SERVER_URL=http://localhost:5232/
  • CALDAV_USERNAME=anything (忽略时 auth=none)
  • CALDAV_PASSWORD=anything (忽略时 auth=none)

脚本

  • npm run dev –使用nodemon+ts节点运行服务器
  • npm run build –将TypeScript编译为 dist/
  • npm start –运行编译后的服务器(dist/index.js)

API

基础路径为 /api/v1.

健康

GET /api/v1/

返回一个简单的JSON消息。

MCP服务器

POST /api/v1/mcp

实现MCP流式HTTP传输。

MCP客户端

POST /api/v1/client

接受以下任一选项:

  1. JSON(文本提示)
curl -sS \
 -H 'Content-Type: application/json' \
 -d '{"prompt":"List my events","timezone":"Europe/Helsinki"}' \
 http://localhost:3000/api/v1/client
  1. multipart/form-data (音频上传)

字段名必须为 audio.

curl -sS \
 -F 'audio=@command.webm' \
 -F 'timezone=Europe/Helsinki' \
 http://localhost:3000/api/v1/client

答复:

{
  "answer": "...",
  "toolCalls": 2
}

MCP工具

MCP服务器当前公开:

  • listEvents –列出主要CalDAV日历中的事件
  • getEventsInTimeSlot –检查某个时间段的可用性(相对日期输入)
  • createEvent –创建事件(相对日期输入+标题+可选描述/位置)

MCP客户端指示模型使用工具处理所有用户请求,并应用一些工作流规则(例如,当用户询问“是否有空”时,在创建事件之前检查可用性)。

故障排除

  • 麦克风权限:浏览器将在第一次提示麦克风访问。如果录制失败,请检查站点权限。
  • CalDAV认证:如果日历工具总是返回空结果,请验证 CALDAV_* 值,并且您的用户至少有一个日历。
  • 代理URL: OPENAI_PROXY_URL 必须是基本URL;应用程序调用 /v1/chat/completions 和 /v1/audio/transcriptions 在它下面。
  • 上传清理:上传的音频在转录后尽最大努力删除;如果满足以下条件,请检查文件系统权限 uploads/ 出乎意料地增长。

API文件: POST /api/v1/client

通过MCP客户端运行用户提示。服务器将调用OpenAI兼容的Chat Completions API,模型可以调用MCP日历工具(通过MCP服务器URL)。

请求

支持的内容类型:

  1. application/json (文本提示)
  • prompt (string,必填)-用户命令/问题
  • timezone (字符串,可选)-IANA时区名称(默认为服务器的默认时区)。请参阅: tz数据库时区列表

JSON请求体示例:

{
  "prompt": "List my events",
  "timezone": "Europe/Helsinki"
}

例子:

curl -sS \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"List my events","timezone":"Europe/Helsinki"}' \
  http://localhost:3000/api/v1/client

选项2: multipart/form-data (音频)

  • audio (文件,必填)–要转录的音频文件(浏览器演示发送 audio/webm)
  • timezone (字符串,可选)–IANA时区名称

在此模式下,服务器首先转录音频,并使用转录文本作为提示。

例子:

curl -sS \
  -F 'audio=@command.webm' \
  -F 'timezone=Europe/Helsinki' \
  http://localhost:3000/api/v1/client

响应

成功时(HTTP 200):

{
  "answer": "...",
  "toolCalls": 2
}
  • answer (string)-最终辅助输出
  • toolCalls (number)–运行期间进行的工具调用总数

错误

  • 400 –请求正文无效(例如,缺失 prompt JSON格式,无效 timezone)
  • 500 –转录失败、OpenAI/MCP错误或意外的服务器错误

错误以JSON格式返回:

{
  "message": "..."
}

#� �m�c�p�-�l�a�b�s�-�2�6� � �