Skip to content

rust(feat): create_artifact uploads file content - #768

Draft
lineville wants to merge 4 commits into
mainfrom
artifact-upload-bytes
Draft

rust(feat): create_artifact uploads file content#768
lineville wants to merge 4 commits into
mainfrom
artifact-upload-bytes

Conversation

@lineville

@lineville lineville commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

create_artifact gains file_path. The MCP server streams the file to POST /api/v0/remote-files/upload (entity type artifact_versions, entity id = the new version), then returns the refreshed artifact with file_name, file_mime_type, remote_file_id, and a signed download_url.

  • The multipart part declares a mime type from the extension via mime_guess, with application/octet-stream as the fallback. The server's own table misses .md, .py, and .parquet.
  • Client checks: a regular non-empty file up to 1 GiB, name up to 255 bytes.
  • A failed upload names the created version and tells the agent not to retry the create. The success note claims a preview only when the response carries a download_url.
  • RestConfig is plumbed CLI → lib → server → ArtifactService. Uploads are essential traffic and ignore --disable-nonessential-traffic.
  • rmcp 3.2.0: a legacy initialize naming 2026-07-28 is now answered with 2025-11-25. Two handshake tests updated.

Closes #766. Consumed by sift-stack/azimuth#13949.

Verification

cargo test -p sift_mcp: 516 pass. Clippy is clean apart from two pre-existing warnings. Built as 0.5.0 and exercised end to end in the azimuth kind cluster.

`create_artifact` gains a `file_path` parameter. The MCP server streams
the file to the remote-files multipart endpoint as the new version's
content (entity type artifact_versions), then returns the refreshed
artifact with its file name, mime type, remote_file_id, and a signed
download_url. Without bytes an artifact card has nothing to preview or
download, so the skill now tells agents to always pass a file.

- New RemoteFileUploader / RestConfig in sift_mcp; the CLI passes its
  rest_uri + api key through unconditionally (uploads are essential
  traffic, unlike client events).
- Client-side caps: regular non-empty files up to 1 GiB, file names up
  to 255 bytes. The server derives the mime type from the extension.
- A failed upload names the created artifact and warns the agent not to
  re-create it, since the metadata row already exists.

Claude-Session: https://claude.ai/code/session_01TASwZHqUw2JgEbiBCZT3s7
@lineville
lineville force-pushed the artifact-upload-bytes branch from 0709294 to b7ca08b Compare August 31, 2026 18:00
…note

The multipart part sent no Content-Type, so the server fell back to Go's
built-in extension table, which does not know .md, .py, .parquet, .yaml or
.ipynb. Those uploads landed with an empty file_mime_type and the file
viewer treated them as download-only. The part now declares a type from
mime_guess, with application/octet-stream as the fallback.

create_artifact's next_step also claimed the user could preview and
download the file even when the post-upload refresh or download-link call
failed silently. The note now follows what the response carries and points
the agent at download_artifact when the link is missing.

Claude-Session: https://claude.ai/code/session_016QEngHzSkPxFT1BQqExiAH
rmcp 3.2.0 no longer answers a legacy initialize that names 2026-07-28
with that version; it negotiates down to the newest legacy version,
2025-11-25, since 2026-07-28 has no handshake. Cargo.lock is untracked,
so CI resolved 3.2.0 and two handshake tests failed. Raise the
requirement so local builds match, and assert the negotiated version and
legacy list shape in those tests.

Claude-Session: https://claude.ai/code/session_016QEngHzSkPxFT1BQqExiAH
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.

1 participant