feat(mcp): implement MCP server and handler

- Implement MCP server and handler
- Add MCP server to serve
- Add MCP handler to handle MCP requests
- Add MCP server to serve
- Add MCP handler to handle MCP requests
This commit is contained in:
Alex Jones
2025-04-25 08:25:55 +01:00
parent 5f82024148
commit 1d9e29dc0b
2 changed files with 72 additions and 72 deletions

View File

@@ -187,7 +187,11 @@ var ServeCmd = &cobra.Command{
if enableMCP {
// Create and start MCP server
mcpServer := k8sgptserver.NewMCPServer(mcpPort, aiProvider)
mcpServer, err := k8sgptserver.NewMCPServer(mcpPort, aiProvider)
if err != nil {
color.Red("Error creating MCP server: %v", err)
os.Exit(1)
}
go func() {
if err := mcpServer.Start(); err != nil {
color.Red("Error starting MCP server: %v", err)

View File

@@ -28,19 +28,41 @@ type MCPServer struct {
server *mcp_golang.Server
port string
aiProvider *ai.AIProvider
analysis *analysis.Analysis
}
// NewMCPServer creates a new MCP server
func NewMCPServer(port string, aiProvider *ai.AIProvider) *MCPServer {
func NewMCPServer(port string, aiProvider *ai.AIProvider) (*MCPServer, error) {
// Create MCP server with stdio transport
transport := stdio.NewStdioServerTransport()
server := mcp_golang.NewServer(transport)
// Initialize analysis configuration
analysis, err := analysis.NewAnalysis(
aiProvider.Name, // backend
"english", // language
[]string{}, // filters
"", // namespace
"", // labelSelector
false, // nocache
false, // explain
10, // maxConcurrency
false, // withDoc
false, // interactiveMode
[]string{}, // customHeaders
false, // withStats
)
if err != nil {
return nil, fmt.Errorf("failed to initialize analysis: %v", err)
}
return &MCPServer{
server: server,
port: port,
aiProvider: aiProvider,
}
analysis: analysis,
}, nil
}
// Start starts the MCP server
@@ -75,7 +97,18 @@ func (s *MCPServer) Start() error {
// AnalyzeRequest represents the input parameters for the analyze tool
type AnalyzeRequest struct {
Namespace string `json:"namespace,omitempty"`
Namespace string `json:"namespace,omitempty"`
Backend string `json:"backend,omitempty"`
Language string `json:"language,omitempty"`
Filters []string `json:"filters,omitempty"`
LabelSelector string `json:"labelSelector,omitempty"`
NoCache bool `json:"noCache,omitempty"`
Explain bool `json:"explain,omitempty"`
MaxConcurrency int `json:"maxConcurrency,omitempty"`
WithDoc bool `json:"withDoc,omitempty"`
InteractiveMode bool `json:"interactiveMode,omitempty"`
CustomHeaders []string `json:"customHeaders,omitempty"`
WithStats bool `json:"withStats,omitempty"`
}
// AnalyzeResponse represents the output of the analyze tool
@@ -95,67 +128,42 @@ type ClusterInfoResponse struct {
// handleAnalyze handles the analyze tool
func (s *MCPServer) handleAnalyze(ctx context.Context, request *AnalyzeRequest) (*mcp_golang.ToolResponse, error) {
namespace := "default"
if request != nil && request.Namespace != "" {
namespace = request.Namespace
}
// Create analysis configuration
config, err := analysis.NewAnalysis(
s.aiProvider.Name, // backend
"english", // language
[]string{}, // filters
namespace, // namespace
"", // labelSelector
false, // nocache
false, // explain
10, // maxConcurrency
false, // withDoc
false, // interactiveMode
[]string{}, // customHeaders
false, // withStats
// Create a new analysis with the request parameters
analysis, err := analysis.NewAnalysis(
request.Backend,
request.Language,
request.Filters,
request.Namespace,
request.LabelSelector,
request.NoCache,
request.Explain,
request.MaxConcurrency,
request.WithDoc,
request.InteractiveMode,
request.CustomHeaders,
request.WithStats,
)
if err != nil {
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("failed to create analysis: %v", err))), nil
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("Failed to create analysis: %v", err))), nil
}
defer config.Close()
defer analysis.Close()
// Run the analysis
config.RunAnalysis()
analysis.RunAnalysis()
// Get the results
results, err := config.PrintOutput("json")
// Get the output
output, err := analysis.PrintOutput("json")
if err != nil {
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("failed to get analysis results: %v", err))), nil
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("Failed to print output: %v", err))), nil
}
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(results))), nil
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(string(output))), nil
}
// handleClusterInfo handles the cluster-info tool
func (s *MCPServer) handleClusterInfo(ctx context.Context, request *ClusterInfoRequest) (*mcp_golang.ToolResponse, error) {
// Create analysis configuration to get cluster info
config, err := analysis.NewAnalysis(
s.aiProvider.Name, // backend
"english", // language
[]string{}, // filters
"", // namespace
"", // labelSelector
false, // nocache
false, // explain
10, // maxConcurrency
false, // withDoc
false, // interactiveMode
[]string{}, // customHeaders
false, // withStats
)
if err != nil {
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("failed to create analysis: %v", err))), nil
}
defer config.Close()
// Get cluster info from the client
version, err := config.Client.Client.Discovery().ServerVersion()
version, err := s.analysis.Client.Client.Discovery().ServerVersion()
if err != nil {
return mcp_golang.NewToolResponse(mcp_golang.NewTextContent(fmt.Sprintf("failed to get cluster version: %v", err))), nil
}
@@ -179,28 +187,8 @@ func (s *MCPServer) registerResources() error {
}
func (s *MCPServer) getClusterInfo(ctx context.Context) (interface{}, error) {
// Create analysis configuration to get cluster info
config, err := analysis.NewAnalysis(
s.aiProvider.Name, // backend
"english", // language
[]string{}, // filters
"", // namespace
"", // labelSelector
false, // nocache
false, // explain
10, // maxConcurrency
false, // withDoc
false, // interactiveMode
[]string{}, // customHeaders
false, // withStats
)
if err != nil {
return nil, fmt.Errorf("failed to create analysis: %v", err)
}
defer config.Close()
// Get cluster info from the client
version, err := config.Client.Client.Discovery().ServerVersion()
version, err := s.analysis.Client.Client.Discovery().ServerVersion()
if err != nil {
return nil, fmt.Errorf("failed to get cluster version: %v", err)
}
@@ -211,3 +199,11 @@ func (s *MCPServer) getClusterInfo(ctx context.Context) (interface{}, error) {
"gitVersion": version.GitVersion,
}, nil
}
// Close closes the MCP server and releases resources
func (s *MCPServer) Close() error {
if s.analysis != nil {
s.analysis.Close()
}
return nil
}