fix: use mimeType instead of mime_type for MCP specification compliance (#339)
- Fix ResourceContents enum to properly serialize with camelCase field names - Add comprehensive tests to verify JSON serialization compliance - Ensure all resource-related structs use mimeType as per MCP spec - Add tests for RawResource, ResourceContents, RawImageContent, RawAudioContent - Add test for prompt message image content serialization - Update message schema files to reflect mimeType changes - Fix import ordering to match project formatting standards This change ensures the Rust SDK is fully compliant with the MCP specification which requires mimeType (camelCase) for all resource content types.
This commit is contained in:
parent
cdea86fb17
commit
7ba1ac4959
5 changed files with 107 additions and 5 deletions
|
|
@ -171,3 +171,40 @@ impl IntoContents for () {
|
|||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_image_content_serialization() {
|
||||
let image_content = RawImageContent {
|
||||
data: "base64data".to_string(),
|
||||
mime_type: "image/png".to_string(),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&image_content).unwrap();
|
||||
println!("ImageContent JSON: {}", json);
|
||||
|
||||
// Verify it contains mimeType (camelCase) not mime_type (snake_case)
|
||||
assert!(json.contains("mimeType"));
|
||||
assert!(!json.contains("mime_type"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_audio_content_serialization() {
|
||||
let audio_content = RawAudioContent {
|
||||
data: "base64audiodata".to_string(),
|
||||
mime_type: "audio/wav".to_string(),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&audio_content).unwrap();
|
||||
println!("AudioContent JSON: {}", json);
|
||||
|
||||
// Verify it contains mimeType (camelCase) not mime_type (snake_case)
|
||||
assert!(json.contains("mimeType"));
|
||||
assert!(!json.contains("mime_type"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,3 +168,25 @@ pub struct PromptArgumentTemplate {
|
|||
pub description: Option<String>,
|
||||
pub required: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_prompt_message_image_serialization() {
|
||||
let image_content = RawImageContent {
|
||||
data: "base64data".to_string(),
|
||||
mime_type: "image/png".to_string(),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&image_content).unwrap();
|
||||
println!("PromptMessage ImageContent JSON: {}", json);
|
||||
|
||||
// Verify it contains mimeType (camelCase) not mime_type (snake_case)
|
||||
assert!(json.contains("mimeType"));
|
||||
assert!(!json.contains("mime_type"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,15 +42,17 @@ pub struct RawResourceTemplate {
|
|||
pub type ResourceTemplate = Annotated<RawResourceTemplate>;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase", untagged)]
|
||||
#[serde(untagged)]
|
||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||
pub enum ResourceContents {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
TextResourceContents {
|
||||
uri: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
mime_type: Option<String>,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
BlobResourceContents {
|
||||
uri: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
|
@ -81,3 +83,44 @@ impl RawResource {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_resource_serialization() {
|
||||
let resource = RawResource {
|
||||
uri: "file:///test.txt".to_string(),
|
||||
name: "test".to_string(),
|
||||
description: Some("Test resource".to_string()),
|
||||
mime_type: Some("text/plain".to_string()),
|
||||
size: Some(100),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&resource).unwrap();
|
||||
println!("Serialized JSON: {}", json);
|
||||
|
||||
// Verify it contains mimeType (camelCase) not mime_type (snake_case)
|
||||
assert!(json.contains("mimeType"));
|
||||
assert!(!json.contains("mime_type"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resource_contents_serialization() {
|
||||
let text_contents = ResourceContents::TextResourceContents {
|
||||
uri: "file:///test.txt".to_string(),
|
||||
mime_type: Some("text/plain".to_string()),
|
||||
text: "Hello world".to_string(),
|
||||
};
|
||||
|
||||
let json = serde_json::to_string(&text_contents).unwrap();
|
||||
println!("ResourceContents JSON: {}", json);
|
||||
|
||||
// Verify it contains mimeType (camelCase) not mime_type (snake_case)
|
||||
assert!(json.contains("mimeType"));
|
||||
assert!(!json.contains("mime_type"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1129,7 +1129,7 @@
|
|||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mime_type": {
|
||||
"mimeType": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
|
@ -1153,7 +1153,7 @@
|
|||
"blob": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"mimeType": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
|
|
|||
|
|
@ -1333,7 +1333,7 @@
|
|||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mime_type": {
|
||||
"mimeType": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
|
@ -1357,7 +1357,7 @@
|
|||
"blob": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"mimeType": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
|
|
|||
Loading…
Reference in a new issue