Artifacts¶
Artifact storage abstractions for persisting and referencing large or binary tool outputs, with in-memory and no-op implementations and auto-discovery.
artifacts
¶
Artifact storage for binary and large text content.
This module provides the ArtifactStore protocol and implementations for storing binary content (PDFs, images, etc.) and large text out-of-band, keeping only compact ArtifactRef references in LLM context.
See RFC: docs/RFC_MCP_BINARY_CONTENT_HANDLING.md
ArtifactStore
¶
Bases: Protocol
Protocol for binary/large-text artifact storage.
Implementations must be async-safe. The protocol is designed to be backend-agnostic - implementations can use memory, disk, S3, etc.
put_bytes
async
¶
put_bytes(data: bytes, *, mime_type: str | None = None, filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store binary data and return a compact reference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The binary content to store. |
required |
mime_type
|
str | None
|
MIME type of the content. |
None
|
filename
|
str | None
|
Suggested filename for downloads. |
None
|
namespace
|
str | None
|
Namespace prefix for the artifact ID (e.g., tool name). |
None
|
scope
|
ArtifactScope | None
|
Scoping information for access control. |
None
|
meta
|
dict[str, Any] | None
|
Additional metadata to include in the reference. |
None
|
Returns:
| Type | Description |
|---|---|
ArtifactRef
|
ArtifactRef with the artifact ID and metadata. |
put_text
async
¶
put_text(text: str, *, mime_type: str = 'text/plain', filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store large text and return a compact reference.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text content to store. |
required |
mime_type
|
str
|
MIME type (default: text/plain). |
'text/plain'
|
filename
|
str | None
|
Suggested filename for downloads. |
None
|
namespace
|
str | None
|
Namespace prefix for the artifact ID. |
None
|
scope
|
ArtifactScope | None
|
Scoping information for access control. |
None
|
meta
|
dict[str, Any] | None
|
Additional metadata to include in the reference. |
None
|
Returns:
| Type | Description |
|---|---|
ArtifactRef
|
ArtifactRef with the artifact ID and metadata. |
get
async
¶
get(artifact_id: str) -> bytes | None
Retrieve artifact bytes by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_id
|
str
|
The artifact ID from an ArtifactRef. |
required |
Returns:
| Type | Description |
|---|---|
bytes | None
|
The binary content, or None if not found or expired. |
get_ref
async
¶
get_ref(artifact_id: str) -> ArtifactRef | None
Retrieve artifact metadata by ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_id
|
str
|
The artifact ID. |
required |
Returns:
| Type | Description |
|---|---|
ArtifactRef | None
|
The ArtifactRef with metadata, or None if not found. |
delete
async
¶
delete(artifact_id: str) -> bool
Delete an artifact.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_id
|
str
|
The artifact ID to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if not found. |
exists
async
¶
exists(artifact_id: str) -> bool
Check if an artifact exists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_id
|
str
|
The artifact ID to check. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if the artifact exists and hasn't expired. |
list
async
¶
list(*, scope: ArtifactScope | None = None) -> list[ArtifactRef]
List artifacts matching the given scope filter.
None fields in scope = don't filter on that dimension. If scope is None, returns all artifacts.
ArtifactRef
¶
Bases: BaseModel
Compact reference to a stored artifact.
This is the only artifact-related data that should appear in LLM context. Never include raw bytes or base64 in observations - only ArtifactRef.
mime_type
class-attribute
instance-attribute
¶
mime_type: str | None = None
MIME type of the content (e.g., 'application/pdf', 'image/png').
size_bytes
class-attribute
instance-attribute
¶
size_bytes: int | None = None
Size of the artifact in bytes.
filename
class-attribute
instance-attribute
¶
filename: str | None = None
Original or suggested filename for downloads.
sha256
class-attribute
instance-attribute
¶
sha256: str | None = None
SHA-256 hash of the content for integrity verification.
scope
class-attribute
instance-attribute
¶
scope: ArtifactScope | None = None
Scoping information for access control.
namespace
class-attribute
instance-attribute
¶
namespace: str | None = None
Namespace for artifact grouping (e.g., tool name).
source
class-attribute
instance-attribute
¶
source: dict[str, Any] = Field(default_factory=dict)
Additional metadata (tool name, warnings, preview, etc.).
ArtifactScope
¶
Bases: BaseModel
Scoping information for access control.
The host (HTTP layer) enforces access control based on these fields. ArtifactStore implementations store this metadata but don't enforce access.
ArtifactRetentionConfig
¶
Bases: BaseModel
Retention policy for artifacts.
ttl_seconds
class-attribute
instance-attribute
¶
ttl_seconds: int = 3600
Artifacts expire after this many seconds. Default: 1 hour.
max_artifact_bytes
class-attribute
instance-attribute
¶
max_artifact_bytes: int = 50 * 1024 * 1024
Maximum size per artifact. Default: 50MB.
max_session_bytes
class-attribute
instance-attribute
¶
max_session_bytes: int = 500 * 1024 * 1024
Maximum total bytes per session. Default: 500MB.
max_trace_bytes
class-attribute
instance-attribute
¶
max_trace_bytes: int = 100 * 1024 * 1024
Maximum total bytes per trace. Default: 100MB.
max_artifacts_per_trace
class-attribute
instance-attribute
¶
max_artifacts_per_trace: int = 100
Maximum artifacts per trace.
max_artifacts_per_session
class-attribute
instance-attribute
¶
max_artifacts_per_session: int = 1000
Maximum artifacts per session.
cleanup_strategy
class-attribute
instance-attribute
¶
cleanup_strategy: Literal['lru', 'fifo', 'none'] = 'lru'
Strategy for evicting artifacts when limits are reached.
InMemoryArtifactStore
¶
InMemoryArtifactStore(retention: ArtifactRetentionConfig | None = None, scope_filter: ArtifactScope | None = None)
In-memory artifact store for development and testing.
Implements LRU eviction and TTL expiration. Suitable for Playground and test environments. Not suitable for production (no persistence).
Initialize the in-memory store.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
retention
|
ArtifactRetentionConfig | None
|
Retention policy configuration. |
None
|
scope_filter
|
ArtifactScope | None
|
If provided, all artifacts are scoped to this. |
None
|
put_bytes
async
¶
put_bytes(data: bytes, *, mime_type: str | None = None, filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store binary data in memory.
put_text
async
¶
put_text(text: str, *, mime_type: str = 'text/plain', filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store text as UTF-8 bytes.
list
async
¶
list(*, scope: ArtifactScope | None = None) -> list[ArtifactRef]
List artifacts matching the given scope filter.
NoOpArtifactStore
¶
NoOpArtifactStore(max_inline_preview: int = 500)
Fallback store that logs warnings but doesn't persist content.
Used when no real ArtifactStore is configured. Returns truncated references with warnings so the system continues to function.
put_bytes
async
¶
put_bytes(data: bytes, *, mime_type: str | None = None, filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store binary data (no-op: logs warning, returns truncated ref).
put_text
async
¶
put_text(text: str, *, mime_type: str = 'text/plain', filename: str | None = None, namespace: str | None = None, scope: ArtifactScope | None = None, meta: dict[str, Any] | None = None) -> ArtifactRef
Store large text (no-op: logs warning, returns truncated ref with preview).
get_ref
async
¶
get_ref(artifact_id: str) -> ArtifactRef | None
Cannot retrieve metadata from no-op store.
list
async
¶
list(*, scope: ArtifactScope | None = None) -> list[ArtifactRef]
No-op list always returns empty.
discover_artifact_store
¶
discover_artifact_store(state_store: Any) -> ArtifactStore | None
Attempt to discover ArtifactStore from state_store via duck-typing.
Checks for: 1. state_store.artifact_store attribute (preferred) 2. state_store implementing ArtifactStore protocol directly
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state_store
|
Any
|
A StateStore or similar object that might provide artifacts. |
required |
Returns:
| Type | Description |
|---|---|
ArtifactStore | None
|
An ArtifactStore if discovered, None otherwise. |