Skip to content

feat: create user files from scoped MCP tool artifacts - #838

Open
Stella-sea wants to merge 5 commits into
DEEIX-AI:devfrom
Stella-sea:feat/mcp-file-create-818
Open

Stella-sea wants to merge 5 commits into
DEEIX-AI:devfrom
Stella-sea:feat/mcp-file-create-818

Conversation

@Stella-sea

Copy link
Copy Markdown
Contributor

Summary

关联 #818。

这是 create-only 的可运行 Draft 实现提案,供维护者评审授权契约;不代表 #818 的协议已获上游批准,也不建议未经评审直接启用。

外部 MCP 生成完成的文件,可以在本次已登记工具调用授权内直接创建为当前用户的 DEEIX 正式文件对象,进入已有文件列表和配额/处理流程,不需要用户先下载再手工上传。

基线:dev@19d60fec8f9356a4bdd997e8b71a5a8a9a0baec9。

最小契约

  • 管理员通过已有 MCP 管理 API 显式设置 fileCreateEnabled: true,默认关闭。首版是管理员授权后的自动创建,不把模型 confirm=true 当成用户确认;临时聊天、附件预处理和发现不签发授权。
  • DEEIX 在实际 tools/call 前签发 32 字节随机、10 分钟有效的一文件 capability,仅通过 X-Deeix-File-Create-Token 发给登记服务。数据库仅保存哈希,绑定服务、目标用户、工具、调用 ID 和撤销代数。现有共享 HMAC 上下文、出站 MCP token、用户 JWT 都不是反向凭证。
  • POST /api/v1/mcp/servers/{id}/files 接收唯一一个限量 multipart file,归属完全由 capability 确定,拒绝额外字段/用户 ID/URL。复用 UploadService 文件策略、对象存储 port、文件元数据及配额事务。
  • 同一次自动工具重试沿用 capability。首次通过文件策略的上传固定摘要/元数据;同凭证同文件返回原 file_id,改变内容/名称/MIME 返回冲突。内容 reused 与请求 replayed 分开表示。
  • receipt 完成、文件行与配额在同一事务结算。候选 key 在对象 I/O 前持久化,Put/提交确认丢失时保留并恢复同一个 key,避免误删已提交文件或重复计费。
  • 服务连接配置/授权/状态变化撤销旧 capability;停用用户、工具或全局 MCP 会永久失效相关授权,重新启用不恢复。验证检查当前持久化状态;数据库错误失败关闭。
  • 返回实际数据库处理状态;创建不等于提取、OCR 或 RAG 完成。有界维护恢复 receipt 到已有处理队列的交接,memory/Redis 已有队列对未结算文件任务去重,初始化用条件更新避免重置 worker。
  • 沿用既有审计与限流,审计识别服务、目标用户和调用,不记录 capability/文件内容。没有新增模型调用、规划、tools loop、通用权限平台、新队列、文件读写同步协议或 UI 卡片。

Change type

  • Bug fix
  • Feature
  • Documentation
  • Refactor
  • Configuration / deployment
  • Security hardening
  • Other

Affected areas

  • Frontend / UI
  • Backend / API
  • Authentication / authorization
  • Conversations / streaming
  • Files / RAG / extraction
  • Model routing / providers
  • MCP / tools
  • Billing / payments
  • Admin console
  • Deployment / Docker / configuration
  • Documentation

管理员开关通过已有 API 配置;未增加前端设置页,前端仅补齐新错误码翻译。

Verification

