@@ -5,18 +5,31 @@ import (
5
5
"context"
6
6
"encoding/json"
7
7
"fmt"
8
+ "regexp"
8
9
9
10
"github.com/mark3labs/mcp-go/mcp"
10
11
)
11
12
13
+ // resourceEntry holds both a resource and its handler
14
+ type resourceEntry struct {
15
+ resource mcp.Resource
16
+ handler ResourceHandlerFunc
17
+ }
18
+
19
+ // resourceTemplateEntry holds both a template and its handler
20
+ type resourceTemplateEntry struct {
21
+ template mcp.ResourceTemplate
22
+ handler ResourceTemplateHandlerFunc
23
+ }
24
+
12
25
// ServerOption is a function that configures an MCPServer.
13
26
type ServerOption func (* MCPServer )
14
27
15
28
// ResourceHandlerFunc is a function that returns resource contents.
16
- type ResourceHandlerFunc func (arguments map [ string ] interface {} ) ([]interface {}, error )
29
+ type ResourceHandlerFunc func (request mcp. ReadResourceRequest ) ([]interface {}, error )
17
30
18
31
// ResourceTemplateHandlerFunc is a function that returns a resource template.
19
- type ResourceTemplateHandlerFunc func (arguments map [ string ]interface {}) (mcp. ResourceTemplate , error )
32
+ type ResourceTemplateHandlerFunc func (request mcp. ReadResourceRequest ) ([ ]interface {}, error )
20
33
21
34
// PromptHandlerFunc handles prompt requests with given arguments.
22
35
type PromptHandlerFunc func (arguments map [string ]string ) (* mcp.GetPromptResult , error )
@@ -32,8 +45,8 @@ type NotificationHandlerFunc func(notification mcp.JSONRPCNotification)
32
45
type MCPServer struct {
33
46
name string
34
47
version string
35
- resources map [string ]ResourceHandlerFunc
36
- resourceTemplates map [string ]ResourceTemplateHandlerFunc
48
+ resources map [string ]resourceEntry
49
+ resourceTemplates map [string ]resourceTemplateEntry
37
50
prompts map [string ]mcp.Prompt
38
51
promptHandlers map [string ]PromptHandlerFunc
39
52
tools map [string ]mcp.Tool
@@ -92,8 +105,8 @@ func NewMCPServer(
92
105
opts ... ServerOption ,
93
106
) * MCPServer {
94
107
s := & MCPServer {
95
- resources : make (map [string ]ResourceHandlerFunc ),
96
- resourceTemplates : make (map [string ]ResourceTemplateHandlerFunc ),
108
+ resources : make (map [string ]resourceEntry ),
109
+ resourceTemplates : make (map [string ]resourceTemplateEntry ),
97
110
prompts : make (map [string ]mcp.Prompt ),
98
111
promptHandlers : make (map [string ]PromptHandlerFunc ),
99
112
tools : make (map [string ]mcp.Tool ),
@@ -298,26 +311,34 @@ func (s *MCPServer) HandleMessage(
298
311
}
299
312
}
300
313
301
- // AddResource registers a new resource handler for the given URI
302
- func (s * MCPServer ) AddResource (uri string , handler ResourceHandlerFunc ) {
314
+ // AddResource registers a new resource and its handler
315
+ func (s * MCPServer ) AddResource (
316
+ resource mcp.Resource ,
317
+ handler ResourceHandlerFunc ,
318
+ ) {
303
319
if s .capabilities .resources == nil {
304
320
panic ("Resource capabilities not enabled" )
305
321
}
306
- s .resources [uri ] = handler
322
+ s .resources [resource .URI ] = resourceEntry {
323
+ resource : resource ,
324
+ handler : handler ,
325
+ }
307
326
}
308
327
309
- // AddResourceTemplate registers a new resource template handler for the given URI template
328
+ // AddResourceTemplate registers a new resource template and its handler
310
329
func (s * MCPServer ) AddResourceTemplate (
311
- uriTemplate string ,
330
+ template mcp. ResourceTemplate ,
312
331
handler ResourceTemplateHandlerFunc ,
313
332
) {
314
333
if s .capabilities .resources == nil {
315
334
panic ("Resource capabilities not enabled" )
316
335
}
317
- s .resourceTemplates [uriTemplate ] = handler
336
+ s .resourceTemplates [template .URITemplate ] = resourceTemplateEntry {
337
+ template : template ,
338
+ handler : handler ,
339
+ }
318
340
}
319
341
320
-
321
342
// AddPrompt registers a new prompt handler with the given name
322
343
func (s * MCPServer ) AddPrompt (prompt mcp.Prompt , handler PromptHandlerFunc ) {
323
344
if s .capabilities .prompts == nil {
@@ -401,10 +422,8 @@ func (s *MCPServer) handleListResources(
401
422
request mcp.ListResourcesRequest ,
402
423
) mcp.JSONRPCMessage {
403
424
resources := make ([]mcp.Resource , 0 , len (s .resources ))
404
- for uri := range s .resources {
405
- resources = append (resources , mcp.Resource {
406
- URI : uri ,
407
- })
425
+ for _ , entry := range s .resources {
426
+ resources = append (resources , entry .resource )
408
427
}
409
428
410
429
result := mcp.ListResourcesResult {
@@ -419,25 +438,10 @@ func (s *MCPServer) handleListResources(
419
438
func (s * MCPServer ) handleListResourceTemplates (
420
439
id interface {},
421
440
request mcp.ListResourceTemplatesRequest ,
422
- ) mcp.
423
- JSONRPCMessage {
441
+ ) mcp.JSONRPCMessage {
424
442
templates := make ([]mcp.ResourceTemplate , 0 , len (s .resourceTemplates ))
425
- for uriTemplate , handler := range s .resourceTemplates {
426
- template , err := handler (nil )
427
- if err != nil {
428
- return createErrorResponse (
429
- id ,
430
- mcp .INTERNAL_ERROR ,
431
- fmt .Sprintf (
432
- "Error getting template for %s: %v" ,
433
- uriTemplate ,
434
- err ,
435
- ),
436
- )
437
- }
438
-
439
- template .URITemplate = uriTemplate
440
- templates = append (templates , template )
443
+ for _ , entry := range s .resourceTemplates {
444
+ templates = append (templates , entry .template )
441
445
}
442
446
443
447
result := mcp.ListResourceTemplatesResult {
@@ -453,26 +457,51 @@ func (s *MCPServer) handleReadResource(
453
457
id interface {},
454
458
request mcp.ReadResourceRequest ,
455
459
) mcp.JSONRPCMessage {
456
- handler , ok := s .resources [request .Params .URI ]
457
- if ! ok {
458
- return createErrorResponse (
459
- id ,
460
- mcp .INVALID_PARAMS ,
461
- fmt .Sprintf ("No handler found for resource URI: %s" , request .Params .
462
- URI ),
463
- )
460
+ // First try direct resource handlers
461
+ if entry , ok := s .resources [request .Params .URI ]; ok {
462
+ contents , err := entry .handler (request )
463
+ if err != nil {
464
+ return createErrorResponse (id , mcp .INTERNAL_ERROR , err .Error ())
465
+ }
466
+ return createResponse (id , mcp.ReadResourceResult {Contents : contents })
464
467
}
465
468
466
- contents , err := handler (request .Params .Arguments )
467
- if err != nil {
468
- return createErrorResponse (id , mcp .INTERNAL_ERROR , err .Error ())
469
+ // If no direct handler found, try matching against templates
470
+ for uriTemplate , entry := range s .resourceTemplates {
471
+ if matchesTemplate (request .Params .URI , uriTemplate ) {
472
+ contents , err := entry .handler (request )
473
+ if err != nil {
474
+ return createErrorResponse (id , mcp .INTERNAL_ERROR , err .Error ())
475
+ }
476
+ return createResponse (
477
+ id ,
478
+ mcp.ReadResourceResult {Contents : contents },
479
+ )
480
+ }
469
481
}
470
482
471
- result := mcp.ReadResourceResult {
472
- Contents : contents ,
473
- }
483
+ return createErrorResponse (
484
+ id ,
485
+ mcp .INVALID_PARAMS ,
486
+ fmt .Sprintf (
487
+ "No handler found for resource URI: %s" ,
488
+ request .Params .URI ,
489
+ ),
490
+ )
491
+ }
474
492
475
- return createResponse (id , result )
493
+ // matchesTemplate checks if a URI matches a URI template pattern
494
+ func matchesTemplate (uri string , template string ) bool {
495
+ // Convert template into a regex pattern
496
+ pattern := template
497
+ // Replace {name} with ([^/]+)
498
+ pattern = regexp .QuoteMeta (pattern )
499
+ pattern = regexp .MustCompile (`\\\{[^}]+\\\}` ).
500
+ ReplaceAllString (pattern , `([^/]+)` )
501
+ pattern = "^" + pattern + "$"
502
+
503
+ matched , _ := regexp .MatchString (pattern , uri )
504
+ return matched
476
505
}
477
506
478
507
func (s * MCPServer ) handleListPrompts (
0 commit comments