@@ -6,6 +6,13 @@ public protocol MCPServer {
66 /// Returns an array of all MCP tools defined in this type
77 var mcpTools : [ MCPTool ] { get }
88
9+ /// Returns an array of all MCP resources defined in this type
10+ var mcpResources : [ MCPResource ] { get }
11+
12+ /// Returns an array of all MCP resource templates defined in this type
13+ var mcpResourceTemplates : [ MCPResourceTemplate ] { get }
14+
15+
916 /// Calls a tool by name with the provided arguments
1017 /// - Parameters:
1118 /// - name: The name of the tool to call
@@ -14,12 +21,25 @@ public protocol MCPServer {
1421 /// - Throws: MCPToolError if the tool doesn't exist or cannot be called
1522 func callTool( _ name: String , arguments: [ String : Any ] ) throws -> Any
1623
24+ /// Gets a resource by URI
25+ /// - Parameter uri: The URI of the resource to get
26+ /// - Returns: The resource content, or nil if the resource doesn't exist
27+ /// - Throws: MCPResourceError if there's an error getting the resource
28+ func getResource( uri: URL ) throws -> MCPResourceContent ?
29+
1730 /// Handles a JSON-RPC request
1831 /// - Parameter request: The JSON-RPC request to handle
1932 /// - Returns: The response as a string, or nil if no response should be sent
2033 func handleRequest( _ request: JSONRPCRequest ) -> Codable ?
2134}
2235
36+ public enum MCPResourceKind
37+ {
38+ case text( String )
39+
40+ case data( Data )
41+ }
42+
2343// MARK: - Default Implementations
2444public extension MCPServer {
2545 /// Handles a JSON-RPC request with default implementation
@@ -35,9 +55,21 @@ public extension MCPServer {
3555 case " notifications/initialized " :
3656 return nil
3757
58+ case " ping " :
59+ return createPingResponse ( id: request. id ?? 0 )
60+
3861 case " tools/list " :
3962 return createToolsResponse ( id: request. id ?? 0 )
4063
64+ case " resources/list " :
65+ return createResourcesListResponse ( id: request. id ?? 0 )
66+
67+ case " resources/templates/list " :
68+ return createResourceTemplatesListResponse ( id: request. id ?? 0 )
69+
70+ case " resources/read " :
71+ return createResourcesReadResponse ( id: request. id ?? 0 , request: request)
72+
4173 case " tools/call " :
4274 return handleToolCall ( request)
4375
@@ -54,6 +86,7 @@ public extension MCPServer {
5486 " protocolVersion " : " 2024-11-05 " ,
5587 " capabilities " : [
5688 " experimental " : [ : ] ,
89+ " resources " : [ " listChanged " : false ] ,
5790 " tools " : [ " listChanged " : false ]
5891 ] ,
5992 " serverInfo " : [
@@ -65,6 +98,27 @@ public extension MCPServer {
6598 return JSONRPC . Response ( id: . number( id) , result: . init( responseDict) )
6699 }
67100
101+ /// Creates a resources list response
102+ /// - Parameter id: The request ID
103+ /// - Returns: The resources list response
104+ func createResourcesListResponse( id: Int ) -> JSONRPC . Response {
105+ // Convert MCPResource objects to dictionaries
106+ let resourceDicts = mcpResources. map { resource -> [ String : Any ] in
107+ return [
108+ " uri " : resource. uri. absoluteString,
109+ " name " : resource. name,
110+ " description " : resource. description,
111+ " mimeType " : resource. mimeType
112+ ]
113+ }
114+
115+ let resourcesList : [ String : Any ] = [
116+ " resources " : resourceDicts
117+ ]
118+
119+ return JSONRPC . Response ( id: . number( id) , result: . init( resourcesList) )
120+ }
121+
68122 /// Creates a tools response
69123 /// - Parameter id: The request ID
70124 /// - Returns: The tools response
@@ -130,4 +184,115 @@ public extension MCPServer {
130184 private var serverVersion : String {
131185 Mirror ( reflecting: self ) . children. first ( where: { $0. label == " __mcpServerVersion " } ) ? . value as? String ?? " UnknownVersion "
132186 }
133- }
187+
188+ /// Creates a resources read response
189+ /// - Parameters:
190+ /// - id: The request ID
191+ /// - request: The original JSON-RPC request
192+ /// - Returns: The resources read response
193+ func createResourcesReadResponse( id: Int , request: JSONRPCRequest ) -> JSONRPC . Response {
194+ // Extract the URI from the request params
195+ guard let uriString = request. params ? [ " uri " ] ? . value as? String ,
196+ let uri = URL ( string: uriString) else {
197+ // If no URI is provided or it's invalid, return an error
198+ let errorDict : [ String : Any ] = [
199+ " error " : " Invalid or missing URI parameter "
200+ ]
201+ return JSONRPC . Response ( id: . number( id) , result: . init( errorDict) )
202+ }
203+
204+ do {
205+ // Try to get the resource content
206+ if let resourceContent = try getResource ( uri: uri) {
207+ // Convert MCPResourceContent to dictionary
208+ var contentDict : [ String : Any ] = [
209+ " uri " : resourceContent. uri. absoluteString
210+ ]
211+
212+ // Add optional fields if they exist
213+ if let mimeType = resourceContent. mimeType {
214+ contentDict [ " mimeType " ] = mimeType
215+ }
216+
217+ if let text = resourceContent. text {
218+ contentDict [ " text " ] = text
219+ }
220+
221+ if let blob = resourceContent. blob {
222+ // Convert binary data to base64 string
223+ contentDict [ " blob " ] = blob. base64EncodedString ( )
224+ }
225+
226+ // Create the response
227+ let responseDict : [ String : Any ] = [
228+ " contents " : [ contentDict]
229+ ]
230+
231+ return JSONRPC . Response ( id: . number( id) , result: . init( responseDict) )
232+ } else {
233+ // Resource not found
234+ let errorDict : [ String : Any ] = [
235+ " error " : " Resource not found: \( uri. absoluteString) "
236+ ]
237+ return JSONRPC . Response ( id: . number( id) , result: . init( errorDict) )
238+ }
239+ } catch {
240+ // Error getting resource
241+ let errorDict : [ String : Any ] = [
242+ " error " : " Error getting resource: \( error. localizedDescription) "
243+ ]
244+ return JSONRPC . Response ( id: . number( id) , result: . init( errorDict) )
245+ }
246+ }
247+
248+ /// Creates a resource templates list response
249+ /// - Parameter id: The request ID
250+ /// - Returns: The resource templates list response
251+ func createResourceTemplatesListResponse( id: Int ) -> JSONRPC . Response {
252+ // Convert MCPResourceTemplate objects to dictionaries
253+ let templateDicts = mcpResourceTemplates. map { template -> [ String : Any ] in
254+ return [
255+ " uriTemplate " : template. uriTemplate. absoluteString,
256+ " name " : template. name,
257+ " description " : template. description,
258+ " mimeType " : template. mimeType
259+ ]
260+ }
261+
262+ let templatesResponse : [ String : Any ] = [
263+ " resourceTemplates " : templateDicts
264+ ]
265+
266+ return JSONRPC . Response ( id: . number( id) , result: . init( templatesResponse) )
267+ }
268+
269+ /// Creates a ping response
270+ /// - Parameter id: The request ID
271+ /// - Returns: The ping response
272+ func createPingResponse( id: Int ) -> JSONRPC . Response {
273+ // Create an empty result object
274+ let emptyResult : [ String : Any ] = [ : ]
275+
276+ // Return a response with the empty result
277+ return JSONRPC . Response ( id: . number( id) , result: . init( emptyResult) )
278+ }
279+
280+ /// Default implementation for mcpResources
281+ var mcpResources : [ MCPResource ] {
282+ // By default, return an empty array
283+ // Implementations can override this to provide actual resources
284+ return [ ]
285+ }
286+
287+ /// Default implementation for mcpResources
288+ var mcpResourceTemplates : [ MCPResourceTemplate ] {
289+ // By default, return an empty array
290+ // Implementations can override this to provide actual resources
291+ return [ ]
292+ }
293+
294+ /// Default implementation
295+ func getResource( uri: URL ) throws -> MCPResourceContent ? {
296+ return nil
297+ }
298+ }
0 commit comments