Skip to content

Commit 490b11c

Browse files
authored
feat(server): support server instructions (#43)
* feat(server): support server instructions * add tests
1 parent 258aee9 commit 490b11c

File tree

2 files changed

+85
-6
lines changed

2 files changed

+85
-6
lines changed

server/server.go

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type MCPServer struct {
6767
mu sync.RWMutex // Add mutex for protecting shared resources
6868
name string
6969
version string
70+
instructions string
7071
resources map[string]resourceEntry
7172
resourceTemplates map[string]resourceTemplateEntry
7273
prompts map[string]mcp.Prompt
@@ -198,6 +199,13 @@ func WithLogging() ServerOption {
198199
}
199200
}
200201

202+
// WithInstructions sets the server instructions for the client returned in the initialize response
203+
func WithInstructions(instructions string) ServerOption {
204+
return func(s *MCPServer) {
205+
s.instructions = instructions
206+
}
207+
}
208+
201209
// NewMCPServer creates a new MCP server instance with the given name, version and options
202210
func NewMCPServer(
203211
name, version string,
@@ -571,6 +579,7 @@ func (s *MCPServer) handleInitialize(
571579
Version: s.version,
572580
},
573581
Capabilities: capabilities,
582+
Instructions: s.instructions,
574583
}
575584

576585
s.initialized.Store(true)

server/server_test.go

+76-6
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ func TestMCPServer_Capabilities(t *testing.T) {
141141
})
142142
}
143143
}
144+
144145
func TestMCPServer_Tools(t *testing.T) {
145146
tests := []struct {
146147
name string
@@ -207,14 +208,14 @@ func TestMCPServer_Tools(t *testing.T) {
207208
assert.Equal(t, "notifications/tools/list_changed", notifications[0].Notification.Method)
208209
// One for DeleteTools
209210
assert.Equal(t, "notifications/tools/list_changed", notifications[1].Notification.Method)
210-
211+
211212
// Expect a successful response with an empty list of tools
212213
resp, ok := toolsList.(mcp.JSONRPCResponse)
213214
assert.True(t, ok, "Expected JSONRPCResponse, got %T", toolsList)
214-
215+
215216
result, ok := resp.Result.(mcp.ListToolsResult)
216217
assert.True(t, ok, "Expected ListToolsResult, got %T", resp.Result)
217-
218+
218219
assert.Empty(t, result.Tools, "Expected empty tools list")
219220
},
220221
},
@@ -660,7 +661,7 @@ func TestMCPServer_HandleMethodsWithoutCapabilities(t *testing.T) {
660661
"name": "test-tool"
661662
}
662663
}`,
663-
options: []ServerOption{}, // No capabilities at all
664+
options: []ServerOption{}, // No capabilities at all
664665
expectedErr: mcp.METHOD_NOT_FOUND,
665666
},
666667
{
@@ -673,7 +674,7 @@ func TestMCPServer_HandleMethodsWithoutCapabilities(t *testing.T) {
673674
"name": "test-prompt"
674675
}
675676
}`,
676-
options: []ServerOption{}, // No capabilities at all
677+
options: []ServerOption{}, // No capabilities at all
677678
expectedErr: mcp.METHOD_NOT_FOUND,
678679
},
679680
{
@@ -686,7 +687,7 @@ func TestMCPServer_HandleMethodsWithoutCapabilities(t *testing.T) {
686687
"uri": "test-resource"
687688
}
688689
}`,
689-
options: []ServerOption{}, // No capabilities at all
690+
options: []ServerOption{}, // No capabilities at all
690691
expectedErr: mcp.METHOD_NOT_FOUND,
691692
},
692693
}
@@ -707,6 +708,75 @@ func TestMCPServer_HandleMethodsWithoutCapabilities(t *testing.T) {
707708
}
708709
}
709710

711+
func TestMCPServer_Instructions(t *testing.T) {
712+
tests := []struct {
713+
name string
714+
instructions string
715+
validate func(t *testing.T, response mcp.JSONRPCMessage)
716+
}{
717+
{
718+
name: "No instructions",
719+
instructions: "",
720+
validate: func(t *testing.T, response mcp.JSONRPCMessage) {
721+
resp, ok := response.(mcp.JSONRPCResponse)
722+
assert.True(t, ok)
723+
724+
initResult, ok := resp.Result.(mcp.InitializeResult)
725+
assert.True(t, ok)
726+
assert.Equal(t, "", initResult.Instructions)
727+
},
728+
},
729+
{
730+
name: "With instructions",
731+
instructions: "These are test instructions for the client.",
732+
validate: func(t *testing.T, response mcp.JSONRPCMessage) {
733+
resp, ok := response.(mcp.JSONRPCResponse)
734+
assert.True(t, ok)
735+
736+
initResult, ok := resp.Result.(mcp.InitializeResult)
737+
assert.True(t, ok)
738+
assert.Equal(t, "These are test instructions for the client.", initResult.Instructions)
739+
},
740+
},
741+
{
742+
name: "With multiline instructions",
743+
instructions: "Line 1\nLine 2\nLine 3",
744+
validate: func(t *testing.T, response mcp.JSONRPCMessage) {
745+
resp, ok := response.(mcp.JSONRPCResponse)
746+
assert.True(t, ok)
747+
748+
initResult, ok := resp.Result.(mcp.InitializeResult)
749+
assert.True(t, ok)
750+
assert.Equal(t, "Line 1\nLine 2\nLine 3", initResult.Instructions)
751+
},
752+
},
753+
}
754+
755+
for _, tt := range tests {
756+
t.Run(tt.name, func(t *testing.T) {
757+
var server *MCPServer
758+
if tt.instructions == "" {
759+
server = NewMCPServer("test-server", "1.0.0")
760+
} else {
761+
server = NewMCPServer("test-server", "1.0.0", WithInstructions(tt.instructions))
762+
}
763+
764+
message := mcp.JSONRPCRequest{
765+
JSONRPC: "2.0",
766+
ID: 1,
767+
Request: mcp.Request{
768+
Method: "initialize",
769+
},
770+
}
771+
messageBytes, err := json.Marshal(message)
772+
assert.NoError(t, err)
773+
774+
response := server.HandleMessage(context.Background(), messageBytes)
775+
tt.validate(t, response)
776+
})
777+
}
778+
}
779+
710780
func createTestServer() *MCPServer {
711781
server := NewMCPServer("test-server", "1.0.0",
712782
WithResourceCapabilities(true, true),

0 commit comments

Comments
 (0)