turbomcp_protocol/types/content.rs
1//! Message content types
2//!
3//! This module contains all content block types used in MCP messages.
4//! Content blocks allow rich message composition with text, images, audio,
5//! and resource references.
6//!
7//! # Content Types
8//!
9//! - [`ContentBlock`] - Content block enum (text, image, audio, resource link, embedded resource)
10//! - [`TextContent`] - Plain text content with annotations
11//! - [`ImageContent`] - Base64-encoded image content
12//! - [`AudioContent`] - Base64-encoded audio content
13//! - [`ResourceLink`] - Reference to external resource
14//! - [`EmbeddedResource`] - Embedded resource content
15//! - [`ContentType`] - Content type enumeration (JSON/Binary/Text)
16
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19
20use super::core::{Annotations, Base64String, MimeType, Uri};
21
22/// Content type enumeration
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
24#[serde(rename_all = "lowercase")]
25pub enum ContentType {
26 /// JSON content
27 Json,
28 /// Binary content
29 Binary,
30 /// Plain text content
31 Text,
32}
33
34/// Content block union type
35///
36/// - MCP 2025-11-25: text, image, audio, resource_link, resource
37/// - MCP 2025-11-25 draft (SEP-1577): + tool_use, tool_result
38#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(tag = "type")]
40pub enum ContentBlock {
41 /// Text content
42 #[serde(rename = "text")]
43 Text(TextContent),
44 /// Image content
45 #[serde(rename = "image")]
46 Image(ImageContent),
47 /// Audio content
48 #[serde(rename = "audio")]
49 Audio(AudioContent),
50 /// Resource link
51 #[serde(rename = "resource_link")]
52 ResourceLink(ResourceLink),
53 /// Embedded resource
54 #[serde(rename = "resource")]
55 Resource(EmbeddedResource),
56 /// Tool use (MCP 2025-11-25 draft, SEP-1577)
57 #[serde(rename = "tool_use")]
58 ToolUse(ToolUseContent),
59 /// Tool result (MCP 2025-11-25 draft, SEP-1577)
60 #[serde(rename = "tool_result")]
61 ToolResult(ToolResultContent),
62}
63
64/// Text content per the current MCP specification
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct TextContent {
67 /// The text content of the message
68 pub text: String,
69 /// Optional annotations for the client
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub annotations: Option<Annotations>,
72 /// General metadata field for extensions and custom data
73 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
74 pub meta: Option<HashMap<String, serde_json::Value>>,
75}
76
77/// Image content per the current MCP specification
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct ImageContent {
80 /// The base64-encoded image data
81 pub data: Base64String,
82 /// The MIME type of the image. Different providers may support different image types
83 #[serde(rename = "mimeType")]
84 pub mime_type: MimeType,
85 /// Optional annotations for the client
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub annotations: Option<Annotations>,
88 /// General metadata field for extensions and custom data
89 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
90 pub meta: Option<HashMap<String, serde_json::Value>>,
91}
92
93/// Audio content per the current MCP specification
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct AudioContent {
96 /// The base64-encoded audio data
97 pub data: Base64String,
98 /// The MIME type of the audio. Different providers may support different audio types
99 #[serde(rename = "mimeType")]
100 pub mime_type: MimeType,
101 /// Optional annotations for the client
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub annotations: Option<Annotations>,
104 /// General metadata field for extensions and custom data
105 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
106 pub meta: Option<HashMap<String, serde_json::Value>>,
107}
108
109/// Resource link per the current MCP specification
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct ResourceLink {
112 /// Resource name (programmatic identifier)
113 pub name: String,
114 /// Display title for UI contexts (optional, falls back to name if not provided)
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub title: Option<String>,
117 /// The URI of this resource
118 pub uri: Uri,
119 /// A description of what this resource represents
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub description: Option<String>,
122 /// The MIME type of this resource, if known
123 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
124 pub mime_type: Option<MimeType>,
125 /// Optional annotations for the client
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub annotations: Option<Annotations>,
128 /// The size of the raw resource content, if known
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub size: Option<u64>,
131 /// General metadata field for extensions and custom data
132 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
133 pub meta: Option<HashMap<String, serde_json::Value>>,
134}
135
136/// Embedded resource content per the current MCP specification
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct EmbeddedResource {
139 /// The embedded resource content (text or binary)
140 pub resource: ResourceContent,
141 /// Optional annotations for the client
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub annotations: Option<Annotations>,
144 /// General metadata field for extensions and custom data
145 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
146 pub meta: Option<HashMap<String, serde_json::Value>>,
147}
148
149/// Text resource contents
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct TextResourceContents {
152 /// The URI of this resource
153 pub uri: Uri,
154 /// The MIME type of this resource, if known
155 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
156 pub mime_type: Option<MimeType>,
157 /// The text content (must only be set for text-representable data)
158 pub text: String,
159 /// General metadata field for extensions and custom data
160 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
161 pub meta: Option<HashMap<String, serde_json::Value>>,
162}
163
164/// Binary resource contents
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct BlobResourceContents {
167 /// The URI of this resource
168 pub uri: Uri,
169 /// The MIME type of this resource, if known
170 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
171 pub mime_type: Option<MimeType>,
172 /// Base64-encoded binary data
173 pub blob: Base64String,
174 /// General metadata field for extensions and custom data
175 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
176 pub meta: Option<HashMap<String, serde_json::Value>>,
177}
178
179/// Union type for resource contents (text or binary)
180#[derive(Debug, Clone, Serialize, Deserialize)]
181#[serde(untagged)]
182pub enum ResourceContent {
183 /// Text resource content
184 Text(TextResourceContents),
185 /// Binary resource content
186 Blob(BlobResourceContents),
187}
188
189/// Tool use content (MCP 2025-11-25 draft, SEP-1577)
190///
191/// Represents a request from the LLM to call a tool during sampling.
192/// The model wants to execute a function and receive its results.
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct ToolUseContent {
195 /// A unique identifier for this tool use
196 /// This ID is used to match tool results to their corresponding tool uses
197 pub id: String,
198
199 /// The name of the tool to call
200 pub name: String,
201
202 /// The arguments to pass to the tool, conforming to the tool's input schema
203 pub input: serde_json::Value,
204
205 /// Optional metadata about the tool use
206 /// Clients SHOULD preserve this field when including tool uses in subsequent
207 /// sampling requests to enable caching optimizations
208 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
209 pub meta: Option<HashMap<String, serde_json::Value>>,
210}
211
212/// Tool result content (MCP 2025-11-25 draft, SEP-1577)
213///
214/// Represents the result of executing a tool that was requested by the LLM.
215/// The server provides the tool execution results back to the model.
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct ToolResultContent {
218 /// The ID of the tool use this result corresponds to
219 /// This MUST match the ID from a previous ToolUseContent
220 #[serde(rename = "toolUseId")]
221 pub tool_use_id: String,
222
223 /// The unstructured result content of the tool use
224 /// Can include text, images, audio, resource links, and embedded resources
225 pub content: Vec<ContentBlock>,
226
227 /// An optional structured result object
228 /// If the tool defined an outputSchema, this SHOULD conform to that schema
229 #[serde(rename = "structuredContent", skip_serializing_if = "Option::is_none")]
230 pub structured_content: Option<serde_json::Value>,
231
232 /// Whether the tool use resulted in an error
233 /// If true, the content typically describes the error that occurred
234 /// Default: false
235 #[serde(rename = "isError", skip_serializing_if = "Option::is_none")]
236 pub is_error: Option<bool>,
237
238 /// Optional metadata about the tool result
239 /// Clients SHOULD preserve this field when including tool results in subsequent
240 /// sampling requests to enable caching optimizations
241 #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
242 pub meta: Option<HashMap<String, serde_json::Value>>,
243}