SDK tutorial · 9 of 10
Capture and read artifacts
Artifacts are durable generated values with metadata and content addressing. They let the model and product refer to a result without copying a large document through every tool response and turn.
Customization depth
Level 4 · Durable generated results
Hosting depth
Local files or injected artifact repository
Documentation status
Supported SDK boundary
Assumptions
- An MCP server may generate source, HTML, JSON, documents, or other large text values.
- The product needs to inspect or reuse generated content after the producing turn.
- Artifact metadata and content remain protected by the product's conversation authorization.
- Create artifact IDs and metadata, track current artifact pointers, and expose artifact tools to the agent.
- Automatically capture configured large MCP result fields and replace mirrors with compact references.
- Read and list artifacts through the engine's resolved repository and root.
- Choose which outputs should become artifacts and how authorized users download or apply them.
- Provide retention, encryption, content validation, and storage compatible with Heddle's current synchronous artifact port, or return a product-owned remote reference.
- Project safe metadata instead of exposing internal content keys or filesystem paths.
Start with automatic MCP result capture
For an MCP extension that returns generated text, HTML, JSON, or document bodies:
const prepared = await prepareMcpHostExtension({
id: 'document-operations',
workspaceRoot,
stateRoot,
serverId: 'documents',
server,
resultArtifacts: true,
})Automatic capture traverses the MCP result, saves sufficiently large strings, infers common kinds, and replaces duplicate text/structured mirrors with the same compact artifact reference. It handles the common MCP shape where a text field repeats serialized structured content.
Start with the boolean option. Tune it only after observing real output:
resultArtifacts: {
auto: {
minChars: 1200,
domain: 'document',
maxPreviewChars: 800,
},
}Path hints and manual rules are advanced overrides for stable server-specific result shapes. Avoid coupling a first integration to guessed nested paths.
Read artifacts from the engine boundary
const artifacts = engine.artifacts.list({ sessionId })
const readResult = engine.artifacts.read(artifactId)
if (readResult) {
console.log(readResult.artifact)
console.log(readResult.content)
}Use engine.artifacts rather than constructing another ArtifactService against stateRoot/artifacts. A host extension or injected repository can change the resolved location.
Understand turn-result artifact scope
result.artifacts is the artifact list currently associated with the session. It is not limited to newly created artifacts from that turn. Use artifact IDs, timestamps, domains, kinds, or your own product record to distinguish new and previously accumulated outputs.
result.toolResults remains scoped to completed tool calls from the current turn.
Compact replacement shape
When automatic capture replaces a large value, the tool result contains metadata equivalent to:
{
artifact,
contentPath,
preview,
omittedCharacters,
}The full content remains available through Heddle's artifact reader/tool path. The preview helps the model understand the value without reloading it in full.
Native tool behavior
resultArtifacts is MCP host-extension capture; it does not automatically convert arbitrary native-tool output. For a native tool backed by your own asynchronous document store, save the value there and return a compact authorized reference:
execute: async (input) => {
const document = await productDocuments.create(input)
return {
ok: true,
output: { documentId: document.id, preview: document.preview },
}
}If the value must become a Heddle artifact, use the synchronous engine.artifacts.saveText(...) host boundary deliberately and account for the storage constraint explained in Use your own storage.
Production considerations
- authorize every artifact read using the owning product conversation or record;
- validate generated content before applying it to a user-visible product object;
- set retention and deletion policy for both metadata and content;
- keep repository content keys and local paths out of public response schemas.