Skip to content

制品传递 (Artefact Hand-Off)

Issue: #349Crate: dcc-mcp-artefactScheme: artefact://sha256/<hex>

流水线在工具之间以及工作流步骤之间传递文件:导入的场景、 质检报告、暂存的 .uasset、烘焙的模拟。内联传递原始字节会 膨胀 MCP 传输;传递绝对路径会跨机器中断并丢失 MIME / 大小 / 校验和元数据。

dcc-mcp-artefact 提供一个小型值类型(FileRef)加上一个 内容寻址存储后端,并将一个 artefact:// URI scheme 接入 MCP Resources 原语,使 MCP 客户端可以通过 URI resources/read 文件传递。

概念

  • FileRef — 对已存储文件的可序列化引用:

    • uri — 规范形式,例如 artefact://sha256/<hex>
    • mime, size_bytes, digest (sha256:<hex>)
    • producer_job_id(可选,用于工作流步骤输出)
    • created_at (RFC-3339)
    • metadata(工具定义的 JSON — 宽/高、帧号等)
  • ArtefactStore — trait,带有 put / get / head / delete / list。存储是内容寻址的:提交相同的字节两次会返回相同的 URI。

  • FilesystemArtefactStore — 默认持久化后端。每个制品存放在 <root>/<sha256>.bin 下,并带有一个携带 FileRef<sha256>.json sidecar。McpHttpServer 将其存储锚定在 <registry_dir>/dcc-mcp-artefacts(或当未配置注册表时的 OS 临时目录)。

  • InMemoryArtefactStore — 非持久化后端,用于测试。

启用 Artefact Resources

python
from dcc_mcp_core import McpHttpConfig, McpHttpServer, ToolRegistry

cfg = McpHttpConfig(port=8765)
cfg.enable_artefact_resources = True    # 默认关闭
server = McpHttpServer(ToolRegistry(), cfg)
handle = server.start()

一旦启用:

  • resources/list 将每个已存储的制品作为 artefact:// URI 包含在内。
  • resources/read 以正确的 MIME 类型返回 body,作为 base64 blob。
  • 未知 URI 的 resources/read 返回 MCP 错误 -32002

禁用(默认)路径仍然识别该 scheme 并以 -32002 "not enabled" 错误响应,因此客户端可以区分 "scheme unknown" 和 "scheme recognized but backing store off"。

Python 辅助函数

python
from dcc_mcp_core import (
    FileRef,
    artefact_put_bytes,
    artefact_put_file,
    artefact_get_bytes,
    artefact_list,
)

# 将磁盘上的文件放入并获取 FileRef。
ref = artefact_put_file("/tmp/render.png", mime="image/png")
print(ref.uri)           # artefact://sha256/<hex>
print(ref.digest)        # sha256:<hex>
print(ref.size_bytes)    # 1024

# 往返一个字节缓冲区。
bref = artefact_put_bytes(b"hello", mime="text/plain")
assert artefact_get_bytes(bref.uri) == b"hello"

# 清单。
for entry in artefact_list():
    print(entry.uri, entry.mime, entry.size_bytes)

辅助函数目标是一个进程级默认存储 (<temp_dir>/dcc-mcp-artefacts)。在服务器进程内部, McpHttpServer 会自动将辅助函数指向它自己的存储。

Rust API

rust
use dcc_mcp_artefact::{
    ArtefactBody, ArtefactFilter, ArtefactStore,
    FilesystemArtefactStore, InMemoryArtefactStore,
    put_bytes, put_file,
};

// 持久化存储 — 真实服务器的默认选项。
let store = FilesystemArtefactStore::new_in("/var/cache/dcc/artefacts")?;
let fr = put_bytes(&store, b"payload".to_vec(), Some("text/plain".into()))?;
assert!(fr.uri.starts_with("artefact://sha256/"));

// 通过 URI 查找。
let body = store.get(&fr.uri)?.unwrap();
assert_eq!(body.into_bytes()?, b"payload");

// 按生产作业筛选列出制品。
let refs = store.list(ArtefactFilter {
    producer_job_id: Some(job_id),
    ..Default::default()
})?;

工作流集成

工作流运行器通过步骤输出传播 FileRef

  1. 一个步骤发出一个 ToolResult,其 context 包含 {"file_refs": [{"uri": "artefact://sha256/...", "mime": "image/png"}]}
  2. 运行器将 FileRef 存储在步骤记录上,并将其替换到下一步骤的 参数上下文中。
  3. 下游步骤通过 artefact_get_bytes(uri) 获取字节 — 或者当从 运行器进程外部使用 MCP resources 原语时通过 resources/read 获取。

本 PR 落地了类型、存储和 resource 接线。运行器集成超出范围。

注意事项

  • 重复内容 → 相同 URI。 不要依赖 URI 的唯一性进行逻辑排序 — 改用 producer_job_idmetadata
  • put_file 会复制。 源路径保持不动;存储拥有规范副本。
  • Sidecar 对元数据是权威的。 手动编辑 JSON sidecar 是支持的; 编辑 .bin 文件则不支持(digest 会不匹配)。
  • 尚无 GC。 存储永远不会自动删除。TTL / 引用计数 GC 在一个 未来的 issue 中追踪。
  • 尚无远程后端。 S3 / SFTP / HTTP 指针已声明在路线图中但尚未 实现 — 一个未来的 issue。

参见

  • docs/api/resources.md — 承载 artefact:// 的 更广泛的 Resources 原语。
  • Issue #348 — 消费 FileRef 的工作流运行器。
  • Issue #350 — Resources 原语(已合并)。

Released under the MIT License.