@@ -46,6 +46,13 @@ type ToolHandlerMiddleware func(ToolHandlerFunc) ToolHandlerFunc
46
46
// ToolFilterFunc is a function that filters tools based on context, typically using session information.
47
47
type ToolFilterFunc func (ctx context.Context , tools []mcp.Tool ) []mcp.Tool
48
48
49
+ // dynamicTools holds configuration for dynamic tool generation
50
+ type dynamicTools struct {
51
+ enabled bool
52
+ listFunc func (ctx context.Context , request mcp.ListToolsRequest ) ([]mcp.Tool , error )
53
+ handlerFunc func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error )
54
+ }
55
+
49
56
// ServerTool combines a Tool with its ToolHandlerFunc.
50
57
type ServerTool struct {
51
58
Tool mcp.Tool
@@ -155,6 +162,7 @@ type MCPServer struct {
155
162
tools map [string ]ServerTool
156
163
toolHandlerMiddlewares []ToolHandlerMiddleware
157
164
toolFilters []ToolFilterFunc
165
+ dynamicTools * dynamicTools
158
166
notificationHandlers map [string ]NotificationHandlerFunc
159
167
capabilities serverCapabilities
160
168
paginationLimit * int
@@ -288,6 +296,20 @@ func WithInstructions(instructions string) ServerOption {
288
296
}
289
297
}
290
298
299
+ func WithDynamicTools (
300
+ enabled bool ,
301
+ listFunc func (ctx context.Context , request mcp.ListToolsRequest ) ([]mcp.Tool , error ),
302
+ handlerFunc func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ),
303
+ ) ServerOption {
304
+ return func (s * MCPServer ) {
305
+ s .dynamicTools = & dynamicTools {
306
+ enabled : enabled ,
307
+ listFunc : listFunc ,
308
+ handlerFunc : handlerFunc ,
309
+ }
310
+ }
311
+ }
312
+
291
313
// NewMCPServer creates a new MCP server instance with the given name, version and options
292
314
func NewMCPServer (
293
315
name , version string ,
@@ -944,6 +966,44 @@ func (s *MCPServer) handleListTools(
944
966
}
945
967
}
946
968
969
+ // Add dynamic tools if enabled
970
+ if s .dynamicTools != nil && s .dynamicTools .enabled && s .dynamicTools .listFunc != nil {
971
+ dynamicTools , err := s .dynamicTools .listFunc (ctx , request )
972
+ if err != nil {
973
+ return nil , & requestError {
974
+ id : id ,
975
+ code : mcp .INTERNAL_ERROR ,
976
+ err : fmt .Errorf ("dynamic tools list function failed: %w" , err ),
977
+ }
978
+ }
979
+
980
+ if len (dynamicTools ) > 0 {
981
+ // Create a map to merge tools properly
982
+ toolMap := make (map [string ]mcp.Tool )
983
+
984
+ // Add dynamic tools first (lowest priority)
985
+ for _ , tool := range dynamicTools {
986
+ toolMap [tool .Name ] = tool
987
+ }
988
+
989
+ // Then add existing tools (they override dynamic tools)
990
+ for _ , tool := range tools {
991
+ toolMap [tool .Name ] = tool
992
+ }
993
+
994
+ // Convert back to slice
995
+ tools = make ([]mcp.Tool , 0 , len (toolMap ))
996
+ for _ , tool := range toolMap {
997
+ tools = append (tools , tool )
998
+ }
999
+
1000
+ // Sort again to maintain consistent ordering
1001
+ sort .Slice (tools , func (i , j int ) bool {
1002
+ return tools [i ].Name < tools [j ].Name
1003
+ })
1004
+ }
1005
+ }
1006
+
947
1007
// Apply tool filters if any are defined
948
1008
s .toolFiltersMu .RLock ()
949
1009
if len (s .toolFilters ) > 0 {
@@ -1006,6 +1066,15 @@ func (s *MCPServer) handleToolCall(
1006
1066
s .toolsMu .RUnlock ()
1007
1067
}
1008
1068
1069
+ // If still not found, try dynamic tool handler
1070
+ if ! ok && s .dynamicTools != nil && s .dynamicTools .enabled && s .dynamicTools .handlerFunc != nil {
1071
+ // Create a ServerTool with the dynamic handler
1072
+ tool = ServerTool {
1073
+ Handler : s .dynamicTools .handlerFunc ,
1074
+ }
1075
+ ok = true
1076
+ }
1077
+
1009
1078
if ! ok {
1010
1079
return nil , & requestError {
1011
1080
id : id ,
0 commit comments