1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//! Types and utils for references
use serde::{Deserialize, Serialize};
use std::fmt::Display;
/// Represents a reference to a resource or prompt.
/// Umbrella type for both ResourceReference and PromptReference from the spec schema.
///
/// See the [schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json) for details
#[derive(Debug, Serialize, Deserialize)]
pub struct Reference {
/// The type of content. Can be ref/resource or ref/prompt.
#[serde(rename = "type")]
pub r#type: String,
/// The URI or URI template of the resource.
#[serde(skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
/// The name of the prompt or prompt template.
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
}
impl Display for Reference {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (&self.uri, &self.name) {
(Some(uri), None) => write!(f, "{}: {}", self.r#type, uri),
(None, Some(name)) => write!(f, "{}: {}", self.r#type, name),
_ => write!(f, "{}: unknown", self.r#type),
}
}
}
impl Reference {
/// Creates a ref/resource [`Reference`]
#[inline]
pub fn resource(uri: &str) -> Self {
Self {
r#type: "ref/resource".into(),
uri: Some(uri.into()),
name: None,
}
}
/// Creates a ref/resource [`Reference`]
#[inline]
pub fn prompt(name: &str) -> Self {
Self {
r#type: "ref/prompt".into(),
name: Some(name.into()),
uri: None,
}
}
/// Validates the reference object.
///
/// # Example
/// ```no_run
/// use neva::types::Reference;
///
/// // valid ref/resource
/// let reference = Reference::resource("file://test");
/// assert!(reference.validate().is_none());
///
/// // valid ref/prompt
/// let reference = Reference::prompt("test");
/// assert!(reference.validate().is_none())
/// ```
pub fn validate(&self) -> Option<String> {
match self.r#type.as_ref() {
"ref/resource" => {
if self.uri.is_none() {
Some("uri is required for ref/resource".into())
} else {
None
}
}
"ref/prompt" => {
if self.name.is_none() {
Some("name is required for ref/prompt".into())
} else {
None
}
}
_ => Some(format!("unknown reference type: {}", self.r#type)),
}
}
}