Files
smartmate/infra/smartflow-mcp-server
LoveLosita 1ed558b488 Version: 0.4.8.dev.260308
feat: 🏗️ 实现 Agent 消息可靠异步持久化(Outbox + Kafka)

* 新增 Outbox 数据模型与消息载荷定义,位于 `backend/model/outbox.go`
* 新增 Outbox DAO,支持创建、扫描、发布标记、失败重试与消费落库事务,位于 `backend/dao/outbox.go`
* 新增 Kafka 基础封装,包含配置、生产者、消费者与消息包装,位于 `backend/kafka` 文件夹

  * `config.go`:Kafka 配置文件
  * `producer.go`:Kafka 生产者
  * `consumer.go`:Kafka 消费者
  * `envelope.go`:消息封装处理
* 新增异步管道服务,处理扫描投递与消费落库,位于 `backend/service/agent_async_pipeline.go`
* 接入 Agent 聊天链路的可靠持久化,替换原有 goroutine 直接写库逻辑,位于 `backend/service/agent.go`
* 启动流程接入管道初始化与启动,位于 `backend/cmd/start.go`
* 增加 Kafka 配置项,更新 `backend/config.yaml` 与 `backend/config.example.yaml`
* 引入 Kafka 依赖:`github.com/segmentio/kafka-go`(见 `backend/go.mod`, `backend/go.sum`)

fix: 🐛 修复首启偶发 user 消息重复落库问题

* 解决因 Outbox 状态并发回写竞态,导致 `consumed` 被晚到的 `published` 覆盖的问题
* 在 `MarkPublished` 中增加条件,避免覆盖已标记为 `consumed` 或 `dead` 的消息,修复位置:`backend/dao/outbox.go`

perf:  更新 Docker Compose 配置与 Kafka 相关服务

* 更新 `docker-compose.yml` 文件,新增 Kafka 配置与服务

fix: 🧹 优化缓存删除逻辑

* 在 `cache deleter` 中忽略了 `model.AgentOutboxMessage`、`model.ChatHistory` 与 `model.AgentChat` 这三个结构体
* 防止这些结构体对应的表单删除缓存时,导致控制台消息爆炸
2026-03-08 12:53:54 +08:00
..
2026-03-07 15:25:40 +08:00
2026-03-07 15:25:40 +08:00
2026-03-07 15:25:40 +08:00
2026-03-08 12:53:54 +08:00
2026-03-07 15:25:40 +08:00
2026-03-07 15:25:40 +08:00
2026-03-07 15:25:40 +08:00
2026-03-08 12:53:54 +08:00

smartflow-mcp-server (MVP)

用于让 Codex 通过 MCPstdio只读访问 MySQL 与 Redis面向接口联调与测试。

1. 功能范围(第一阶段)

只实现 3 个只读工具:

  1. mysql_query_readonly
  2. redis_get
  3. redis_scan

未实现任何写操作工具。

2. 目录结构

infra/smartflow-mcp-server
├─ cmd/server/main.go
├─ internal
│  ├─ audit
│  ├─ config
│  ├─ envutil
│  ├─ mcp
│  ├─ ratelimit
│  ├─ security
│  ├─ store
│  └─ tools
├─ .env.example
├─ go.mod
└─ README.md

3. 快速启动

go mod tidy
go test ./...
go run ./cmd/server

服务采用 stdio MCP 协议,不会启动 HTTP 端口。

4. 配置说明(全部来自环境变量)

复制并编辑:

cp .env.example .env

关键变量:

  • MYSQL_HOST / MYSQL_PORT / MYSQL_USER / MYSQL_PASSWORD / MYSQL_DATABASE
  • REDIS_ADDR / REDIS_PASSWORD / REDIS_DB
  • MYSQL_ALLOWED_DATABASES:逗号分隔
  • MYSQL_ALLOWED_TABLES:逗号分隔,支持 db.tabletable;留空表示允许所有表
  • MCP_ENFORCE_WHITELISTtrue 时无明确表引用会拒绝执行
  • MCP_TOOL_TIMEOUT_MS:单次工具调用超时
  • MCP_RATE_LIMIT_RPS + MCP_RATE_LIMIT_BURST:基础令牌桶限流
  • MCP_MAX_RESULT_ROWSMySQL 最大返回行数
  • MCP_REDIS_SCAN_MAX_KEYSredis_scan 最大返回 key 数
  • MCP_AUDIT_LOG_PATH:审计日志路径

