Skip to content

Commit c748bc1

Browse files
authored
Add support for audio content in prompts and tool results (#73)
1 parent 82f4fd2 commit c748bc1

File tree

4 files changed

+57
-4
lines changed

4 files changed

+57
-4
lines changed

Sources/MCP/Server/Prompts.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public struct Prompt: Hashable, Codable, Sendable {
6464
case text(text: String)
6565
/// Image content
6666
case image(data: String, mimeType: String)
67+
/// Audio content
68+
case audio(data: String, mimeType: String)
6769
/// Embedded resource content
6870
case resource(uri: String, mimeType: String, text: String?, blob: String?)
6971

@@ -82,6 +84,10 @@ public struct Prompt: Hashable, Codable, Sendable {
8284
try container.encode("image", forKey: .type)
8385
try container.encode(data, forKey: .data)
8486
try container.encode(mimeType, forKey: .mimeType)
87+
case .audio(let data, let mimeType):
88+
try container.encode("audio", forKey: .type)
89+
try container.encode(data, forKey: .data)
90+
try container.encode(mimeType, forKey: .mimeType)
8591
case .resource(let uri, let mimeType, let text, let blob):
8692
try container.encode("resource", forKey: .type)
8793
try container.encode(uri, forKey: .uri)
@@ -103,6 +109,10 @@ public struct Prompt: Hashable, Codable, Sendable {
103109
let data = try container.decode(String.self, forKey: .data)
104110
let mimeType = try container.decode(String.self, forKey: .mimeType)
105111
self = .image(data: data, mimeType: mimeType)
112+
case "audio":
113+
let data = try container.decode(String.self, forKey: .data)
114+
let mimeType = try container.decode(String.self, forKey: .mimeType)
115+
self = .audio(data: data, mimeType: mimeType)
106116
case "resource":
107117
let uri = try container.decode(String.self, forKey: .uri)
108118
let mimeType = try container.decode(String.self, forKey: .mimeType)
@@ -155,7 +165,7 @@ public enum ListPrompts: Method {
155165

156166
public struct Parameters: NotRequired, Hashable, Codable, Sendable {
157167
public let cursor: String?
158-
168+
159169
public init() {
160170
self.cursor = nil
161171
}

Sources/MCP/Server/Tools.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public struct Tool: Hashable, Codable, Sendable {
2828
case text(String)
2929
/// Image content
3030
case image(data: String, mimeType: String, metadata: [String: String]?)
31+
/// Audio content
32+
case audio(data: String, mimeType: String)
3133
/// Embedded resource content
3234
case resource(uri: String, mimeType: String, text: String?)
3335

@@ -36,6 +38,7 @@ public struct Tool: Hashable, Codable, Sendable {
3638
case text
3739
case image
3840
case resource
41+
case audio
3942
case uri
4043
case mimeType
4144
case data
@@ -56,6 +59,10 @@ public struct Tool: Hashable, Codable, Sendable {
5659
let metadata = try container.decodeIfPresent(
5760
[String: String].self, forKey: .metadata)
5861
self = .image(data: data, mimeType: mimeType, metadata: metadata)
62+
case "audio":
63+
let data = try container.decode(String.self, forKey: .data)
64+
let mimeType = try container.decode(String.self, forKey: .mimeType)
65+
self = .audio(data: data, mimeType: mimeType)
5966
case "resource":
6067
let uri = try container.decode(String.self, forKey: .uri)
6168
let mimeType = try container.decode(String.self, forKey: .mimeType)
@@ -79,6 +86,10 @@ public struct Tool: Hashable, Codable, Sendable {
7986
try container.encode(data, forKey: .data)
8087
try container.encode(mimeType, forKey: .mimeType)
8188
try container.encodeIfPresent(metadata, forKey: .metadata)
89+
case .audio(let data, let mimeType):
90+
try container.encode("audio", forKey: .type)
91+
try container.encode(data, forKey: .data)
92+
try container.encode(mimeType, forKey: .mimeType)
8293
case .resource(let uri, let mimeType, let text):
8394
try container.encode("resource", forKey: .type)
8495
try container.encode(uri, forKey: .uri)
@@ -120,7 +131,7 @@ public enum ListTools: Method {
120131

121132
public struct Parameters: NotRequired, Hashable, Codable, Sendable {
122133
public let cursor: String?
123-
134+
124135
public init() {
125136
self.cursor = nil
126137
}

Tests/MCPTests/PromptTests.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ struct PromptTests {
6363
#expect(Bool(false), "Expected text content")
6464
}
6565

66+
// Test audio content
67+
let audioContent = Prompt.Message.Content.audio(
68+
data: "base64audiodata", mimeType: "audio/wav")
69+
let audioData = try encoder.encode(audioContent)
70+
let decodedAudio = try decoder.decode(Prompt.Message.Content.self, from: audioData)
71+
if case .audio(let data, let mimeType) = decodedAudio {
72+
#expect(data == "base64audiodata")
73+
#expect(mimeType == "audio/wav")
74+
} else {
75+
#expect(Bool(false), "Expected audio content")
76+
}
77+
6678
// Test image content
6779
let imageContent = Prompt.Message.Content.image(data: "base64data", mimeType: "image/png")
6880
let imageData = try encoder.encode(imageContent)
@@ -142,7 +154,7 @@ struct PromptTests {
142154
let emptyParams = ListPrompts.Parameters()
143155
#expect(emptyParams.cursor == nil)
144156
}
145-
157+
146158
@Test("ListPrompts request decoding with omitted params")
147159
func testListPromptsRequestDecodingWithOmittedParams() throws {
148160
// Test decoding when params field is omitted
@@ -157,7 +169,7 @@ struct PromptTests {
157169
#expect(decoded.id == "test-id")
158170
#expect(decoded.method == ListPrompts.name)
159171
}
160-
172+
161173
@Test("ListPrompts request decoding with null params")
162174
func testListPromptsRequestDecodingWithNullParams() throws {
163175
// Test decoding when params field is null

Tests/MCPTests/ToolTests.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,26 @@ struct ToolTests {
103103
}
104104
}
105105

106+
@Test("Audio content encoding and decoding")
107+
func testToolContentAudioEncoding() throws {
108+
let content = Tool.Content.audio(
109+
data: "base64audiodata",
110+
mimeType: "audio/wav"
111+
)
112+
let encoder = JSONEncoder()
113+
let decoder = JSONDecoder()
114+
115+
let data = try encoder.encode(content)
116+
let decoded = try decoder.decode(Tool.Content.self, from: data)
117+
118+
if case .audio(let data, let mimeType) = decoded {
119+
#expect(data == "base64audiodata")
120+
#expect(mimeType == "audio/wav")
121+
} else {
122+
#expect(Bool(false), "Expected audio content")
123+
}
124+
}
125+
106126
@Test("ListTools parameters validation")
107127
func testListToolsParameters() throws {
108128
let params = ListTools.Parameters(cursor: "next_page")

0 commit comments

Comments
 (0)