Skip to main content
Glama
README.md
# domain-manager

`domain-manager` 是用于管理 `iveseenu.com` Cloudflare DNS 的安全命令行工具。它不是常驻服务,不管理域名注册商、Nameserver、DNSSEC、Cloudflare Zone 设置、SSL/TLS、WAF、Workers 或 API Token。

工具只允许操作 `iveseenu.com` 及其子域名,并在本地再次执行白名单和敏感记录保护,即使 Cloudflare Token 被意外授予其他 Zone 权限也不会突破该限制。

## 启动方式

项目不依赖第三方 Python 包。在项目根目录执行:

```bash
./domain-manager --help
```

如果已将项目目录加入 `PATH`,也可以直接使用 `domain-manager --help`。

## 配置

工具从环境变量读取 Cloudflare 凭据;不要将 Token 写入源码、README、Git 或普通配置文件。

```bash
export CLOUDFLARE_API_TOKEN='...'
export CLOUDFLARE_ZONE_ID='...'       # 可选;未提供时会查询 Active Zone 并缓存结果
export ALLOWED_ZONE='iveseenu.com'    # 可选,默认值即为 iveseenu.com
```

可参考 [`.env.example`](.env.example)。`.env` 已被 Git 忽略,但工具不会自动读取 `.env` 文件,需要由运行环境安全地注入变量。

## 名称与默认值

- 简短名称会自动补全 Zone:`test` 变为 `test.iveseenu.com`。
- 已是 `iveseenu.com` 子域的完整名称不会重复拼接。
- 默认 `ttl` 为 `300` 秒,使用 `--ttl auto` 时交给 Cloudflare 管理。
- 默认 `proxied` 为 `false`(DNS only)。只有显式 `--proxied true` 才会启用 Cloudflare Proxy;代理记录的 TTL 由 Cloudflare 自动管理。
- 创建、更新与 upsert 仅支持 `A`、`AAAA`、`CNAME`、`TXT`。

## 查询记录

列出全部记录:

```bash
./domain-manager list
./domain-manager list --output json
```

按类型或名称过滤:

```bash
./domain-manager list --type A --output json
./domain-manager list --name codex --output json
```

查询指定名称:

```bash
./domain-manager get codex --output json
./domain-manager get codex.iveseenu.com --type A --output json
```

## Dry Run

所有写操作都支持 `--dry-run`。该模式只查询现状并输出计划,不会向 Cloudflare 发送创建、更新或删除请求。建议 Agent 和人工操作都先执行一次 Dry Run。

```bash
./domain-manager create \
  --type A --name domain-manager-test --content 192.0.2.10 \
  --ttl 300 --proxied false --dry-run --output json

./domain-manager upsert \
  --type A --name domain-manager-test --content 192.0.2.10 \
  --dry-run --output json
```

`192.0.2.10` 是文档保留测试地址;移除 `--dry-run` 前应确认该地址和记录名称确实可用。

## 创建记录

```bash
./domain-manager create \
  --type A --name app --content 203.0.113.10 \
  --ttl 300 --proxied false --dry-run
```

若同类型、同名称的记录已存在,`create` 会拒绝请求。请改用 `update` 或 `upsert`。

## 更新记录

`update` 必须精确匹配一条记录。执行时会先查询旧值,更新后再次查询验证新值。

```bash
./domain-manager update \
  --type A --name app --content 203.0.113.11 \
  --ttl 300 --proxied false --dry-run --output json
```

## 幂等写入(推荐)

`upsert` 是 Agent 最适合使用的接口:记录不存在则创建,存在但内容或配置不同则更新,完全相同则返回 `NOOP`,不产生写操作。

```bash
./domain-manager upsert \
  --type A --name app --content 203.0.113.10 \
  --ttl 300 --proxied false --dry-run --output json
```

## 删除记录

删除默认被拒绝,必须同时显式提供 `--confirm-delete`。删除前会查询并保存旧记录信息,删除后会再次查询确认记录已不存在。

```bash
./domain-manager delete \
  --type A --name app --confirm-delete --dry-run --output json
```

仅在确认 Dry Run 的目标正确后,才移除 `--dry-run` 执行真实删除。

## 安全限制

- 不允许操作任何其他 Zone。
- 根域 `iveseenu.com` 的更新和删除默认拒绝,只有显式 `--allow-root` 才可继续。
- `MX`、`NS`、`SOA`、`CAA` 禁止创建、更新和删除。
- `_domainconnect.*` 禁止更新和删除。
- `_acme-challenge.*`、`_dmarc.*`、`selector*._domainkey.*` 等敏感验证/邮件记录,需要显式 `--allow-sensitive`。
- 删除必须使用 `--confirm-delete`,写入前建议始终使用 `--dry-run`。