最终版本已通过:

  • make lint test(backend 工作目录;等同 make -C backend lint test):Linux 容器内 Go 1.26.8,包含 gofmt、go vet、staticcheck、deadcode、完整 go test ./...。
  • go test -race ./...:同一 Linux Go 1.26.8 环境完整通过。
  • go build ./...。
  • go build -tags nopostgres,noredis,nos3,noswagger,nomsgpack,nootlp ./...。
  • CI sidecar tag 集对应的 tracing/openwebui/persistence 测试。
  • 真实 PostgreSQL 17 + pgvector:两个独立应用/DB 连接并发提交,仅一次文件/配额结算。
  • 真实专用 Redis 7:重复恢复入队、重入队、结算、DLQ、embedding stream ID 碰撞和 invalid-message marker 清理。
  • pnpm api:generate、pnpm api:check。
  • pnpm turbo run check --filter=@deeix/web --filter=./packages/* --env-mode=loose。
  • pnpm --filter @deeix/web build。
  • packages/core 的 40 个 Node 测试(Node 24 Linux 容器)。
  • git diff --check、相对 dev 的完整差异检查、独立只读安全审查。

聚焦回归覆盖:用户归属与列表/配额、正常创建和重放、错服务/伪造 token/共享 HMAC 不能授权、过期与撤销后重新启用、连接快照失效、大小/类型/配额拒绝、跨实例并发、Put/提交响应丢失、事务回滚、过期候选清理/失败重试/跨用户引用保护、真实处理恢复及浏览器初始化竞态、审计凭据/内容隔离、调用重试和 discovery/redirect 凭证边界。

环境限制已绕过:Windows 根级 pnpm check 因缺少 make 失败;本机 Node 22 无法直接运行现有 .ts 测试。后端在独立 Linux checkout 用仓库锁定 Go 版本完成原检查,Node 测试在 CI 使用的 Node 24 完成。未运行完整 Rust 桌面 cargo check 或桌面打包;已完成 Go sidecar tag 构建/测试。现有 CI 未自动设置集成测试 DSN,因此 PostgreSQL/Redis 特定测试在普通 CI 会跳过,本地实测结果如上。

  • Not run; reason:

Screenshots, API examples, or logs

外部服务的 DEEIX 地址与登记服务 ID 由部署者配置,不从模型参数或 Host 推断:

curl --fail-with-body \
  -H "Authorization: Bearer $DEEIX_FILE_CREATE_TOKEN" \
  -F 'file=@report.txt;type=text/plain' \
  'https://chat.example/api/v1/mcp/servers/42/files'
{
  "errorMsg": "",
  "data": {
    "file_id": "file_example",
    "file_name": "report.txt",
    "size_bytes": 123,
    "sha256": "<64 hex characters>",
    "reused": false,
    "replayed": false,
    "processing_status": "queued",
    "extract_status": "none",
    "embed_status": "none",
    "processing_ready": false
  }
}

完整错误、幂等、部分失败及过期语义见 docs/MCP_FILE_CREATE.md。

Configuration, migration, and compatibility notes

  • 一个新的 mcp_file_create_grants receipt 表;MCP 服务新增默认关闭字段及撤销代数,由既有 schema migration 管理。
  • 现有登录 JWT /api/v1/files 鉴权不变,未授权 MCP 服务不获得 capability。
  • 没有新 YAML/env、依赖、共享存储卷、URL 拉取或反向 JWT。
  • Swagger 和 packages/api-contract/src/types.generated.ts 由生成流水线更新,未手改。
  • 对象存储与数据库不是分布式原子事务:通过持久候选 key、恢复/过期清理处理失败。最小版在有界对象 I/O 期间持有用户配额锁,可能限制单用户并发吞吐。
  • 幂等回放窗口为 capability 的 10 分钟有效期;过期后通过用户既有文件列表确认结果。取消聊天/浏览器注销不提前撤销独立 capability。
  • 审计沿用原服务的独立写入,提交后进程退出仍有缺失成功审计窗口;本 PR 没有构建 audit outbox,也不承诺审计与文件事务原子。

请维护者决定

  1. 是否接受管理员按服务授权后自动创建的 v1,以及临时聊天/附件预处理不授权。
  2. 是否接受每调用一文件、10 分钟 bearer capability、端点/头名称与回放窗口。
  3. 合并前是否需要管理员 UI,或将成功审计进一步与结算原子记录。

Documentation

  • Documentation is not needed for this change.
  • Documentation was updated.
  • Documentation still needs to be updated.

新增 docs/MCP_FILE_CREATE.md,明确这是待评审契约,backend README 增加入口。

Security and privacy

  • No secrets, tokens, credentials, local config, or personal data are included.
  • User data access remains scoped by authenticated user context unless an admin-only path explicitly requires broader access.
  • Security-sensitive behavior was reviewed, including authentication, authorization, provider routing, file processing, billing, and admin APIs where relevant.

Checklist

  • I searched existing issues and pull requests.
  • Changes are focused and do not include unrelated refactors.
  • Tests or static verification were run where practical.
  • User-facing behavior, deployment steps, API contracts, or configuration changes are documented.
  • Generated artifacts are included only when this project explicitly requires them.
  • Caches, build output, .pyc files, .env files, and local storage data are not committed.

Comment thread backend/internal/infra/cache/redis/conversation_cache.go Fixed
@Stella-sea
Stella-sea marked this pull request as ready for review October 6, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants