server_tools.go•2.87 kB
package mcpgenerator
import (
"context"
"fmt"
"github.com/centralmind/gateway/mcp"
"github.com/centralmind/gateway/model"
"github.com/centralmind/gateway/xcontext"
)
func (s *MCPServer) Tools() []model.Endpoint {
return s.tools
}
func (s *MCPServer) SetTools(tools []model.Endpoint) {
s.mu.Lock()
defer s.mu.Unlock()
var names []string
for _, t := range tools {
names = append(names, t.MCPMethod)
}
s.server.DeleteTools(names...)
for _, endpoint := range tools {
var opts []mcp.ToolOption
if endpoint.Description != "" {
opts = append(opts, mcp.WithDescription(endpoint.Description))
} else if endpoint.Summary != "" {
opts = append(opts, mcp.WithDescription(endpoint.Summary))
}
for _, col := range endpoint.Params {
if col.Required {
opts = append(opts, ArgumentOption(col, mcp.Required()))
} else {
opts = append(opts, ArgumentOption(col))
}
}
s.server.AddTool(mcp.NewTool(
endpoint.MCPMethod,
opts...,
), s.endpoint(endpoint))
}
s.tools = tools
}
func (s *MCPServer) endpoint(endpoint model.Endpoint) func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
arg := request.Params.Arguments
for _, param := range endpoint.Params {
if _, ok := arg[param.Name]; !ok {
arg[param.Name] = nil
}
}
resData, err := s.connector.Query(ctx, endpoint, request.Params.Arguments)
if err != nil {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: fmt.Sprintf("Unable to query: %s", err),
},
},
IsError: true,
}, nil
}
var res []map[string]interface{}
MAIN:
for _, row := range resData {
for _, interceptor := range s.interceptors {
r, skip := interceptor.Process(row, xcontext.Headers(ctx))
if skip {
continue MAIN
}
row = r
}
res = append(res, row)
}
var content []mcp.Content
content = append(content, mcp.TextContent{
Type: "text",
Text: fmt.Sprintf("Found a %v row-(s) in %s.", len(res), endpoint.Group),
})
for _, row := range res {
content = append(content, mcp.TextContent{
Type: "text",
Text: jsonify(row),
})
}
return &mcp.CallToolResult{
Content: content,
}, nil
}
}
func ArgumentOption(col model.EndpointParams, opts ...mcp.PropertyOption) mcp.ToolOption {
opts = append(opts, mcp.Title(fmt.Sprintf("Column %s", col.Name)))
opts = append(opts, func(m map[string]interface{}) {
m["default"] = col.Default
})
switch col.Type {
case "integer", "double", "float", "number":
return mcp.WithNumber(col.Name, opts...)
case "string":
return mcp.WithString(col.Name, opts...)
case "bool", "boolean":
return mcp.WithBoolean(col.Name, opts...)
default:
return mcp.WithString(col.Name)
}
}