Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
Thumbs.db
__pycache__/
*.pyc
mcp-*/.venv/
7 changes: 7 additions & 0 deletions mcp-message-assistant/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
HY3_API_BASE=http://127.0.0.1:8000/v1
HY3_API_KEY=EMPTY
HY3_MODEL=hy3
HY3_TIMEOUT_SECONDS=120
HY3_MAX_RETRIES=2
HY3_MAX_PROMPT_CHARS=120000
MESSAGE_ASSISTANT_ALLOWED_ROOTS=/absolute/path/to/message-data
185 changes: 185 additions & 0 deletions mcp-message-assistant/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Hy3 Email & Message Assistant MCP Server

[中文说明](./README_CN.md)

A local stdio MCP server that uses Hy3 to turn email and message files into a prioritized inbox, explicit action items, safe reply drafts, and a concise digest.

The server only reads paths explicitly allowed by the user. It never sends, deletes, or modifies messages.

## Workflow

```text
local files -> load_messages -> Hy3 triage
|-> action items
|-> reply drafts
`-> inbox digest
```

## Tools

| Tool | Purpose |
| --- | --- |
| `load_messages` | Read `.eml`, `.json`, `.jsonl`, `.txt`, or `.md` files into normalized JSON. |
| `triage_messages_with_hy3` | Classify messages, assign priority, identify reply needs, and preserve explicit deadlines. |
| `extract_action_items_with_hy3` | Extract tasks, owners, deadlines, waiting states, and unresolved questions. |
| `draft_replies_with_hy3` | Draft replies without sending them and flag details that need confirmation. |
| `generate_inbox_digest_with_hy3` | Create a Markdown digest organized by urgency and next action. |

Every tool has a typed MCP input schema with parameter descriptions. The Hy3 tools support `no_think`, `low`, and `high` reasoning modes.

## Requirements

- Python 3.10+
- A Hy3 OpenAI-compatible endpoint
- Cursor, CodeBuddy, or another MCP client with stdio support

## One-command install

From this directory:

```bash
./scripts/install.sh
```

The executable is created at:

```text
.venv/bin/hy3-message-assistant-mcp
```

You can also install without the script:

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

## Environment

Copy the variable names from [`.env.example`](./.env.example) into your MCP client configuration or shell environment.

| Variable | Required | Description |
| --- | --- | --- |
| `HY3_API_KEY` | Yes | API credential. Use `EMPTY` only for a local endpoint that does not require authentication. |
| `HY3_API_BASE` | No | OpenAI-compatible endpoint. Defaults to `http://127.0.0.1:8000/v1`. |
| `HY3_MODEL` | No | Served model name. Defaults to `hy3`. |
| `MESSAGE_ASSISTANT_ALLOWED_ROOTS` | Recommended | Allowed input roots, separated by the operating system path separator. Defaults to the server working directory. |
| `HY3_DRY_RUN` | No | Set to `1` to preview prompts without calling Hy3. |
| `HY3_TIMEOUT_SECONDS` | No | API timeout. Defaults to 120 seconds. |
| `HY3_MAX_PROMPT_CHARS` | No | Maximum prompt size. Defaults to 120000 characters. |

No real API key is stored in the repository.

## Input formats

### JSON

Use either a message list or an object containing `messages`:

```json
{
"messages": [
{
"id": "msg-001",
"channel": "email",
"sender": "sender@example.com",
"recipients": ["me@example.com"],
"subject": "Confirm the demo",
"timestamp": "2026-07-25T09:00:00+08:00",
"body": "Please confirm by noon."
}
]
}
```

JSONL uses one message object per line. EML uses the standard email format. TXT and Markdown files are treated as one message each.

## Cursor

Cursor project-level MCP configuration lives at `.cursor/mcp.json`. Start from [the provided example](./configs/cursor.project.mcp.json), replace the absolute executable and allowed-root paths, and set `HY3_API_KEY` in the local Cursor configuration.

Dry-run demo request:

```text
Use hy3-message-assistant.load_messages to read
/absolute/path/to/Hy3/mcp-message-assistant/examples/sample_messages.json.
Then pass the returned JSON to triage_messages_with_hy3 with
user_context="Project lead preparing an MCP demo".
Do not use the terminal or write a script.
```

## CodeBuddy

CodeBuddy project configuration lives at `<project root>/.mcp.json`. Copy [the provided project example](./configs/codebuddy.project.mcp.json) to that location, then export the local values before starting CodeBuddy:

```bash
export HY3_API_KEY=EMPTY
export MESSAGE_ASSISTANT_ALLOWED_ROOTS=/absolute/path/to/Hy3/mcp-message-assistant/examples
codebuddy --settings '{"enableAllProjectMcpServers":true}' \
-p "Use hy3-message-assistant to load examples/sample_messages.json and triage the inbox."
```