5. 工具说明

5.1 mysql_query_readonly

输入:

{
  "sql": "SELECT id, name FROM users WHERE id = ?",
  "params": [1]
}

安全限制:

  • 仅允许 SELECT / SHOW / DESCRIBE / EXPLAIN
  • 禁止分号 ;(多语句)
  • 禁止注释 -- / # / /* */
  • 禁止 DDL/DML 关键字(INSERT/UPDATE/DELETE/ALTER/DROP/TRUNCATE 等)
  • 支持库/表白名单校验

输出(结构化):

  • columns
  • rows
  • rowCount
  • truncated
  • durationMs

5.2 redis_get

输入:

{
  "key": "user:1001"
}

输出:

  • exists
  • key
  • type
  • value
  • truncated
  • durationMs

5.3 redis_scan

输入:

{
  "pattern": "user:*",
  "count": 50
}

输出:

  • pattern
  • keys
  • returned
  • nextCursor
  • truncated
  • durationMs

6. 审计日志

每次工具调用会记录JSON 行格式):

  • 时间
  • 工具名
  • 调用方caller
  • 是否成功
  • 耗时
  • 脱敏后的输入摘要
  • 错误信息(截断)

敏感字段处理:

  • SQL 字符串字面量与数字会脱敏
  • Redis key 仅保留前后少量字符

7. Codex MCP 配置示例stdio

可按客户端配置格式接入,示例:

{
  "mcpServers": {
    "smartflow-db-readonly": {
      "command": "go",
      "args": ["run", "./cmd/server"],
      "cwd": "E:/SmartFlow-Agent/infra/smartflow-mcp-server",
      "env": {
        "MYSQL_HOST": "127.0.0.1",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "readonly_user",
        "MYSQL_PASSWORD": "replace_me",
        "MYSQL_DATABASE": "smartflow",
        "MYSQL_ALLOWED_DATABASES": "smartflow",
        "MYSQL_ALLOWED_TABLES": "",
        "REDIS_ADDR": "127.0.0.1:6379",
        "REDIS_DB": "0",
        "MCP_TOOL_TIMEOUT_MS": "5000",
        "MCP_RATE_LIMIT_RPS": "5",
        "MCP_RATE_LIMIT_BURST": "10",
        "MCP_MAX_RESULT_ROWS": "500",
        "MCP_REDIS_SCAN_MAX_KEYS": "200",
        "MCP_AUDIT_LOG_PATH": "logs/audit.log"
      }
    }
  }
}

8. 安全限制生效示例

  • SQL 多语句:SELECT 1; SELECT 2 -> 被拒绝semicolon is not allowed
  • SQL 注释绕过:SELECT * FROM users --x -> 被拒绝sql comments are not allowed
  • 写操作:DELETE FROM users -> 被拒绝dangerous sql keyword detected
  • 白名单外表:SELECT * FROM admin.secret -> 被拒绝table not in whitelist
  • Redis 大范围扫描:redis_scan 返回数量受 MCP_REDIS_SCAN_MAX_KEYS 限制

9. 风险说明MVP 已知边界)

  1. SQL 校验采用关键字与模式匹配,不是完整 SQL AST 解析,建议二阶段引入 AST 级校验。
  2. SHOW DATABASES 等无显式表引用语句在非严格模式下可执行;生产建议开启 MCP_ENFORCE_WHITELIST=true
  3. Redis 复杂类型返回做了截断保护,但仍建议在生产环境设置更小上限。

10. 常见问题FAQ

Q1: 启动时报 MYSQL_USER and MYSQL_DATABASE are required

检查环境变量是否正确加载,建议先确认 .env 存在于 infra/smartflow-mcp-server

Q2: 为什么调用工具报限流

默认启用了令牌桶限流,调大 MCP_RATE_LIMIT_RPSMCP_RATE_LIMIT_BURST 即可。

Q3: 为什么 redis_scan 返回不全

是预期行为,结果数被 MCP_REDIS_SCAN_MAX_KEYS 限制,避免全量扫描拖垮 Redis。

Q4: 审计日志在哪里

默认在 logs/audit.log,可用 MCP_AUDIT_LOG_PATH 自定义。