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 per MCP 2025-06-18 specification
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(tag = "type")]
37pub enum ContentBlock {
38    /// Text content
39    #[serde(rename = "text")]
40    Text(TextContent),
41    /// Image content
42    #[serde(rename = "image")]
43    Image(ImageContent),
44    /// Audio content
45    #[serde(rename = "audio")]
46    Audio(AudioContent),
47    /// Resource link
48    #[serde(rename = "resource_link")]
49    ResourceLink(ResourceLink),
50    /// Embedded resource
51    #[serde(rename = "resource")]
52    Resource(EmbeddedResource),
53}
54
55/// Compatibility alias for the old Content enum
56pub type Content = ContentBlock;
57
58/// Text content per MCP 2025-06-18 specification
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct TextContent {
61    /// The text content of the message
62    pub text: String,
63    /// Optional annotations for the client
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub annotations: Option<Annotations>,
66    /// General metadata field for extensions and custom data
67    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
68    pub meta: Option<HashMap<String, serde_json::Value>>,
69}
70
71/// Image content per MCP 2025-06-18 specification
72#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct ImageContent {
74    /// The base64-encoded image data
75    pub data: Base64String,
76    /// The MIME type of the image. Different providers may support different image types
77    #[serde(rename = "mimeType")]
78    pub mime_type: MimeType,
79    /// Optional annotations for the client
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub annotations: Option<Annotations>,
82    /// General metadata field for extensions and custom data
83    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
84    pub meta: Option<HashMap<String, serde_json::Value>>,
85}
86
87/// Audio content per MCP 2025-06-18 specification
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct AudioContent {
90    /// The base64-encoded audio data
91    pub data: Base64String,
92    /// The MIME type of the audio. Different providers may support different audio types
93    #[serde(rename = "mimeType")]
94    pub mime_type: MimeType,
95    /// Optional annotations for the client
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub annotations: Option<Annotations>,
98    /// General metadata field for extensions and custom data
99    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
100    pub meta: Option<HashMap<String, serde_json::Value>>,
101}
102
103/// Resource link per MCP 2025-06-18 specification
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct ResourceLink {
106    /// Resource name (programmatic identifier)
107    pub name: String,
108    /// Display title for UI contexts (optional, falls back to name if not provided)
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub title: Option<String>,
111    /// The URI of this resource
112    pub uri: Uri,
113    /// A description of what this resource represents
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub description: Option<String>,
116    /// The MIME type of this resource, if known
117    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
118    pub mime_type: Option<MimeType>,
119    /// Optional annotations for the client
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub annotations: Option<Annotations>,
122    /// The size of the raw resource content, if known
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub size: Option<u64>,
125    /// General metadata field for extensions and custom data
126    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
127    pub meta: Option<HashMap<String, serde_json::Value>>,
128}
129
130/// Embedded resource content per MCP 2025-06-18 specification
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct EmbeddedResource {
133    /// The embedded resource content (text or binary)
134    pub resource: ResourceContent,
135    /// Optional annotations for the client
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub annotations: Option<Annotations>,
138    /// General metadata field for extensions and custom data
139    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
140    pub meta: Option<HashMap<String, serde_json::Value>>,
141}
142
143/// Text resource contents
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct TextResourceContents {
146    /// The URI of this resource
147    pub uri: Uri,
148    /// The MIME type of this resource, if known
149    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
150    pub mime_type: Option<MimeType>,
151    /// The text content (must only be set for text-representable data)
152    pub text: String,
153    /// General metadata field for extensions and custom data
154    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
155    pub meta: Option<HashMap<String, serde_json::Value>>,
156}
157
158/// Binary resource contents
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct BlobResourceContents {
161    /// The URI of this resource
162    pub uri: Uri,
163    /// The MIME type of this resource, if known
164    #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
165    pub mime_type: Option<MimeType>,
166    /// Base64-encoded binary data
167    pub blob: Base64String,
168    /// General metadata field for extensions and custom data
169    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
170    pub meta: Option<HashMap<String, serde_json::Value>>,
171}
172
173/// Union type for resource contents (text or binary)
174#[derive(Debug, Clone, Serialize, Deserialize)]
175#[serde(untagged)]
176pub enum ResourceContent {
177    /// Text resource content
178    Text(TextResourceContents),
179    /// Binary resource content
180    Blob(BlobResourceContents),
181}