The equivalent project-scoped CLI registration is:

```bash
codebuddy mcp add-json --scope project hy3-message-assistant \
'{"type":"stdio","command":"./mcp-message-assistant/.venv/bin/hy3-message-assistant-mcp","args":[],"env":{"HY3_API_BASE":"http://127.0.0.1:8000/v1","HY3_API_KEY":"EMPTY","HY3_MODEL":"hy3","MESSAGE_ASSISTANT_ALLOWED_ROOTS":"."}}'
```

Use environment expansion in the committed `.mcp.json`; the literal `EMPTY` above is only for a local no-auth Hy3 endpoint.

## Demo and verification

Run all tests:

```bash
.venv/bin/python -m unittest discover -s tests -v
```

Run the local workflow without a live model:

```bash
HY3_DRY_RUN=1 .venv/bin/python examples/demo_workflow.py
```

Start the stdio server, list all tools, load the sample inbox, and call all four Hy3 tools through an MCP client:

```bash
.venv/bin/python examples/protocol_smoke_test.py
```

Expected summary:

```text
tools=draft_replies_with_hy3,extract_action_items_with_hy3,generate_inbox_digest_with_hy3,load_messages,triage_messages_with_hy3
load_messages=ok
hy3_tools=ok
```

## Privacy and safety

- Message content is sent to the configured Hy3 endpoint. Use a trusted endpoint for private data.
- `MESSAGE_ASSISTANT_ALLOWED_ROOTS` limits which local paths can be read.
- The server does not connect to IMAP, Gmail, chat platforms, or sending APIs.
- Reply output is always a draft. The user remains responsible for verification and sending.
- The prompts explicitly prohibit invented deadlines, commitments, approvals, prices, or claims that a message was sent.

## Limitations

- Attachments are not parsed.
- HTML email is converted to plain text; complex layouts may lose structure.
- Large bodies and prompts are truncated at configured limits.
- Hy3 output quality depends on the deployed model and endpoint.
- The current implementation reads exported or local message files rather than a live mailbox.

## Troubleshooting

- **Path rejected:** add the parent directory to `MESSAGE_ASSISTANT_ALLOWED_ROOTS`.
- **Missing API key:** set `HY3_API_KEY`; use `EMPTY` only for a local no-auth endpoint.
- **502 or connection error:** verify that the Hy3 endpoint is running and `HY3_API_BASE` is correct.
- **Client cannot start the server:** use an absolute executable path and run the protocol smoke test first.
- **Need to test without Hy3:** set `HY3_DRY_RUN=1`.

## License

Apache 2.0. See the repository root license.
100 changes: 100 additions & 0 deletions mcp-message-assistant/README_CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Hy3 邮件与消息处理 MCP Server

[English](./README.md)

这是一个本地运行的 MCP Server。它读取用户主动提供的邮件或消息文件,使用 Hy3 完成优先级判断、行动项提取、回复草稿和收件箱摘要。

它不会发送、删除或修改任何消息。

## 提供的工具

| 工具 | 功能 |
| --- | --- |
| `load_messages` | 读取 `.eml`、`.json`、`.jsonl`、`.txt` 和 `.md` 文件,并统一为消息列表。 |
| `triage_messages_with_hy3` | 判断消息类别、优先级、是否需要回复和明确截止时间。 |
| `extract_action_items_with_hy3` | 提取任务、负责人、截止时间、等待状态和未解决问题。 |
| `draft_replies_with_hy3` | 生成回复草稿,并标出必须由用户确认的细节。 |
| `generate_inbox_digest_with_hy3` | 生成按照紧急程度和下一步行动组织的摘要。 |

## 安装

在当前目录运行:

```bash
./scripts/install.sh
```

安装后启动命令位于:

```text
.venv/bin/hy3-message-assistant-mcp
```

## 必要配置

`HY3_API_KEY` 必须通过环境变量或 MCP 客户端配置传入。使用不需要鉴权的本地 Hy3 服务时,可以设为 `EMPTY`。

```bash
export HY3_API_BASE=http://127.0.0.1:8000/v1
export HY3_API_KEY=EMPTY
export HY3_MODEL=hy3
export MESSAGE_ASSISTANT_ALLOWED_ROOTS=/absolute/path/to/message-data
```

其他可选变量见 [`.env.example`](./.env.example)。

## Cursor 配置

将 [`configs/cursor.project.mcp.json`](./configs/cursor.project.mcp.json) 的内容放到项目的 `.cursor/mcp.json`,替换其中的绝对路径和本地凭据。

可直接在 Cursor Agent 中输入:

```text
直接使用 hy3-message-assistant.load_messages 读取
/absolute/path/to/mcp-message-assistant/examples/sample_messages.json,
然后把返回结果交给 triage_messages_with_hy3。
不要运行终端,不要另写脚本。
```

## CodeBuddy 配置

将 [`configs/codebuddy.project.mcp.json`](./configs/codebuddy.project.mcp.json) 复制到项目根目录的 `.mcp.json`。该配置通过环境变量引用凭据,不保存真实密钥。

项目级命令示例:

```bash
codebuddy mcp add-json --scope project hy3-message-assistant \
'{"type":"stdio","command":"./mcp-message-assistant/.venv/bin/hy3-message-assistant-mcp","args":[],"env":{"HY3_API_BASE":"http://127.0.0.1:8000/v1","HY3_API_KEY":"EMPTY","HY3_MODEL":"hy3","MESSAGE_ASSISTANT_ALLOWED_ROOTS":"."}}'
```

## 测试与演示

```bash
.venv/bin/python -m unittest discover -s tests -v
HY3_DRY_RUN=1 .venv/bin/python examples/demo_workflow.py
.venv/bin/python examples/protocol_smoke_test.py
```

样例数据位于:

- `examples/sample_messages.json`
- `examples/sample_email.eml`

## 隐私与限制

- 消息内容会发送到用户配置的 Hy3 服务,请只使用可信服务处理私人数据。
- Server 只能读取 `MESSAGE_ASSISTANT_ALLOWED_ROOTS` 指定的目录。
- 当前不连接真实邮箱或聊天平台,也不会发送消息。
- 附件暂不解析,复杂 HTML 邮件会转为纯文本。
- 大段正文会按照配置限制截断。

## 常见问题

- 路径无法读取:检查 `MESSAGE_ASSISTANT_ALLOWED_ROOTS`。
- 提示缺少凭据:设置 `HY3_API_KEY`。
- 接口返回 502:检查 Hy3 服务和 `HY3_API_BASE`。
- 没有可用 Hy3 服务:设置 `HY3_DRY_RUN=1` 验证完整 MCP 调用链。

## 许可证

Apache 2.0,参见仓库根目录许可证。
16 changes: 16 additions & 0 deletions mcp-message-assistant/configs/codebuddy.project.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"mcpServers": {
"hy3-message-assistant": {
"type": "stdio",
"command": "./mcp-message-assistant/.venv/bin/hy3-message-assistant-mcp",
"args": [],
"env": {
"HY3_API_BASE": "${HY3_API_BASE:-http://127.0.0.1:8000/v1}",
"HY3_API_KEY": "${HY3_API_KEY}",
"HY3_MODEL": "${HY3_MODEL:-hy3}",
"MESSAGE_ASSISTANT_ALLOWED_ROOTS": "${MESSAGE_ASSISTANT_ALLOWED_ROOTS:-.}"
},
"description": "Hy3-powered email and message triage, action extraction, reply drafting, and digest generation"
}
}
}
14 changes: 14 additions & 0 deletions mcp-message-assistant/configs/cursor.project.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"mcpServers": {
"hy3-message-assistant": {
"command": "/absolute/path/to/Hy3/mcp-message-assistant/.venv/bin/hy3-message-assistant-mcp",
"args": [],
"env": {
"HY3_API_BASE": "http://127.0.0.1:8000/v1",
"HY3_API_KEY": "REPLACE_WITH_KEY_OR_EMPTY",
"HY3_MODEL": "hy3",
"MESSAGE_ASSISTANT_ALLOWED_ROOTS": "/absolute/path/to/message-data"
}
}
}
}
35 changes: 35 additions & 0 deletions mcp-message-assistant/examples/demo_workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import annotations

import os
from pathlib import Path

from hy3_message_assistant_mcp.core import (
draft_replies_with_hy3,
extract_action_items_with_hy3,
generate_inbox_digest_with_hy3,
triage_messages_with_hy3,
)
from hy3_message_assistant_mcp.loaders import load_messages


def main() -> None:
root = Path(__file__).resolve().parents[1]
sample = root / "examples" / "sample_messages.json"
os.environ.setdefault("MESSAGE_ASSISTANT_ALLOWED_ROOTS", str(root))
os.environ.setdefault("HY3_DRY_RUN", "1")

messages = load_messages(str(sample))
outputs = [
("triage", triage_messages_with_hy3(messages, user_context="Project lead preparing an MCP demo.")),
("actions", extract_action_items_with_hy3(messages)),
("drafts", draft_replies_with_hy3(messages, tone="friendly and concise")),
("digest", generate_inbox_digest_with_hy3(messages)),
]

for name, output in outputs:
print(f"\n=== {name} ===\n")
print(output)


if __name__ == "__main__":
main()
Loading