Skip to content

Commit c66bce8

Browse files
committed
[khan-changes] listing resources
1 parent ec8af12 commit c66bce8

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

server/streamable_http_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,135 @@ func TestStreamableHTTP_HttpHandler(t *testing.T) {
590590
})
591591
}
592592

593+
func TestStreamableHttpResourceGet(t *testing.T) {
594+
s := NewMCPServer("test-mcp-server", "1.0", WithResourceCapabilities(true, true))
595+
596+
testServer := NewTestStreamableHTTPServer(
597+
s,
598+
WithHTTPContextFunc(func(ctx context.Context, r *http.Request) context.Context {
599+
session := ClientSessionFromContext(ctx)
600+
601+
if st, ok := session.(SessionWithResources); ok {
602+
if _, ok := st.GetSessionResources()["file://test_resource"]; !ok {
603+
st.SetSessionResources(map[string]ServerResource{
604+
"file://test_resource": ServerResource{
605+
Resource: mcp.Resource{
606+
URI: "file://test_resource",
607+
Name: "test_resource",
608+
Description: "A test resource",
609+
MIMEType: "text/plain",
610+
},
611+
Handler: func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
612+
return []mcp.ResourceContents{
613+
mcp.TextResourceContents{
614+
URI: "file://test_resource",
615+
Text: "test content",
616+
MIMEType: "text/plain",
617+
},
618+
}, nil
619+
},
620+
},
621+
})
622+
}
623+
} else {
624+
t.Error("Session does not support tools/resources")
625+
}
626+
627+
return ctx
628+
}),
629+
)
630+
631+
var sessionID string
632+
633+
// Initialize session
634+
resp, err := postJSON(testServer.URL, initRequest)
635+
if err != nil {
636+
t.Fatalf("Failed to send initialize request: %v", err)
637+
}
638+
defer resp.Body.Close()
639+
640+
if resp.StatusCode != http.StatusOK {
641+
t.Errorf("Expected status 200, got %d", resp.StatusCode)
642+
}
643+
644+
sessionID = resp.Header.Get(HeaderKeySessionID)
645+
if sessionID == "" {
646+
t.Fatal("Expected session id in header")
647+
}
648+
649+
// List resources
650+
listResourcesRequest := map[string]any{
651+
"jsonrpc": "2.0",
652+
"id": 2,
653+
"method": "resources/list",
654+
"params": map[string]any{},
655+
}
656+
resp, err = postSessionJSON(testServer.URL, sessionID, listResourcesRequest)
657+
if err != nil {
658+
t.Fatalf("Failed to send list resources request: %v", err)
659+
}
660+
661+
if resp.StatusCode != http.StatusOK {
662+
t.Errorf("Expected status 200, got %d", resp.StatusCode)
663+
}
664+
665+
bodyBytes, _ := io.ReadAll(resp.Body)
666+
var listResponse jsonRPCResponse
667+
if err := json.Unmarshal(bodyBytes, &listResponse); err != nil {
668+
t.Fatalf("Failed to unmarshal response: %v", err)
669+
}
670+
671+
items, ok := listResponse.Result["resources"].([]any)
672+
if !ok {
673+
t.Fatal("Expected resources array in response")
674+
}
675+
if len(items) != 1 {
676+
t.Fatalf("Expected 1 resource, got %d", len(items))
677+
}
678+
imap, ok := items[0].(map[string]any)
679+
if !ok {
680+
t.Fatal("Expected resource to be a map")
681+
}
682+
if imap["uri"] != "file://test_resource" {
683+
t.Errorf("Expected resource URI file://test_resource, got %v", imap["uri"])
684+
}
685+
686+
// List resources
687+
getResourceRequest := map[string]any{
688+
"jsonrpc": "2.0",
689+
"id": 2,
690+
"method": "resources/read",
691+
"params": map[string]any{"uri": "file://test_resource"},
692+
}
693+
resp, err = postSessionJSON(testServer.URL, sessionID, getResourceRequest)
694+
if err != nil {
695+
t.Fatalf("Failed to send list resources request: %v", err)
696+
}
697+
698+
bodyBytes, _ = io.ReadAll(resp.Body)
699+
var readResponse jsonRPCResponse
700+
if err := json.Unmarshal(bodyBytes, &readResponse); err != nil {
701+
t.Fatalf("Failed to unmarshal response: %v", err)
702+
}
703+
704+
contents, ok := readResponse.Result["contents"].([]any)
705+
if !ok {
706+
t.Fatal("Expected contents array in response")
707+
}
708+
if len(contents) != 1 {
709+
t.Fatalf("Expected 1 content, got %d", len(contents))
710+
}
711+
712+
cmap, ok := contents[0].(map[string]any)
713+
if !ok {
714+
t.Fatal("Expected content to be a map")
715+
}
716+
if cmap["uri"] != "file://test_resource" {
717+
t.Errorf("Expected content URI file://test_resource, got %v", cmap["uri"])
718+
}
719+
720+
}
721+
593722
func TestStreamableHTTP_SessionWithTools(t *testing.T) {
594723

595724
t.Run("SessionWithTools implementation", func(t *testing.T) {
@@ -1055,3 +1184,11 @@ func postJSON(url string, bodyObject any) (*http.Response, error) {
10551184
req.Header.Set("Content-Type", "application/json")
10561185
return http.DefaultClient.Do(req)
10571186
}
1187+
1188+
func postSessionJSON(url, session string, bodyObject any) (*http.Response, error) {
1189+
jsonBody, _ := json.Marshal(bodyObject)
1190+
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonBody))
1191+
req.Header.Set("Content-Type", "application/json")
1192+
req.Header.Set(HeaderKeySessionID, session)
1193+
return http.DefaultClient.Do(req)
1194+
}

0 commit comments

Comments
 (0)