## 输出格式

默认输出为便于人工阅读的表格。Agent 应使用 `--output json`;JSON 模式的 stdout 只包含 JSON。

成功更新示例:

```json
{
  "success": true,
  "action": "UPDATE",
  "changed": true,
  "record": {
    "id": "...",
    "type": "A",
    "name": "app.iveseenu.com",
    "content": "203.0.113.10",
    "ttl": 300,
    "proxied": false
  },
  "error": null
}
```

完全相同的 `upsert` 返回 `action: "NOOP"` 且 `changed: false`。失败时返回 `success: false` 和不含 Token 的 `error` 对象。

## 审计日志

每次真实写操作会记录时间、操作、Zone、记录 ID/类型/名称、旧值、新值和结果。日志优先写入:

```text
/var/log/domain-manager/audit.log
```

没有该目录写权限时,使用:

```text
./logs/audit.log
```

审计日志不会记录 `CLOUDFLARE_API_TOKEN` 或 Authorization Header。

## MCP:供 Codex、Hermes 等 Agent 调用

MCP Server 使用标准输入输出(stdio)JSON-RPC 传输,不是 HTTP 服务。启动命令为:

```bash
./domain-manager-mcp
```

在 Codex、Hermes 或其他 MCP Client 的 Server 配置中,将 `command` 设置为该启动器的绝对路径:

```text
/mnt/d/codes/projects/scripts/domain-manage/domain-manager-mcp
```

不要把 Token 写进 MCP 配置文件、工具参数、Prompt、Git 或日志。应由启动 MCP Client 的受控环境注入 `CLOUDFLARE_API_TOKEN`。对于支持 Secret File / Secret Mount 的运行环境,可改用 `CLOUDFLARE_API_TOKEN_FILE`:该文件必须是普通文件且权限为 `0600`,内容仅为 Token。

```bash
install -m 600 /dev/null /run/user/$(id -u)/cloudflare-token
# 通过你的 Secret Manager 或安全终端写入 Token;不要使用 shell history 保存它。
export CLOUDFLARE_API_TOKEN_FILE=/run/user/$(id -u)/cloudflare-token
./domain-manager-mcp
```

MCP 工具列表如下。所有工具结果都返回统一 JSON 结构;MCP transport 的 stdout 只输出 JSON-RPC 消息。

| MCP 工具 | 用途 |
| --- | --- |
| `list_dns` | 列出记录,可选 `type`、`name` 筛选。 |
| `get_dns` | 查询指定 `name`,可选 `type`。 |
| `create_dns` | 创建 `A`、`AAAA`、`CNAME`、`TXT` 记录。 |
| `update_dns` | 精确匹配一条记录后更新,并进行后置验证。 |
| `upsert_dns` | 不存在则创建,不同则更新,相同则 `NOOP`。 |
| `delete_dns` | 删除记录;必须传入 `confirm_delete: true`。 |

写工具参数与 CLI 对应:`type`、`name`、`content`、`ttl`、`proxied`、`dry_run`、`allow_root`、`allow_sensitive`。`delete_dns` 还要求 `confirm_delete: true`。工具参数中不接受 Token。

Agent 首先应使用 `dry_run: true`,确认返回的目标记录后才发起真实写入。`delete_dns` 即使在 Dry Run 下也必须显式设置 `confirm_delete: true`。

## 测试

运行本地单元测试:

```bash
python3 -m unittest discover -v
```

测试使用模拟 Cloudflare Client,不会读取 Token 或修改真实 DNS。

TDQS

A3.7/5.0

Scored across 6 tools

Disambiguation4/5

The verbs clearly separate list/get/create/update/upsert/delete, and descriptions clarify each tool's scope. Minor overlap exists between list_dns with a name filter and get_dns, and create_dns vs upsert_dns could be confused by an agent not reading carefully, but the intended boundaries are discernible.

Naming Consistency5/5

All tools follow a consistent verb_dns pattern: list, get, create, update, upsert, delete. This makes the tool surface highly predictable and easy to reason about.

Tool Count5/5

Six tools cover the core DNS record lifecycle without unnecessary bulk. The count is well-scoped for a focused domain-manager server.

Completeness4/5

The set provides full CRUD plus idempotent upsert and post-update verification, which covers the primary workflow. However, descriptions repeatedly instruct agents to prefer dry_run first, but no dry_run tool is exposed, leaving a notable referenced capability missing.

Maintenance

ActivityMaintained
ResponsivenessNo issues