Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mcp/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type ResourceTemplateOption func(*ResourceTemplate)
// Options are applied in order, allowing for flexible template configuration.
func NewResourceTemplate(uriTemplate string, name string, opts ...ResourceTemplateOption) ResourceTemplate {
template := ResourceTemplate{
URITemplate: uritemplate.MustNew(uriTemplate),
URITemplate: &URITemplate{Template: uritemplate.MustNew(uriTemplate)},
Name: name,
}

Expand Down
23 changes: 22 additions & 1 deletion mcp/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ import (
"github.com/yosida95/uritemplate/v3"
)

type URITemplate struct {
*uritemplate.Template
}

func (t *URITemplate) MarshalJSON() ([]byte, error) {
return json.Marshal(t.Template.Raw())
}

func (t *URITemplate) UnmarshalJSON(data []byte) error {
var raw string
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
template, err := uritemplate.New(raw)
if err != nil {
return err
}
t.Template = template
return nil
}

/* JSON-RPC types */

// JSONRPCMessage represents either a JSONRPCRequest, JSONRPCNotification, JSONRPCResponse, or JSONRPCError
Expand Down Expand Up @@ -446,7 +467,7 @@ type ResourceTemplate struct {
Annotated
// A URI template (according to RFC 6570) that can be used to construct
// resource URIs.
URITemplate *uritemplate.Template `json:"uriTemplate"`
URITemplate *URITemplate `json:"uriTemplate"`
// A human-readable name for the type of resource this template refers to.
//
// This can be used by clients to populate UI elements.
Expand Down
3 changes: 1 addition & 2 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"sync/atomic"

"github.com/mark3labs/mcp-go/mcp"
"github.com/yosida95/uritemplate/v3"
)

// resourceEntry holds both a resource and its handler
Expand Down Expand Up @@ -731,7 +730,7 @@ func (s *MCPServer) handleReadResource(
}

// matchesTemplate checks if a URI matches a URI template pattern
func matchesTemplate(uri string, template *uritemplate.Template) bool {
func matchesTemplate(uri string, template *mcp.URITemplate) bool {
return template.Regexp().MatchString(uri)
}

Expand Down
35 changes: 32 additions & 3 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,6 @@ func TestMCPServer_Instructions(t *testing.T) {
func TestMCPServer_ResourceTemplates(t *testing.T) {
server := NewMCPServer("test-server", "1.0.0",
WithResourceCapabilities(true, true),
WithPromptCapabilities(true),
)

server.AddResourceTemplate(
Expand All @@ -947,9 +946,15 @@ func TestMCPServer_ResourceTemplates(t *testing.T) {
},
)

message := `{
listMessage := `{
"jsonrpc": "2.0",
"id": 1,
"method": "resources/templates/list"
}`

message := `{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/read",
"params": {
"uri": "test://something/test-resource/a/b/c"
Expand All @@ -959,12 +964,35 @@ func TestMCPServer_ResourceTemplates(t *testing.T) {
t.Run("Get resource template", func(t *testing.T) {
response := server.HandleMessage(
context.Background(),
[]byte(message),
[]byte(listMessage),
)
assert.NotNil(t, response)

resp, ok := response.(mcp.JSONRPCResponse)
assert.True(t, ok)
listResult, ok := resp.Result.(mcp.ListResourceTemplatesResult)
assert.True(t, ok)
assert.Len(t, listResult.ResourceTemplates, 1)
assert.Equal(t, "My Resource", listResult.ResourceTemplates[0].Name)
template, err := json.Marshal(listResult.ResourceTemplates[0])
assert.NoError(t, err)

// Need to serialize the json to map[string]string to validate the URITemplate is correctly marshalled
var resourceTemplate map[string]string
err = json.Unmarshal(template, &resourceTemplate)
assert.NoError(t, err)

assert.Equal(t, "test://{a}/test-resource{/b*}", resourceTemplate["uriTemplate"])

response = server.HandleMessage(
context.Background(),
[]byte(message),
)

assert.NotNil(t, response)

resp, ok = response.(mcp.JSONRPCResponse)
assert.True(t, ok)
// Validate that the resource values are returned correctly
result, ok := resp.Result.(mcp.ReadResourceResult)
assert.True(t, ok)
Expand All @@ -974,6 +1002,7 @@ func TestMCPServer_ResourceTemplates(t *testing.T) {
assert.Equal(t, "test://something/test-resource/a/b/c", resultContent.URI)
assert.Equal(t, "text/plain", resultContent.MIMEType)
assert.Equal(t, "test content: something", resultContent.Text)

})
}

Expand Down