Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions sast-engine/cmd/serve.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package cmd

import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"

"github.com/shivasurya/code-pathfinder/sast-engine/graph"
Expand All @@ -16,25 +19,33 @@ import (
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Start MCP server for AI coding assistants",
Long: `Builds code index and starts MCP server on stdio.
Long: `Builds code index and starts MCP server.

Designed for integration with Claude Code, Codex CLI, and other AI assistants
that support the Model Context Protocol (MCP).

The server indexes the codebase once at startup, then responds to queries
about symbols, call graphs, and code relationships.`,
about symbols, call graphs, and code relationships.

Transport modes:
- stdio (default): Standard input/output for direct integration
- http: HTTP server for network access`,
RunE: runServe,
}

func init() {
rootCmd.AddCommand(serveCmd)
serveCmd.Flags().StringP("project", "p", ".", "Project path to index")
serveCmd.Flags().String("python-version", "3.11", "Python version for stdlib resolution")
serveCmd.Flags().Bool("http", false, "Use HTTP transport instead of stdio")
serveCmd.Flags().String("address", ":8080", "HTTP server address (only with --http)")
}

func runServe(cmd *cobra.Command, _ []string) error {
projectPath, _ := cmd.Flags().GetString("project")
pythonVersion, _ := cmd.Flags().GetString("python-version")
useHTTP, _ := cmd.Flags().GetBool("http")
address, _ := cmd.Flags().GetString("address")

fmt.Fprintln(os.Stderr, "Building index...")
start := time.Now()
Expand Down Expand Up @@ -66,9 +77,45 @@ func runServe(cmd *cobra.Command, _ []string) error {
fmt.Fprintf(os.Stderr, " Call edges: %d\n", len(callGraph.Edges))
fmt.Fprintf(os.Stderr, " Modules: %d\n", len(moduleRegistry.Modules))

// 4. Create and run MCP server
// 4. Create MCP server
server := mcp.NewServer(projectPath, pythonVersion, callGraph, moduleRegistry, codeGraph, buildTime)

// 5. Start appropriate transport
if useHTTP {
return runHTTPServer(server, address)
}

fmt.Fprintln(os.Stderr, "Starting MCP server on stdio...")
return server.ServeStdio()
}

func runHTTPServer(mcpServer *mcp.Server, address string) error {
config := &mcp.HTTPConfig{
Address: address,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
ShutdownTimeout: 5 * time.Second,
AllowedOrigins: []string{"*"},
}

httpServer := mcp.NewHTTPServer(mcpServer, config)

// Handle graceful shutdown.
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

errChan := make(chan error, 1)
go func() {
errChan <- httpServer.Start()
}()

select {
case err := <-errChan:
return err
case sig := <-sigChan:
fmt.Fprintf(os.Stderr, "\nReceived %v, shutting down...\n", sig)
ctx, cancel := context.WithTimeout(context.Background(), config.ShutdownTimeout)
defer cancel()
return httpServer.Shutdown(ctx)
}
}
Loading
Loading