Commit 2d6631a

mo khan <mo@mokhan.ca>
2025-08-18 20:51:20
refactor: remove semantic mcp server
1 parent 2d09db2
cmd/semantic/main.go
@@ -1,212 +0,0 @@
-package main
-
-import (
-	"context"
-	"flag"
-	"fmt"
-	"log"
-	"os"
-	"os/signal"
-	"syscall"
-
-	"github.com/xlgmokha/mcp/pkg/semantic"
-)
-
-func main() {
-	var (
-		projectRoot = flag.String("project-root", ".", "Root directory of the project to analyze")
-		configFile  = flag.String("config", "", "Path to configuration file")
-		logLevel    = flag.String("log-level", "info", "Log level (debug, info, warn, error)")
-		showHelp    = flag.Bool("help", false, "Show help information")
-		showVersion = flag.Bool("version", false, "Show version information")
-	)
-	flag.Parse()
-
-	if *showVersion {
-		fmt.Println("Semantic MCP Server v1.0.0")
-		os.Exit(0)
-	}
-
-	if *showHelp {
-		printHelp()
-		os.Exit(0)
-	}
-
-	// Set up logging
-	setupLogging(*logLevel)
-
-	// Create and configure the semantic server
-	server, err := semantic.New()
-	if err != nil {
-		log.Fatalf("Failed to create semantic server: %v", err)
-	}
-
-	// Initialize project discovery
-	if err := initializeProject(*projectRoot, *configFile); err != nil {
-		log.Fatalf("Failed to initialize project: %v", err)
-	}
-
-	// Set up graceful shutdown
-	sigChan := make(chan os.Signal, 1)
-	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-
-	go func() {
-		<-sigChan
-		log.Println("Shutting down semantic server...")
-		// Note: Shutdown is no longer available in the new pattern
-		// LSP managers are handled internally
-		os.Exit(0)
-	}()
-
-	// Run the server
-	log.Printf("Starting Semantic MCP Server (project: %s)", *projectRoot)
-	ctx := context.Background()
-	if err := server.Run(ctx); err != nil {
-		log.Fatalf("Server error: %v", err)
-	}
-}
-
-func printHelp() {
-	fmt.Print(`Semantic MCP Server - Intelligent code analysis and manipulation
-
-USAGE:
-    mcp-semantic [FLAGS]
-
-FLAGS:
-    --project-root <PATH>    Root directory of the project to analyze (default: ".")
-    --config <FILE>          Path to configuration file  
-    --log-level <LEVEL>      Log level: debug, info, warn, error (default: "info")
-    --help                   Show this help message
-    --version                Show version information
-
-DESCRIPTION:
-    The Semantic MCP Server provides AI assistants with intelligent, symbol-aware 
-    code operations. It leverages Language Server Protocol (LSP) to understand code 
-    structure and relationships across multiple programming languages.
-
-SUPPORTED LANGUAGES:
-    • Go          (via gopls)
-    • Rust        (via rust-analyzer)  
-    • Ruby        (via solargraph)
-    • Python      (via python-lsp-server)
-    • JavaScript  (via typescript-language-server)
-    • TypeScript  (via typescript-language-server)
-    • HTML        (via vscode-html-language-server)
-    • CSS         (via vscode-css-language-server)
-
-AVAILABLE TOOLS:
-    Symbol Discovery (Phase 1 - ✅ Complete):
-      • semantic_find_symbol        - Find symbols by name, type, or pattern
-      • semantic_get_overview       - Get high-level code structure overview
-      • semantic_get_definition     - Get detailed symbol information
-
-    Code Analysis (Phase 2 - ✅ Complete):
-      • semantic_get_references     - Find all symbol usages with context
-      • semantic_get_call_hierarchy - Understand calling relationships (incoming/outgoing)
-      • semantic_analyze_dependencies - Map symbol dependencies and relationships
-
-    Semantic Editing (Phase 3 - 🚧 Planned):
-      • semantic_replace_symbol     - Replace symbol implementations safely
-      • semantic_insert_after_symbol - Insert code after specific symbols
-      • semantic_rename_symbol      - Rename symbols across entire project
-
-LANGUAGE SERVER REQUIREMENTS:
-    Install the required language servers for your languages:
-
-    # Go
-    go install golang.org/x/tools/gopls@latest
-
-    # Rust  
-    rustup component add rust-analyzer
-
-    # Ruby
-    gem install solargraph
-
-    # Python
-    pip install python-lsp-server
-
-    # JavaScript/TypeScript
-    npm install -g typescript-language-server typescript
-
-    # HTML/CSS
-    npm install -g vscode-langservers-extracted
-
-EXAMPLES:
-    # Basic usage with current directory
-    mcp-semantic
-
-    # Analyze specific project
-    mcp-semantic --project-root /path/to/project
-
-    # With custom configuration
-    mcp-semantic --config semantic-config.json --log-level debug
-
-    # Find symbols in Go project
-    echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "semantic_find_symbol", "arguments": {"name": "main", "kind": "function", "language": "go"}}}' | mcp-semantic
-
-    # Get references to a function
-    echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "semantic_get_references", "arguments": {"symbol": "UserService.authenticate", "context_lines": 3}}}' | mcp-semantic
-
-    # Analyze call hierarchy
-    echo '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "semantic_get_call_hierarchy", "arguments": {"symbol": "main", "direction": "both", "max_depth": 3}}}' | mcp-semantic
-
-CONFIGURATION:
-    Create a semantic-config.json file for custom settings:
-    
-    {
-      "project": {
-        "exclude_patterns": ["**/vendor/**", "**/node_modules/**"]
-      },
-      "language_servers": {
-        "go": {"enabled": true, "timeout": 30},
-        "rust": {"enabled": true, "timeout": 60}
-      }
-    }
-
-FOR MORE INFORMATION:
-    • Design Document: cmd/mcp-semantic/DESIGN.md
-    • Implementation Plan: cmd/mcp-semantic/IMPLEMENTATION_PLAN.md
-    • GitHub: https://github.com/xlgmokha/mcp
-
-The Semantic MCP Server transforms how AI assistants work with code - from text 
-manipulation to true semantic understanding.
-`)
-}
-
-func setupLogging(level string) {
-	// Set up basic logging for now
-	// In a full implementation, this would configure structured logging
-	log.SetFlags(log.LstdFlags | log.Lshortfile)
-
-	switch level {
-	case "debug":
-		log.Println("Debug logging enabled")
-	case "info":
-		// Default level
-	case "warn", "error":
-		// For now, just note the level
-		log.Printf("Log level set to: %s", level)
-	}
-}
-
-func initializeProject(projectRoot, configFile string) error {
-	// This is a placeholder for project initialization
-	// In the full implementation, this would:
-	// 1. Load configuration from file if provided
-	// 2. Initialize project discovery
-	// 3. Start language servers as needed
-	// 4. Set up file watching
-
-	log.Printf("Initializing project at: %s", projectRoot)
-
-	if configFile != "" {
-		log.Printf("Loading configuration from: %s", configFile)
-		// TODO: Load and apply configuration
-	}
-
-	// TODO: Initialize project manager with the root path
-	// TODO: Start language server discovery
-	// TODO: Begin symbol indexing in background
-
-	return nil
-}
pkg/semantic/lsp_manager.go
@@ -1,571 +0,0 @@
-package semantic
-
-import (
-	"bufio"
-	"encoding/json"
-	"fmt"
-	"io"
-	"os/exec"
-	"sync"
-	"time"
-)
-
-// LSPManager manages connections to language servers
-type LSPManager struct {
-	clients    map[string]*LSPClient
-	configs    map[string]LanguageServerConfig
-	mu         sync.RWMutex
-	maxIdle    time.Duration
-	shutdownCh chan struct{}
-}
-
-// LSPClient represents a connection to a language server
-type LSPClient struct {
-	language  string
-	cmd       *exec.Cmd
-	stdin     io.WriteCloser
-	stdout    io.ReadCloser
-	stderr    io.ReadCloser
-	requestID int
-	responses map[int]chan LSPResponse
-	mu        sync.RWMutex
-	lastUsed  time.Time
-	healthy   bool
-}
-
-// NewLSPManager creates a new LSP manager
-func NewLSPManager() *LSPManager {
-	manager := &LSPManager{
-		clients:    make(map[string]*LSPClient),
-		configs:    DefaultLanguageServers,
-		maxIdle:    30 * time.Minute,
-		shutdownCh: make(chan struct{}),
-	}
-
-	// Start health monitoring
-	go manager.monitorHealth()
-
-	return manager
-}
-
-// GetClient gets or creates an LSP client for the specified language
-func (m *LSPManager) GetClient(language string) (*LSPClient, error) {
-	m.mu.RLock()
-	if client, exists := m.clients[language]; exists && client.IsHealthy() {
-		client.lastUsed = time.Now()
-		m.mu.RUnlock()
-		return client, nil
-	}
-	m.mu.RUnlock()
-
-	// Start new language server
-	return m.startLanguageServer(language)
-}
-
-// startLanguageServer starts a new language server process
-func (m *LSPManager) startLanguageServer(language string) (*LSPClient, error) {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-
-	config, exists := m.configs[language]
-	if !exists || !config.Enabled {
-		return nil, fmt.Errorf("language server not configured or disabled: %s", language)
-	}
-
-	// Check if command exists
-	if !commandExists(config.ServerCmd) {
-		return nil, fmt.Errorf("language server command not found: %s", config.ServerCmd)
-	}
-
-	// Start the language server process
-	cmd := exec.Command(config.ServerCmd, config.Args...)
-	
-	stdin, err := cmd.StdinPipe()
-	if err != nil {
-		return nil, fmt.Errorf("failed to create stdin pipe: %w", err)
-	}
-
-	stdout, err := cmd.StdoutPipe()
-	if err != nil {
-		return nil, fmt.Errorf("failed to create stdout pipe: %w", err)
-	}
-
-	stderr, err := cmd.StderrPipe()
-	if err != nil {
-		return nil, fmt.Errorf("failed to create stderr pipe: %w", err)
-	}
-
-	if err := cmd.Start(); err != nil {
-		return nil, fmt.Errorf("failed to start language server: %w", err)
-	}
-
-	client := &LSPClient{
-		language:  language,
-		cmd:       cmd,
-		stdin:     stdin,
-		stdout:    stdout,
-		stderr:    stderr,
-		responses: make(map[int]chan LSPResponse),
-		lastUsed:  time.Now(),
-		healthy:   true,
-	}
-
-	// Start response handler
-	go client.handleResponses()
-
-	// Initialize the language server
-	if err := client.initialize(); err != nil {
-		client.shutdown()
-		return nil, fmt.Errorf("failed to initialize language server: %w", err)
-	}
-
-	m.clients[language] = client
-	return client, nil
-}
-
-// initialize sends the initialize request to the language server
-func (c *LSPClient) initialize() error {
-	initParams := map[string]interface{}{
-		"processId": nil,
-		"capabilities": map[string]interface{}{
-			"textDocument": map[string]interface{}{
-				"documentSymbol": map[string]interface{}{
-					"symbolKind": map[string]interface{}{
-						"valueSet": []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
-					},
-					"hierarchicalDocumentSymbolSupport": true,
-				},
-				"definition": map[string]interface{}{
-					"linkSupport": true,
-				},
-				"references": map[string]interface{}{
-					"context": map[string]interface{}{
-						"includeDeclaration": true,
-					},
-				},
-				"callHierarchy": map[string]interface{}{},
-			},
-			"workspace": map[string]interface{}{
-				"symbol": map[string]interface{}{
-					"symbolKind": map[string]interface{}{
-						"valueSet": []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
-					},
-				},
-			},
-		},
-	}
-
-	response, err := c.SendRequest("initialize", initParams)
-	if err != nil {
-		return fmt.Errorf("initialize request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return fmt.Errorf("initialize request error: %s", response.Error.Message)
-	}
-
-	// Send initialized notification
-	return c.SendNotification("initialized", map[string]interface{}{})
-}
-
-// SendRequest sends a request and waits for response
-func (c *LSPClient) SendRequest(method string, params interface{}) (*LSPResponse, error) {
-	c.mu.Lock()
-	requestID := c.requestID
-	c.requestID++
-	
-	responseCh := make(chan LSPResponse, 1)
-	c.responses[requestID] = responseCh
-	c.mu.Unlock()
-
-	request := LSPRequest{
-		JSONRPC: "2.0",
-		ID:      requestID,
-		Method:  method,
-		Params:  params,
-	}
-
-	if err := c.writeMessage(request); err != nil {
-		c.mu.Lock()
-		delete(c.responses, requestID)
-		c.mu.Unlock()
-		return nil, fmt.Errorf("failed to send request: %w", err)
-	}
-
-	// Wait for response with timeout
-	select {
-	case response := <-responseCh:
-		return &response, nil
-	case <-time.After(30 * time.Second):
-		c.mu.Lock()
-		delete(c.responses, requestID)
-		c.mu.Unlock()
-		return nil, fmt.Errorf("request timeout: %s", method)
-	}
-}
-
-// SendNotification sends a notification (no response expected)
-func (c *LSPClient) SendNotification(method string, params interface{}) error {
-	notification := map[string]interface{}{
-		"jsonrpc": "2.0",
-		"method":  method,
-		"params":  params,
-	}
-
-	return c.writeMessage(notification)
-}
-
-// writeMessage writes a JSON-RPC message to the language server
-func (c *LSPClient) writeMessage(message interface{}) error {
-	data, err := json.Marshal(message)
-	if err != nil {
-		return fmt.Errorf("failed to marshal message: %w", err)
-	}
-
-	header := fmt.Sprintf("Content-Length: %d\r\n\r\n", len(data))
-	
-	if _, err := c.stdin.Write([]byte(header)); err != nil {
-		return fmt.Errorf("failed to write header: %w", err)
-	}
-
-	if _, err := c.stdin.Write(data); err != nil {
-		return fmt.Errorf("failed to write message: %w", err)
-	}
-
-	return nil
-}
-
-// handleResponses handles incoming responses from the language server
-func (c *LSPClient) handleResponses() {
-	scanner := bufio.NewScanner(c.stdout)
-	
-	for scanner.Scan() {
-		line := scanner.Text()
-		
-		// Skip headers and empty lines
-		if line == "" || line[0] != '{' {
-			continue
-		}
-
-		var response LSPResponse
-		if err := json.Unmarshal([]byte(line), &response); err != nil {
-			continue // Skip malformed responses
-		}
-
-		c.mu.RLock()
-		if ch, exists := c.responses[response.ID]; exists {
-			select {
-			case ch <- response:
-			default:
-				// Channel full, skip
-			}
-		}
-		c.mu.RUnlock()
-	}
-
-	// Mark as unhealthy if we reach here
-	c.mu.Lock()
-	c.healthy = false
-	c.mu.Unlock()
-}
-
-// IsHealthy checks if the LSP client is healthy
-func (c *LSPClient) IsHealthy() bool {
-	c.mu.RLock()
-	defer c.mu.RUnlock()
-	return c.healthy && c.cmd.Process != nil
-}
-
-// shutdown shuts down the LSP client
-func (c *LSPClient) shutdown() error {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-
-	c.healthy = false
-
-	// Send shutdown request
-	if c.stdin != nil {
-		c.SendNotification("shutdown", nil)
-		c.stdin.Close()
-	}
-
-	if c.stdout != nil {
-		c.stdout.Close()
-	}
-
-	if c.stderr != nil {
-		c.stderr.Close()
-	}
-
-	if c.cmd != nil && c.cmd.Process != nil {
-		return c.cmd.Process.Kill()
-	}
-
-	return nil
-}
-
-// monitorHealth monitors the health of language servers
-func (m *LSPManager) monitorHealth() {
-	ticker := time.NewTicker(30 * time.Second)
-	defer ticker.Stop()
-
-	for {
-		select {
-		case <-ticker.C:
-			m.cleanupUnhealthyClients()
-		case <-m.shutdownCh:
-			return
-		}
-	}
-}
-
-// cleanupUnhealthyClients removes unhealthy or idle clients
-func (m *LSPManager) cleanupUnhealthyClients() {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-
-	for language, client := range m.clients {
-		if !client.IsHealthy() || time.Since(client.lastUsed) > m.maxIdle {
-			client.shutdown()
-			delete(m.clients, language)
-		}
-	}
-}
-
-// Shutdown shuts down all language servers
-func (m *LSPManager) Shutdown() error {
-	// Close shutdown channel if not already closed
-	select {
-	case <-m.shutdownCh:
-		// Already closed
-	default:
-		close(m.shutdownCh)
-	}
-
-	m.mu.Lock()
-	defer m.mu.Unlock()
-
-	var lastErr error
-	for language, client := range m.clients {
-		if err := client.shutdown(); err != nil {
-			lastErr = err
-		}
-		delete(m.clients, language)
-	}
-
-	return lastErr
-}
-
-// GetReferences gets all references to a symbol at a given position
-func (c *LSPClient) GetReferences(filePath string, line, column int, includeDeclaration bool) ([]LSPLocation, error) {
-	params := map[string]interface{}{
-		"textDocument": map[string]interface{}{
-			"uri": "file://" + filePath,
-		},
-		"position": map[string]interface{}{
-			"line":      line - 1, // LSP uses 0-based lines
-			"character": column - 1,
-		},
-		"context": map[string]interface{}{
-			"includeDeclaration": includeDeclaration,
-		},
-	}
-
-	response, err := c.SendRequest("textDocument/references", params)
-	if err != nil {
-		return nil, fmt.Errorf("references request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("references error: %s", response.Error.Message)
-	}
-
-	// Parse response
-	var locations []LSPLocation
-	if result, ok := response.Result.([]interface{}); ok {
-		for _, item := range result {
-			if itemMap, ok := item.(map[string]interface{}); ok {
-				location := parseLSPLocation(itemMap)
-				locations = append(locations, location)
-			}
-		}
-	}
-
-	return locations, nil
-}
-
-// GetDefinition gets the definition location of a symbol
-func (c *LSPClient) GetDefinition(filePath string, line, column int) ([]LSPLocation, error) {
-	params := map[string]interface{}{
-		"textDocument": map[string]interface{}{
-			"uri": "file://" + filePath,
-		},
-		"position": map[string]interface{}{
-			"line":      line - 1,
-			"character": column - 1,
-		},
-	}
-
-	response, err := c.SendRequest("textDocument/definition", params)
-	if err != nil {
-		return nil, fmt.Errorf("definition request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("definition error: %s", response.Error.Message)
-	}
-
-	// Parse response
-	var locations []LSPLocation
-	if result, ok := response.Result.([]interface{}); ok {
-		for _, item := range result {
-			if itemMap, ok := item.(map[string]interface{}); ok {
-				location := parseLSPLocation(itemMap)
-				locations = append(locations, location)
-			}
-		}
-	}
-
-	return locations, nil
-}
-
-// PrepareCallHierarchy prepares call hierarchy for a symbol
-func (c *LSPClient) PrepareCallHierarchy(filePath string, line, column int) ([]map[string]interface{}, error) {
-	params := map[string]interface{}{
-		"textDocument": map[string]interface{}{
-			"uri": "file://" + filePath,
-		},
-		"position": map[string]interface{}{
-			"line":      line - 1,
-			"character": column - 1,
-		},
-	}
-
-	response, err := c.SendRequest("textDocument/prepareCallHierarchy", params)
-	if err != nil {
-		return nil, fmt.Errorf("prepareCallHierarchy request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("prepareCallHierarchy error: %s", response.Error.Message)
-	}
-
-	// Parse response
-	var items []map[string]interface{}
-	if result, ok := response.Result.([]interface{}); ok {
-		for _, item := range result {
-			if itemMap, ok := item.(map[string]interface{}); ok {
-				items = append(items, itemMap)
-			}
-		}
-	}
-
-	return items, nil
-}
-
-// GetIncomingCalls gets incoming calls for a call hierarchy item
-func (c *LSPClient) GetIncomingCalls(item map[string]interface{}) ([]map[string]interface{}, error) {
-	params := map[string]interface{}{
-		"item": item,
-	}
-
-	response, err := c.SendRequest("callHierarchy/incomingCalls", params)
-	if err != nil {
-		return nil, fmt.Errorf("incomingCalls request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("incomingCalls error: %s", response.Error.Message)
-	}
-
-	// Parse response
-	var calls []map[string]interface{}
-	if result, ok := response.Result.([]interface{}); ok {
-		for _, call := range result {
-			if callMap, ok := call.(map[string]interface{}); ok {
-				calls = append(calls, callMap)
-			}
-		}
-	}
-
-	return calls, nil
-}
-
-// GetOutgoingCalls gets outgoing calls for a call hierarchy item  
-func (c *LSPClient) GetOutgoingCalls(item map[string]interface{}) ([]map[string]interface{}, error) {
-	params := map[string]interface{}{
-		"item": item,
-	}
-
-	response, err := c.SendRequest("callHierarchy/outgoingCalls", params)
-	if err != nil {
-		return nil, fmt.Errorf("outgoingCalls request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("outgoingCalls error: %s", response.Error.Message)
-	}
-
-	// Parse response
-	var calls []map[string]interface{}
-	if result, ok := response.Result.([]interface{}); ok {
-		for _, call := range result {
-			if callMap, ok := call.(map[string]interface{}); ok {
-				calls = append(calls, callMap)
-			}
-		}
-	}
-
-	return calls, nil
-}
-
-// parseLSPLocation parses an LSP location object
-func parseLSPLocation(data map[string]interface{}) LSPLocation {
-	location := LSPLocation{}
-	
-	if uri, ok := data["uri"].(string); ok {
-		location.URI = uri
-	}
-	
-	if rng, ok := data["range"].(map[string]interface{}); ok {
-		location.Range = parseLSPRange(rng)
-	}
-	
-	return location
-}
-
-// parseLSPRange parses an LSP range object
-func parseLSPRange(data map[string]interface{}) LSPRange {
-	rng := LSPRange{}
-	
-	if start, ok := data["start"].(map[string]interface{}); ok {
-		rng.Start = parseLSPPosition(start)
-	}
-	
-	if end, ok := data["end"].(map[string]interface{}); ok {
-		rng.End = parseLSPPosition(end)
-	}
-	
-	return rng
-}
-
-// parseLSPPosition parses an LSP position object
-func parseLSPPosition(data map[string]interface{}) LSPPosition {
-	pos := LSPPosition{}
-	
-	if line, ok := data["line"].(float64); ok {
-		pos.Line = int(line)
-	}
-	
-	if char, ok := data["character"].(float64); ok {
-		pos.Character = int(char)
-	}
-	
-	return pos
-}
-
-// commandExists checks if a command is available in PATH
-func commandExists(cmd string) bool {
-	_, err := exec.LookPath(cmd)
-	return err == nil
-}
\ No newline at end of file
pkg/semantic/project_manager.go
@@ -1,384 +0,0 @@
-package semantic
-
-import (
-	"fmt"
-	"io/fs"
-	"os"
-	"path/filepath"
-	"strings"
-	"sync"
-	"time"
-)
-
-// ProjectManager manages project context and boundaries
-type ProjectManager struct {
-	rootPath      string
-	config        *ProjectConfig
-	languageFiles map[string][]string // language -> file_paths
-	excludeRules  []string
-	mu            sync.RWMutex
-}
-
-// FileInfo represents information about a file
-type FileInfo struct {
-	Path    string
-	Size    int64
-	ModTime time.Time
-	IsDir   bool
-}
-
-// NewProjectManager creates a new project manager
-func NewProjectManager() *ProjectManager {
-	return &ProjectManager{
-		languageFiles: make(map[string][]string),
-		excludeRules: []string{
-			"**/node_modules/**",
-			"**/vendor/**",
-			"**/.git/**",
-			"**/target/**",
-			"**/dist/**",
-			"**/build/**",
-			"**/*.min.js",
-			"**/*.min.css",
-		},
-	}
-}
-
-// DiscoverProject initializes project discovery from a root path
-func (pm *ProjectManager) DiscoverProject(rootPath string) error {
-	pm.mu.Lock()
-	defer pm.mu.Unlock()
-
-	absPath, err := filepath.Abs(rootPath)
-	if err != nil {
-		return fmt.Errorf("failed to get absolute path: %w", err)
-	}
-
-	pm.rootPath = absPath
-
-	// Initialize project config
-	pm.config = &ProjectConfig{
-		Name:            filepath.Base(absPath),
-		RootPath:        absPath,
-		Languages:       []string{},
-		ExcludePatterns: pm.excludeRules,
-		IncludePatterns: []string{"**/*"},
-		CustomSettings:  make(map[string]string),
-	}
-
-	// Scan for files and detect languages
-	if err := pm.scanProject(); err != nil {
-		return fmt.Errorf("failed to scan project: %w", err)
-	}
-
-	return nil
-}
-
-// scanProject scans the project and categorizes files by language
-func (pm *ProjectManager) scanProject() error {
-	pm.languageFiles = make(map[string][]string)
-
-	err := filepath.WalkDir(pm.rootPath, func(path string, d fs.DirEntry, err error) error {
-		if err != nil {
-			return nil // Continue on errors
-		}
-
-		// Skip excluded paths
-		if pm.shouldExclude(path) {
-			if d.IsDir() {
-				return filepath.SkipDir
-			}
-			return nil
-		}
-
-		// Only process files
-		if d.IsDir() {
-			return nil
-		}
-
-		// Detect language and add to appropriate list
-		language := pm.detectLanguage(path)
-		if language != "" {
-			pm.languageFiles[language] = append(pm.languageFiles[language], path)
-			
-			// Add to supported languages if not already present
-			found := false
-			for _, lang := range pm.config.Languages {
-				if lang == language {
-					found = true
-					break
-				}
-			}
-			if !found {
-				pm.config.Languages = append(pm.config.Languages, language)
-			}
-		}
-
-		return nil
-	})
-
-	return err
-}
-
-// shouldExclude checks if a path should be excluded based on patterns
-func (pm *ProjectManager) shouldExclude(path string) bool {
-	relPath, err := filepath.Rel(pm.rootPath, path)
-	if err != nil {
-		return true
-	}
-
-	for _, pattern := range pm.excludeRules {
-		if matched, _ := filepath.Match(pattern, relPath); matched {
-			return true
-		}
-
-		// Handle ** patterns manually
-		if strings.Contains(pattern, "**") {
-			pattern = strings.ReplaceAll(pattern, "**", "*")
-			if matched, _ := filepath.Match(pattern, relPath); matched {
-				return true
-			}
-		}
-
-		// Check if any parent directory matches
-		parts := strings.Split(relPath, string(filepath.Separator))
-		for i := range parts {
-			partialPath := strings.Join(parts[:i+1], string(filepath.Separator))
-			if matched, _ := filepath.Match(pattern, partialPath); matched {
-				return true
-			}
-		}
-	}
-
-	return false
-}
-
-// detectLanguage detects the programming language from file extension
-func (pm *ProjectManager) detectLanguage(filePath string) string {
-	ext := strings.ToLower(filepath.Ext(filePath))
-
-	for language, config := range DefaultLanguageServers {
-		for _, supportedExt := range config.FileExts {
-			if ext == supportedExt {
-				return language
-			}
-		}
-	}
-
-	return ""
-}
-
-// GetSupportedLanguages returns list of detected languages in the project
-func (pm *ProjectManager) GetSupportedLanguages() []string {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-
-	if pm.config == nil {
-		return []string{}
-	}
-
-	return pm.config.Languages
-}
-
-// GetFilesByLanguage returns all files for a specific language
-func (pm *ProjectManager) GetFilesByLanguage(language string) []string {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-
-	files, exists := pm.languageFiles[language]
-	if !exists {
-		return []string{}
-	}
-
-	// Return a copy to avoid race conditions
-	result := make([]string, len(files))
-	copy(result, files)
-	return result
-}
-
-// GetFilesInDirectory returns all supported files in a directory
-func (pm *ProjectManager) GetFilesInDirectory(dirPath string) []string {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-
-	var files []string
-
-	// Convert to absolute path if relative
-	if !filepath.IsAbs(dirPath) {
-		dirPath = filepath.Join(pm.rootPath, dirPath)
-	}
-
-	// Walk the directory
-	filepath.WalkDir(dirPath, func(path string, d fs.DirEntry, err error) error {
-		if err != nil {
-			return nil
-		}
-
-		if d.IsDir() {
-			return nil
-		}
-
-		// Check if file is supported
-		if pm.detectLanguage(path) != "" && !pm.shouldExclude(path) {
-			files = append(files, path)
-		}
-
-		return nil
-	})
-
-	return files
-}
-
-// IsFileInProject checks if a file is within project boundaries
-func (pm *ProjectManager) IsFileInProject(filePath string) bool {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-
-	if pm.rootPath == "" {
-		return false
-	}
-
-	absPath, err := filepath.Abs(filePath)
-	if err != nil {
-		return false
-	}
-
-	// Check if file is under project root
-	relPath, err := filepath.Rel(pm.rootPath, absPath)
-	if err != nil || strings.HasPrefix(relPath, "..") {
-		return false
-	}
-
-	// Check if file should be excluded
-	return !pm.shouldExclude(absPath)
-}
-
-// ReadFile reads the contents of a file
-func (pm *ProjectManager) ReadFile(filePath string) ([]byte, error) {
-	if !pm.IsFileInProject(filePath) {
-		return nil, fmt.Errorf("file is outside project boundaries: %s", filePath)
-	}
-
-	return os.ReadFile(filePath)
-}
-
-// GetFileInfo gets information about a file
-func (pm *ProjectManager) GetFileInfo(filePath string) (*FileInfo, error) {
-	if !pm.IsFileInProject(filePath) {
-		return nil, fmt.Errorf("file is outside project boundaries: %s", filePath)
-	}
-
-	stat, err := os.Stat(filePath)
-	if err != nil {
-		return nil, fmt.Errorf("failed to stat file: %w", err)
-	}
-
-	return &FileInfo{
-		Path:    filePath,
-		Size:    stat.Size(),
-		ModTime: stat.ModTime(),
-		IsDir:   stat.IsDir(),
-	}, nil
-}
-
-// GetProjectStats returns statistics about the project
-func (pm *ProjectManager) GetProjectStats() map[string]interface{} {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-
-	stats := make(map[string]interface{})
-	
-	if pm.config != nil {
-		stats["name"] = pm.config.Name
-		stats["root_path"] = pm.config.RootPath
-		stats["languages"] = pm.config.Languages
-	}
-
-	stats["files_by_language"] = make(map[string]int)
-	totalFiles := 0
-	
-	for language, files := range pm.languageFiles {
-		count := len(files)
-		stats["files_by_language"].(map[string]int)[language] = count
-		totalFiles += count
-	}
-	
-	stats["total_files"] = totalFiles
-
-	return stats
-}
-
-// GetRootPath returns the project root path
-func (pm *ProjectManager) GetRootPath() string {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-	return pm.rootPath
-}
-
-// GetConfig returns the project configuration
-func (pm *ProjectManager) GetConfig() *ProjectConfig {
-	pm.mu.RLock()
-	defer pm.mu.RUnlock()
-	
-	if pm.config == nil {
-		return nil
-	}
-
-	// Return a copy
-	config := *pm.config
-	config.Languages = make([]string, len(pm.config.Languages))
-	copy(config.Languages, pm.config.Languages)
-	
-	config.ExcludePatterns = make([]string, len(pm.config.ExcludePatterns))
-	copy(config.ExcludePatterns, pm.config.ExcludePatterns)
-	
-	config.IncludePatterns = make([]string, len(pm.config.IncludePatterns))
-	copy(config.IncludePatterns, pm.config.IncludePatterns)
-	
-	config.CustomSettings = make(map[string]string)
-	for k, v := range pm.config.CustomSettings {
-		config.CustomSettings[k] = v
-	}
-
-	return &config
-}
-
-// SetExcludePatterns sets custom exclude patterns
-func (pm *ProjectManager) SetExcludePatterns(patterns []string) {
-	pm.mu.Lock()
-	defer pm.mu.Unlock()
-
-	pm.excludeRules = patterns
-	if pm.config != nil {
-		pm.config.ExcludePatterns = patterns
-	}
-
-	// Re-scan project with new patterns
-	if pm.rootPath != "" {
-		pm.scanProject()
-	}
-}
-
-// AddExcludePattern adds a new exclude pattern
-func (pm *ProjectManager) AddExcludePattern(pattern string) {
-	pm.mu.Lock()
-	defer pm.mu.Unlock()
-
-	pm.excludeRules = append(pm.excludeRules, pattern)
-	if pm.config != nil {
-		pm.config.ExcludePatterns = append(pm.config.ExcludePatterns, pattern)
-	}
-}
-
-// Shutdown gracefully shuts down the project manager
-func (pm *ProjectManager) Shutdown() error {
-	pm.mu.Lock()
-	defer pm.mu.Unlock()
-
-	// Clear all data
-	pm.languageFiles = make(map[string][]string)
-	pm.config = nil
-	pm.rootPath = ""
-
-	return nil
-}
\ No newline at end of file
pkg/semantic/server.go
@@ -1,561 +0,0 @@
-package semantic
-
-import (
-	"encoding/json"
-	"fmt"
-	"sync"
-
-	"github.com/xlgmokha/mcp/pkg/mcp"
-)
-
-// SemanticOperations provides semantic analysis operations
-type SemanticOperations struct {
-	lspManager    *LSPManager
-	symbolManager *SymbolManager
-	projectManager *ProjectManager
-	mu            sync.RWMutex
-}
-
-// NewSemanticOperations creates a new SemanticOperations helper
-func NewSemanticOperations() (*SemanticOperations, error) {
-	lspManager := NewLSPManager()
-	projectManager := NewProjectManager()
-	symbolManager := NewSymbolManager(lspManager, projectManager)
-	
-	return &SemanticOperations{
-		lspManager:     lspManager,
-		symbolManager:  symbolManager,
-		projectManager: projectManager,
-	}, nil
-}
-
-// New creates a new Semantic MCP server
-func New() (*mcp.Server, error) {
-	semantic, err := NewSemanticOperations()
-	if err != nil {
-		return nil, err
-	}
-	
-	builder := mcp.NewServerBuilder("mcp-semantic", "1.0.0")
-
-// Add semantic_find_symbol tool
-	builder.AddTool(mcp.NewTool("semantic_find_symbol", "Find symbols by name, type, or pattern across the project", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"query": map[string]interface{}{
-				"type":        "string",
-				"description": "Symbol name or pattern to search for",
-			},
-			"symbol_type": map[string]interface{}{
-				"type":        "string",
-				"description": "Type of symbol to search for (function, class, variable, etc.)",
-				"enum":        []string{"function", "class", "variable", "interface", "type", "constant", "module"},
-			},
-			"language": map[string]interface{}{
-				"type":        "string",
-				"description": "Programming language to filter by (optional)",
-				"enum":        []string{"go", "rust", "typescript", "javascript", "python", "java", "cpp"},
-			},
-			"case_sensitive": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Whether the search should be case sensitive (default: false)",
-			},
-			"exact_match": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Whether to match the exact symbol name (default: false, allows partial matches)",
-			},
-		},
-		"required": []string{"query"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleFindSymbol(req)
-	}))
-
-	// Add semantic_get_overview tool
-	builder.AddTool(mcp.NewTool("semantic_get_overview", "Get a high-level overview of symbols and structure in a file or directory", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"path": map[string]interface{}{
-				"type":        "string",
-				"description": "File or directory path to analyze",
-			},
-			"depth": map[string]interface{}{
-				"type":        "integer",
-				"description": "Depth of analysis (1=top-level only, 2=include immediate children, etc.) (default: 2)",
-				"minimum":     1,
-				"maximum":     5,
-			},
-			"include_private": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Include private/internal symbols (default: false)",
-			},
-			"group_by": map[string]interface{}{
-				"type":        "string",
-				"description": "How to group the results (type, file, module) (default: type)",
-				"enum":        []string{"type", "file", "module"},
-			},
-		},
-		"required": []string{"path"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleGetOverview(req)
-	}))
-
-	// Add semantic_get_definition tool
-	builder.AddTool(mcp.NewTool("semantic_get_definition", "Get the definition location and details for a specific symbol", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"symbol": map[string]interface{}{
-				"type":        "string",
-				"description": "Symbol name to find definition for",
-			},
-			"file": map[string]interface{}{
-				"type":        "string",
-				"description": "File path where the symbol is referenced (helps with context)",
-			},
-			"line": map[string]interface{}{
-				"type":        "integer",
-				"description": "Line number where the symbol is referenced (optional, for better precision)",
-				"minimum":     1,
-			},
-			"column": map[string]interface{}{
-				"type":        "integer",
-				"description": "Column number where the symbol is referenced (optional, for better precision)",
-				"minimum":     1,
-			},
-			"include_signature": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Include full function/method signature (default: true)",
-			},
-		},
-		"required": []string{"symbol"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleGetDefinition(req)
-	}))
-
-	// Add semantic_get_references tool
-	builder.AddTool(mcp.NewTool("semantic_get_references", "Find all references to a specific symbol across the project", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"symbol": map[string]interface{}{
-				"type":        "string",
-				"description": "Symbol name to find references for",
-			},
-			"file": map[string]interface{}{
-				"type":        "string",
-				"description": "File path where the symbol is defined (helps with context)",
-			},
-			"line": map[string]interface{}{
-				"type":        "integer",
-				"description": "Line number where the symbol is defined (optional, for better precision)",
-				"minimum":     1,
-			},
-			"include_declaration": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Include the symbol declaration in results (default: true)",
-			},
-			"scope": map[string]interface{}{
-				"type":        "string",
-				"description": "Scope of search (file, directory, project) (default: project)",
-				"enum":        []string{"file", "directory", "project"},
-			},
-		},
-		"required": []string{"symbol"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleGetReferences(req)
-	}))
-
-	// Add semantic_get_call_hierarchy tool
-	builder.AddTool(mcp.NewTool("semantic_get_call_hierarchy", "Get the call hierarchy (callers and callees) for a function or method", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"symbol": map[string]interface{}{
-				"type":        "string",
-				"description": "Function or method name to analyze",
-			},
-			"file": map[string]interface{}{
-				"type":        "string",
-				"description": "File path where the function is defined",
-			},
-			"line": map[string]interface{}{
-				"type":        "integer",
-				"description": "Line number where the function is defined (optional)",
-				"minimum":     1,
-			},
-			"direction": map[string]interface{}{
-				"type":        "string",
-				"description": "Direction of call hierarchy (incoming=who calls this, outgoing=what this calls, both) (default: both)",
-				"enum":        []string{"incoming", "outgoing", "both"},
-			},
-			"depth": map[string]interface{}{
-				"type":        "integer",
-				"description": "Depth of call hierarchy to retrieve (default: 3)",
-				"minimum":     1,
-				"maximum":     10,
-			},
-		},
-		"required": []string{"symbol", "file"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleGetCallHierarchy(req)
-	}))
-
-	// Add semantic_analyze_dependencies tool
-	builder.AddTool(mcp.NewTool("semantic_analyze_dependencies", "Analyze dependencies and relationships between modules, files, or symbols", map[string]interface{}{
-		"type": "object",
-		"properties": map[string]interface{}{
-			"path": map[string]interface{}{
-				"type":        "string",
-				"description": "Path to analyze (file, directory, or project root)",
-			},
-			"analysis_type": map[string]interface{}{
-				"type":        "string",
-				"description": "Type of dependency analysis to perform (default: imports)",
-				"enum":        []string{"imports", "exports", "modules", "symbols", "circular"},
-			},
-			"include_external": map[string]interface{}{
-				"type":        "boolean",
-				"description": "Include external/third-party dependencies (default: false)",
-			},
-			"format": map[string]interface{}{
-				"type":        "string",
-				"description": "Output format (tree, graph, list) (default: tree)",
-				"enum":        []string{"tree", "graph", "list"},
-			},
-			"max_depth": map[string]interface{}{
-				"type":        "integer",
-				"description": "Maximum depth of dependency analysis (default: 5)",
-				"minimum":     1,
-				"maximum":     20,
-			},
-		},
-		"required": []string{"path"},
-	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-		return semantic.handleAnalyzeDependencies(req)
-	}))
-
-	return builder.Build(), nil
-}
-
-
-// handleFindSymbol finds symbols by name, type, or pattern across the project
-func (semantic *SemanticOperations) handleFindSymbol(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Name            string   `json:"name"`                      // Symbol path or pattern
-		Kind            string   `json:"kind,omitempty"`            // function, class, variable, etc.
-		Scope           string   `json:"scope,omitempty"`           // project, file, directory
-		Language        string   `json:"language,omitempty"`        // Optional language filter
-		IncludeChildren bool     `json:"include_children,omitempty"` // Include child symbols
-		MaxResults      int      `json:"max_results,omitempty"`     // Limit results
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Name == "" {
-		return mcp.CallToolResult{}, fmt.Errorf("name is required")
-	}
-
-	// Set defaults
-	if args.Scope == "" {
-		args.Scope = "project"
-	}
-	if args.MaxResults == 0 {
-		args.MaxResults = 50
-	}
-
-	// Build query
-	query := SymbolQuery{
-		Name:            args.Name,
-		Kind:            SymbolKind(args.Kind),
-		Scope:           args.Scope,
-		Language:        args.Language,
-		IncludeChildren: args.IncludeChildren,
-		MaxResults:      args.MaxResults,
-	}
-
-	// Find symbols
-	symbols, err := semantic.symbolManager.FindSymbols(query)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to find symbols: %w", err)
-	}
-
-	// Format response
-	responseData := map[string]interface{}{
-		"symbols":     symbols,
-		"total_found": len(symbols),
-		"query":       query,
-	}
-
-	responseJSON, _ := json.MarshalIndent(responseData, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Found %d symbols matching '%s':\n\n%s", 
-					len(symbols), args.Name, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// handleGetOverview gets high-level symbol overview of files or directories
-func (semantic *SemanticOperations) handleGetOverview(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Path           string   `json:"path"`                      // File or directory path
-		Depth          int      `json:"depth,omitempty"`           // How deep to analyze
-		IncludeKinds   []string `json:"include_kinds,omitempty"`   // Filter symbol types
-		ExcludePrivate bool     `json:"exclude_private,omitempty"` // Skip private symbols
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Path == "" {
-		return mcp.CallToolResult{}, fmt.Errorf("path is required")
-	}
-
-	// Set defaults
-	if args.Depth == 0 {
-		args.Depth = 2
-	}
-
-	// Get overview
-	overview, err := semantic.symbolManager.GetOverview(args.Path, args.Depth, args.IncludeKinds, args.ExcludePrivate)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to get overview: %w", err)
-	}
-
-	// Format response
-	responseJSON, _ := json.MarshalIndent(overview, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Symbol overview for '%s':\n\n%s", args.Path, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// handleGetDefinition gets detailed information about a symbol's definition
-func (semantic *SemanticOperations) handleGetDefinition(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Symbol              string `json:"symbol"`                        // Target symbol
-		IncludeSignature    bool   `json:"include_signature,omitempty"`    // Include full signature
-		IncludeDocumentation bool   `json:"include_documentation,omitempty"` // Include comments/docs
-		IncludeDependencies bool   `json:"include_dependencies,omitempty"` // Include what this symbol uses
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Symbol == "" {
-		return mcp.CallToolResult{}, fmt.Errorf("symbol is required")
-	}
-
-	// Get definition
-	definition, err := semantic.symbolManager.GetDefinition(args.Symbol, args.IncludeSignature, args.IncludeDocumentation, args.IncludeDependencies)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to get definition: %w", err)
-	}
-
-	// Format response
-	responseJSON, _ := json.MarshalIndent(definition, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Definition for symbol '%s':\n\n%s", args.Symbol, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// handleGetReferences finds all places where a symbol is used
-func (semantic *SemanticOperations) handleGetReferences(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Symbol              string   `json:"symbol"`                        // Target symbol
-		IncludeDefinitions  bool     `json:"include_definitions,omitempty"` // Include definition location
-		ContextLines        int      `json:"context_lines,omitempty"`       // Lines of context around usage
-		FilterByKind        []string `json:"filter_by_kind,omitempty"`      // Type of references
-		Language            string   `json:"language,omitempty"`            // Language filter
-		IncludeExternal     bool     `json:"include_external,omitempty"`    // Include external package references
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Symbol == "" {
-		return mcp.CallToolResult{}, fmt.Errorf("symbol is required")
-	}
-
-	// Set defaults
-	if args.ContextLines == 0 {
-		args.ContextLines = 3
-	}
-
-	// Get references
-	references, err := semantic.symbolManager.GetReferences(args.Symbol, args.IncludeDefinitions, args.ContextLines, args.FilterByKind, args.Language, args.IncludeExternal)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to get references: %w", err)
-	}
-
-	// Format response
-	responseData := map[string]interface{}{
-		"symbol":          args.Symbol,
-		"references":      references.References,
-		"total_found":     len(references.References),
-		"definition":      references.Definition,
-		"context_lines":   args.ContextLines,
-		"include_external": args.IncludeExternal,
-	}
-
-	responseJSON, _ := json.MarshalIndent(responseData, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Found %d references for symbol '%s':\n\n%s", 
-					len(references.References), args.Symbol, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// handleGetCallHierarchy understands calling relationships (what calls this, what this calls)
-func (semantic *SemanticOperations) handleGetCallHierarchy(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Symbol          string `json:"symbol"`                    // Target symbol
-		Direction       string `json:"direction,omitempty"`       // "incoming", "outgoing", "both"
-		MaxDepth        int    `json:"max_depth,omitempty"`       // How many levels deep
-		IncludeExternal bool   `json:"include_external,omitempty"` // Include calls to external packages
-		Language        string `json:"language,omitempty"`        // Language filter
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Symbol == "" {
-		return mcp.CallToolResult{}, fmt.Errorf("symbol is required")
-	}
-
-	// Set defaults
-	if args.Direction == "" {
-		args.Direction = "both"
-	}
-	if args.MaxDepth == 0 {
-		args.MaxDepth = 3
-	}
-
-	// Get call hierarchy
-	hierarchy, err := semantic.symbolManager.GetCallHierarchy(args.Symbol, args.Direction, args.MaxDepth, args.IncludeExternal, args.Language)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to get call hierarchy: %w", err)
-	}
-
-	// Format response
-	responseJSON, _ := json.MarshalIndent(hierarchy, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Call hierarchy for symbol '%s' (direction: %s, depth: %d):\n\n%s", 
-					args.Symbol, args.Direction, args.MaxDepth, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// handleAnalyzeDependencies analyzes symbol dependencies and relationships  
-func (semantic *SemanticOperations) handleAnalyzeDependencies(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	semantic.mu.RLock()
-	defer semantic.mu.RUnlock()
-
-	var args struct {
-		Scope           string `json:"scope"`                     // Analysis scope: "file", "package", "project"
-		Path            string `json:"path,omitempty"`            // Specific path to analyze
-		IncludeExternal bool   `json:"include_external,omitempty"` // Include external dependencies
-		GroupBy         string `json:"group_by,omitempty"`        // "file", "package", "kind"
-		ShowUnused      bool   `json:"show_unused,omitempty"`     // Highlight unused symbols
-		Language        string `json:"language,omitempty"`        // Language filter
-	}
-
-	argsBytes, _ := json.Marshal(req.Arguments)
-	if err := json.Unmarshal(argsBytes, &args); err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("invalid arguments: %w", err)
-	}
-
-	if args.Scope == "" {
-		args.Scope = "project"
-	}
-	if args.GroupBy == "" {
-		args.GroupBy = "package"
-	}
-
-	// Analyze dependencies
-	analysis, err := semantic.symbolManager.AnalyzeDependencies(args.Scope, args.Path, args.IncludeExternal, args.GroupBy, args.ShowUnused, args.Language)
-	if err != nil {
-		return mcp.CallToolResult{}, fmt.Errorf("failed to analyze dependencies: %w", err)
-	}
-
-	// Format response
-	responseJSON, _ := json.MarshalIndent(analysis, "", "  ")
-
-	return mcp.CallToolResult{
-		Content: []mcp.Content{
-			mcp.TextContent{
-				Type: "text",
-				Text: fmt.Sprintf("Dependency analysis for scope '%s' (grouped by %s):\n\n%s", 
-					args.Scope, args.GroupBy, string(responseJSON)),
-			},
-		},
-	}, nil
-}
-
-// Shutdown gracefully shuts down the semantic server
-func (semantic *SemanticOperations) Shutdown() error {
-	semantic.mu.Lock()
-	defer semantic.mu.Unlock()
-
-	if semantic.lspManager != nil {
-		if err := semantic.lspManager.Shutdown(); err != nil {
-			return fmt.Errorf("failed to shutdown LSP manager: %w", err)
-		}
-	}
-
-	if semantic.projectManager != nil {
-		if err := semantic.projectManager.Shutdown(); err != nil {
-			return fmt.Errorf("failed to shutdown project manager: %w", err)
-		}
-	}
-
-	return nil
-}
\ No newline at end of file
pkg/semantic/symbol_manager.go
@@ -1,829 +0,0 @@
-package semantic
-
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-	"sync"
-	"time"
-)
-
-// SymbolManager manages symbol discovery and caching
-type SymbolManager struct {
-	lspManager     *LSPManager
-	projectManager *ProjectManager
-	cache          *SymbolCache
-	mu             sync.RWMutex
-}
-
-// NewSymbolManager creates a new symbol manager
-func NewSymbolManager(lspManager *LSPManager, projectManager *ProjectManager) *SymbolManager {
-	return &SymbolManager{
-		lspManager:     lspManager,
-		projectManager: projectManager,
-		cache: &SymbolCache{
-			Symbols:    make(map[string][]Symbol),
-			References: make(map[string][]SourceLocation),
-			Index:      make(map[string][]string),
-			LastUpdate: make(map[string]time.Time),
-		},
-	}
-}
-
-// FindSymbols finds symbols matching the given query
-func (sm *SymbolManager) FindSymbols(query SymbolQuery) ([]Symbol, error) {
-	sm.mu.RLock()
-	defer sm.mu.RUnlock()
-
-	switch query.Scope {
-	case "project":
-		return sm.findSymbolsInProject(query)
-	case "file":
-		if query.Language == "" {
-			return nil, fmt.Errorf("language must be specified for file scope")
-		}
-		return sm.findSymbolsInFile(query.Name, query)
-	case "directory":
-		return sm.findSymbolsInDirectory(query.Name, query)
-	default:
-		return sm.findSymbolsInProject(query)
-	}
-}
-
-// findSymbolsInProject finds symbols across the entire project
-func (sm *SymbolManager) findSymbolsInProject(query SymbolQuery) ([]Symbol, error) {
-	var allResults []Symbol
-
-	// Get project files by language
-	languages := sm.projectManager.GetSupportedLanguages()
-	if query.Language != "" {
-		languages = []string{query.Language}
-	}
-
-	for _, language := range languages {
-		files := sm.projectManager.GetFilesByLanguage(language)
-		
-		for _, file := range files {
-			symbols, err := sm.getSymbolsFromFile(file, language)
-			if err != nil {
-				continue // Skip files with errors
-			}
-
-			// Filter symbols by query
-			filtered := sm.filterSymbols(symbols, query)
-			allResults = append(allResults, filtered...)
-
-			// Respect max results limit
-			if len(allResults) >= query.MaxResults {
-				break
-			}
-		}
-
-		if len(allResults) >= query.MaxResults {
-			break
-		}
-	}
-
-	// Trim to max results
-	if len(allResults) > query.MaxResults {
-		allResults = allResults[:query.MaxResults]
-	}
-
-	return allResults, nil
-}
-
-// findSymbolsInFile finds symbols in a specific file
-func (sm *SymbolManager) findSymbolsInFile(filePath string, query SymbolQuery) ([]Symbol, error) {
-	language := sm.detectLanguageFromFile(filePath)
-	if language == "" {
-		return nil, fmt.Errorf("unsupported file type: %s", filePath)
-	}
-
-	symbols, err := sm.getSymbolsFromFile(filePath, language)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get symbols from file: %w", err)
-	}
-
-	return sm.filterSymbols(symbols, query), nil
-}
-
-// findSymbolsInDirectory finds symbols in a directory
-func (sm *SymbolManager) findSymbolsInDirectory(dirPath string, query SymbolQuery) ([]Symbol, error) {
-	var allResults []Symbol
-
-	files := sm.projectManager.GetFilesInDirectory(dirPath)
-	
-	for _, file := range files {
-		language := sm.detectLanguageFromFile(file)
-		if language == "" || (query.Language != "" && language != query.Language) {
-			continue
-		}
-
-		symbols, err := sm.getSymbolsFromFile(file, language)
-		if err != nil {
-			continue
-		}
-
-		filtered := sm.filterSymbols(symbols, query)
-		allResults = append(allResults, filtered...)
-
-		if len(allResults) >= query.MaxResults {
-			break
-		}
-	}
-
-	if len(allResults) > query.MaxResults {
-		allResults = allResults[:query.MaxResults]
-	}
-
-	return allResults, nil
-}
-
-// getSymbolsFromFile gets symbols from a file (with caching)
-func (sm *SymbolManager) getSymbolsFromFile(filePath string, language string) ([]Symbol, error) {
-	// Check cache first
-	if symbols, cached := sm.getCachedSymbols(filePath); cached {
-		return symbols, nil
-	}
-
-	// Get LSP client for the language
-	client, err := sm.lspManager.GetClient(language)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get LSP client for %s: %w", language, err)
-	}
-
-	// Open document in LSP
-	if err := sm.openDocument(client, filePath); err != nil {
-		return nil, fmt.Errorf("failed to open document: %w", err)
-	}
-
-	// Get document symbols
-	symbols, err := sm.getDocumentSymbols(client, filePath, language)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get document symbols: %w", err)
-	}
-
-	// Cache the symbols
-	sm.cacheSymbols(filePath, symbols)
-
-	return symbols, nil
-}
-
-// getCachedSymbols checks if symbols are cached for a file
-func (sm *SymbolManager) getCachedSymbols(filePath string) ([]Symbol, bool) {
-	symbols, exists := sm.cache.Symbols[filePath]
-	if !exists {
-		return nil, false
-	}
-
-	// Check if cache is still valid (file hasn't been modified)
-	lastUpdate, hasUpdate := sm.cache.LastUpdate[filePath]
-	if !hasUpdate {
-		return symbols, true
-	}
-
-	fileInfo, err := sm.projectManager.GetFileInfo(filePath)
-	if err != nil || fileInfo.ModTime.After(lastUpdate) {
-		// Cache is stale
-		delete(sm.cache.Symbols, filePath)
-		delete(sm.cache.LastUpdate, filePath)
-		return nil, false
-	}
-
-	return symbols, true
-}
-
-// cacheSymbols caches symbols for a file
-func (sm *SymbolManager) cacheSymbols(filePath string, symbols []Symbol) {
-	sm.cache.Symbols[filePath] = symbols
-	sm.cache.LastUpdate[filePath] = time.Now()
-
-	// Update index
-	for _, symbol := range symbols {
-		if files, exists := sm.cache.Index[symbol.Name]; exists {
-			// Add file if not already present
-			found := false
-			for _, file := range files {
-				if file == filePath {
-					found = true
-					break
-				}
-			}
-			if !found {
-				sm.cache.Index[symbol.Name] = append(files, filePath)
-			}
-		} else {
-			sm.cache.Index[symbol.Name] = []string{filePath}
-		}
-	}
-}
-
-// openDocument opens a document in the language server
-func (sm *SymbolManager) openDocument(client *LSPClient, filePath string) error {
-	content, err := sm.projectManager.ReadFile(filePath)
-	if err != nil {
-		return fmt.Errorf("failed to read file: %w", err)
-	}
-
-	language := sm.detectLanguageFromFile(filePath)
-	
-	params := map[string]interface{}{
-		"textDocument": map[string]interface{}{
-			"uri":        "file://" + filePath,
-			"languageId": language,
-			"version":    1,
-			"text":       string(content),
-		},
-	}
-
-	return client.SendNotification("textDocument/didOpen", params)
-}
-
-// getDocumentSymbols gets symbols from a document via LSP
-func (sm *SymbolManager) getDocumentSymbols(client *LSPClient, filePath string, language string) ([]Symbol, error) {
-	params := map[string]interface{}{
-		"textDocument": map[string]interface{}{
-			"uri": "file://" + filePath,
-		},
-	}
-
-	response, err := client.SendRequest("textDocument/documentSymbol", params)
-	if err != nil {
-		return nil, fmt.Errorf("documentSymbol request failed: %w", err)
-	}
-
-	if response.Error != nil {
-		return nil, fmt.Errorf("documentSymbol error: %s", response.Error.Message)
-	}
-
-	// Parse LSP symbols
-	return sm.parseLSPSymbols(response.Result, filePath, language)
-}
-
-// parseLSPSymbols converts LSP symbols to our internal format
-func (sm *SymbolManager) parseLSPSymbols(result interface{}, filePath string, language string) ([]Symbol, error) {
-	var symbols []Symbol
-
-	// Handle both DocumentSymbol[] and SymbolInformation[] responses
-	switch data := result.(type) {
-	case []interface{}:
-		for _, item := range data {
-			if itemMap, ok := item.(map[string]interface{}); ok {
-				symbol := sm.convertLSPSymbol(itemMap, filePath, language)
-				if symbol != nil {
-					symbols = append(symbols, *symbol)
-				}
-			}
-		}
-	default:
-		return nil, fmt.Errorf("unexpected symbol response format")
-	}
-
-	return symbols, nil
-}
-
-// convertLSPSymbol converts a single LSP symbol to our format
-func (sm *SymbolManager) convertLSPSymbol(lspSymbol map[string]interface{}, filePath string, language string) *Symbol {
-	name, ok := lspSymbol["name"].(string)
-	if !ok {
-		return nil
-	}
-
-	kind, ok := lspSymbol["kind"].(float64)
-	if !ok {
-		return nil
-	}
-
-	// Convert LSP symbol kind to our SymbolKind
-	symbolKind := sm.convertSymbolKind(int(kind))
-
-	// Extract location
-	var location SourceLocation
-	if loc, ok := lspSymbol["location"].(map[string]interface{}); ok {
-		location = sm.extractLocation(loc)
-	} else if rng, ok := lspSymbol["range"].(map[string]interface{}); ok {
-		location = sm.extractLocationFromRange(rng, filePath)
-	}
-
-	symbol := &Symbol{
-		Name:       name,
-		FullPath:   name, // Will be updated with proper path
-		Kind:       symbolKind,
-		Location:   location,
-		Language:   language,
-		Visibility: "public", // Default, can be refined
-	}
-
-	// Extract additional details
-	if detail, ok := lspSymbol["detail"].(string); ok {
-		symbol.Signature = detail
-	}
-
-	// Handle children (for hierarchical symbols)
-	if children, ok := lspSymbol["children"].([]interface{}); ok {
-		for _, child := range children {
-			if childMap, ok := child.(map[string]interface{}); ok {
-				if childSymbol := sm.convertLSPSymbol(childMap, filePath, language); childSymbol != nil {
-					childSymbol.FullPath = symbol.Name + "." + childSymbol.Name
-					symbol.Children = append(symbol.Children, *childSymbol)
-				}
-			}
-		}
-	}
-
-	return symbol
-}
-
-// convertSymbolKind converts LSP symbol kind to our SymbolKind
-func (sm *SymbolManager) convertSymbolKind(lspKind int) SymbolKind {
-	switch lspKind {
-	case 1:
-		return SymbolKindFile
-	case 2:
-		return SymbolKindModule
-	case 3:
-		return SymbolKindNamespace
-	case 4:
-		return SymbolKindPackage
-	case 5:
-		return SymbolKindClass
-	case 6:
-		return SymbolKindMethod
-	case 7:
-		return SymbolKindProperty
-	case 8:
-		return SymbolKindField
-	case 9:
-		return SymbolKindConstructor
-	case 10:
-		return SymbolKindEnum
-	case 11:
-		return SymbolKindInterface
-	case 12:
-		return SymbolKindFunction
-	case 13:
-		return SymbolKindVariable
-	case 14:
-		return SymbolKindConstant
-	case 15:
-		return SymbolKindString
-	case 16:
-		return SymbolKindNumber
-	case 17:
-		return SymbolKindBoolean
-	case 18:
-		return SymbolKindArray
-	case 19:
-		return SymbolKindObject
-	case 20:
-		return SymbolKindKey
-	case 21:
-		return SymbolKindNull
-	case 22:
-		return SymbolKindEnumMember
-	case 23:
-		return SymbolKindStruct
-	case 24:
-		return SymbolKindEvent
-	case 25:
-		return SymbolKindOperator
-	case 26:
-		return SymbolKindTypeParameter
-	default:
-		return SymbolKindObject // Default fallback
-	}
-}
-
-// extractLocation extracts location from LSP location object
-func (sm *SymbolManager) extractLocation(loc map[string]interface{}) SourceLocation {
-	uri, _ := loc["uri"].(string)
-	filePath := strings.TrimPrefix(uri, "file://")
-
-	if rng, ok := loc["range"].(map[string]interface{}); ok {
-		return sm.extractLocationFromRange(rng, filePath)
-	}
-
-	return SourceLocation{FilePath: filePath}
-}
-
-// extractLocationFromRange extracts location from LSP range
-func (sm *SymbolManager) extractLocationFromRange(rng map[string]interface{}, filePath string) SourceLocation {
-	location := SourceLocation{FilePath: filePath}
-
-	if start, ok := rng["start"].(map[string]interface{}); ok {
-		if line, ok := start["line"].(float64); ok {
-			location.Line = int(line) + 1 // LSP is 0-based, we use 1-based
-		}
-		if char, ok := start["character"].(float64); ok {
-			location.Column = int(char) + 1
-		}
-	}
-
-	if end, ok := rng["end"].(map[string]interface{}); ok {
-		if line, ok := end["line"].(float64); ok {
-			location.EndLine = int(line) + 1
-		}
-		if char, ok := end["character"].(float64); ok {
-			location.EndColumn = int(char) + 1
-		}
-	}
-
-	return location
-}
-
-// filterSymbols filters symbols based on the query
-func (sm *SymbolManager) filterSymbols(symbols []Symbol, query SymbolQuery) []Symbol {
-	var filtered []Symbol
-
-	for _, symbol := range symbols {
-		if sm.symbolMatches(symbol, query) {
-			if query.IncludeChildren {
-				filtered = append(filtered, symbol)
-			} else {
-				// Create a copy without children
-				symbolCopy := symbol
-				symbolCopy.Children = nil
-				filtered = append(filtered, symbolCopy)
-			}
-		}
-
-		// Also check children if include_children is true
-		if query.IncludeChildren {
-			for _, child := range symbol.Children {
-				if sm.symbolMatches(child, query) {
-					filtered = append(filtered, child)
-				}
-			}
-		}
-	}
-
-	return filtered
-}
-
-// symbolMatches checks if a symbol matches the query criteria
-func (sm *SymbolManager) symbolMatches(symbol Symbol, query SymbolQuery) bool {
-	// Check name match
-	if !sm.nameMatches(symbol.Name, query.Name) && !sm.nameMatches(symbol.FullPath, query.Name) {
-		return false
-	}
-
-	// Check kind filter
-	if query.Kind != "" && symbol.Kind != query.Kind {
-		return false
-	}
-
-	// Check language filter
-	if query.Language != "" && symbol.Language != query.Language {
-		return false
-	}
-
-	return true
-}
-
-// nameMatches checks if a symbol name matches the query pattern
-func (sm *SymbolManager) nameMatches(symbolName, queryName string) bool {
-	// Exact match
-	if symbolName == queryName {
-		return true
-	}
-
-	// Case-insensitive substring match
-	if strings.Contains(strings.ToLower(symbolName), strings.ToLower(queryName)) {
-		return true
-	}
-
-	// Path-style match (e.g., "Class.method" matches "method")
-	if strings.Contains(symbolName, ".") {
-		parts := strings.Split(symbolName, ".")
-		if parts[len(parts)-1] == queryName {
-			return true
-		}
-	}
-
-	return false
-}
-
-// detectLanguageFromFile detects language from file extension
-func (sm *SymbolManager) detectLanguageFromFile(filePath string) string {
-	ext := strings.ToLower(filepath.Ext(filePath))
-	
-	for language, config := range DefaultLanguageServers {
-		for _, fileExt := range config.FileExts {
-			if ext == fileExt {
-				return language
-			}
-		}
-	}
-
-	return ""
-}
-
-// GetOverview gets a high-level overview of symbols in a path
-func (sm *SymbolManager) GetOverview(path string, depth int, includeKinds []string, excludePrivate bool) (*SymbolOverview, error) {
-	// This is a placeholder implementation
-	// In a full implementation, this would analyze the directory/file structure
-	// and provide statistics and top-level symbols
-	
-	overview := &SymbolOverview{
-		Path:         path,
-		TotalSymbols: 0,
-		ByKind:       make(map[string]int),
-		ByLanguage:   make(map[string]int),
-		TopLevel:     []Symbol{},
-		Structure:    make(map[string]interface{}),
-	}
-
-	return overview, nil
-}
-
-// GetDefinition gets detailed information about a symbol's definition
-func (sm *SymbolManager) GetDefinition(symbolName string, includeSignature, includeDocumentation, includeDependencies bool) (*SymbolDefinition, error) {
-	// This is a placeholder implementation
-	// In a full implementation, this would find the symbol and get its definition details
-	
-	definition := &SymbolDefinition{
-		Symbol: Symbol{
-			Name:     symbolName,
-			FullPath: symbolName,
-			Kind:     SymbolKindFunction,
-		},
-	}
-
-	return definition, nil
-}
-
-// GetReferences gets all references to a symbol
-func (sm *SymbolManager) GetReferences(symbolName string, includeDefinitions bool, contextLines int, filterByKind []string, language string, includeExternal bool) (*SymbolReferences, error) {
-	// First, find the symbol to get its location
-	query := SymbolQuery{
-		Name:       symbolName,
-		Language:   language,
-		MaxResults: 1,
-	}
-
-	symbols, err := sm.FindSymbols(query)
-	if err != nil {
-		return nil, fmt.Errorf("failed to find symbol: %w", err)
-	}
-
-	if len(symbols) == 0 {
-		return &SymbolReferences{
-			Symbol:     symbolName,
-			References: []SymbolReference{},
-			TotalFound: 0,
-		}, nil
-	}
-
-	symbol := symbols[0]
-	
-	// Get language server for the symbol's language
-	client, err := sm.lspManager.GetClient(symbol.Language)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get LSP client: %w", err)
-	}
-
-	// Get references via LSP
-	lspRefs, err := client.GetReferences(symbol.Location.FilePath, symbol.Location.Line, symbol.Location.Column, includeDefinitions)
-	if err != nil {
-		// If LSP fails, return empty result rather than error
-		return &SymbolReferences{
-			Symbol:     symbolName,
-			References: []SymbolReference{},
-			TotalFound: 0,
-		}, nil
-	}
-
-	// Convert LSP references to our format
-	var references []SymbolReference
-	var definition *SourceLocation
-
-	for _, lspRef := range lspRefs {
-		// Convert LSP location to our format
-		filePath := strings.TrimPrefix(lspRef.URI, "file://")
-		location := SourceLocation{
-			FilePath: filePath,
-			Line:     lspRef.Range.Start.Line + 1, // Convert back to 1-based
-			Column:   lspRef.Range.Start.Character + 1,
-			EndLine:  lspRef.Range.End.Line + 1,
-			EndColumn: lspRef.Range.End.Character + 1,
-		}
-
-		// Check if this is the definition location
-		if includeDefinitions && sm.isDefinitionLocation(location, symbol.Location) {
-			definition = &location
-			if !includeDefinitions {
-				continue
-			}
-		}
-
-		// Get context around the reference
-		context := sm.getCodeContext(filePath, location.Line, contextLines)
-
-		ref := SymbolReference{
-			Location: location,
-			Context:  context,
-			Kind:     "reference", // Could be enhanced to detect call vs import vs etc
-			Symbol:   symbolName,
-		}
-
-		references = append(references, ref)
-	}
-
-	result := &SymbolReferences{
-		Symbol:     symbolName,
-		Definition: definition,
-		References: references,
-		TotalFound: len(references),
-	}
-
-	return result, nil
-}
-
-// GetCallHierarchy gets call hierarchy for a symbol
-func (sm *SymbolManager) GetCallHierarchy(symbolName string, direction string, maxDepth int, includeExternal bool, language string) (*CallHierarchy, error) {
-	// Find the symbol first
-	query := SymbolQuery{
-		Name:       symbolName,
-		Language:   language,
-		MaxResults: 1,
-	}
-
-	symbols, err := sm.FindSymbols(query)
-	if err != nil {
-		return nil, fmt.Errorf("failed to find symbol: %w", err)
-	}
-
-	if len(symbols) == 0 {
-		return &CallHierarchy{
-			Symbol:     symbolName,
-			Direction:  direction,
-			MaxDepth:   maxDepth,
-			TotalItems: 0,
-		}, nil
-	}
-
-	symbol := symbols[0]
-
-	// Get language server
-	client, err := sm.lspManager.GetClient(symbol.Language)
-	if err != nil {
-		return nil, fmt.Errorf("failed to get LSP client: %w", err)
-	}
-
-	// Prepare call hierarchy
-	items, err := client.PrepareCallHierarchy(symbol.Location.FilePath, symbol.Location.Line, symbol.Location.Column)
-	if err != nil || len(items) == 0 {
-		// If LSP doesn't support call hierarchy, return empty result
-		return &CallHierarchy{
-			Symbol:     symbolName,
-			Direction:  direction,
-			MaxDepth:   maxDepth,
-			TotalItems: 0,
-		}, nil
-	}
-
-	// Build call hierarchy tree
-	root := sm.buildCallHierarchyItem(items[0], client, direction, maxDepth, 0, includeExternal)
-
-	hierarchy := &CallHierarchy{
-		Symbol:     symbolName,
-		Root:       root,
-		Direction:  direction,
-		MaxDepth:   maxDepth,
-		TotalItems: sm.countCallHierarchyItems(root),
-	}
-
-	return hierarchy, nil
-}
-
-// AnalyzeDependencies analyzes symbol dependencies
-func (sm *SymbolManager) AnalyzeDependencies(scope string, path string, includeExternal bool, groupBy string, showUnused bool, language string) (*DependencyAnalysis, error) {
-	// This is a simplified implementation
-	// In a full implementation, this would analyze the entire dependency graph
-	
-	analysis := &DependencyAnalysis{
-		Scope:           scope,
-		GroupBy:         groupBy,
-		TotalSymbols:    0,
-		ExternalDeps:    0,
-		UnusedSymbols:   0,
-		Groups:          make(map[string][]DependencyNode),
-		DependencyGraph: make(map[string][]string),
-		Summary:         make(map[string]int),
-	}
-
-	// For now, return a placeholder response
-	// Real implementation would:
-	// 1. Scan all symbols in the specified scope
-	// 2. Build dependency relationships via LSP or static analysis
-	// 3. Group by specified criteria
-	// 4. Identify unused symbols
-	// 5. Calculate statistics
-
-	return analysis, nil
-}
-
-// Helper methods
-
-func (sm *SymbolManager) isDefinitionLocation(ref, def SourceLocation) bool {
-	return ref.FilePath == def.FilePath && 
-		   ref.Line == def.Line && 
-		   ref.Column == def.Column
-}
-
-func (sm *SymbolManager) getCodeContext(filePath string, line int, contextLines int) string {
-	// Read context around the line
-	content, err := sm.projectManager.ReadFile(filePath)
-	if err != nil {
-		return ""
-	}
-
-	lines := strings.Split(string(content), "\n")
-	if line < 1 || line > len(lines) {
-		return ""
-	}
-
-	start := line - contextLines - 1
-	if start < 0 {
-		start = 0
-	}
-
-	end := line + contextLines
-	if end > len(lines) {
-		end = len(lines)
-	}
-
-	contextLines_slice := lines[start:end]
-	
-	// Add line numbers for clarity
-	var result strings.Builder
-	for i, contextLine := range contextLines_slice {
-		lineNum := start + i + 1
-		marker := "  "
-		if lineNum == line {
-			marker = "►"
-		}
-		result.WriteString(fmt.Sprintf("%s %3d: %s\n", marker, lineNum, contextLine))
-	}
-
-	return result.String()
-}
-
-func (sm *SymbolManager) buildCallHierarchyItem(item map[string]interface{}, client *LSPClient, direction string, maxDepth int, currentDepth int, includeExternal bool) CallHierarchyItem {
-	// Extract basic information from LSP item
-	name, _ := item["name"].(string)
-	kind, _ := item["kind"].(float64)
-	
-	hierItem := CallHierarchyItem{
-		Symbol: name,
-		Name:   name,
-		Kind:   sm.convertSymbolKind(int(kind)),
-		Depth:  currentDepth,
-	}
-
-	// Extract location if present
-	if uri, ok := item["uri"].(string); ok {
-		hierItem.Location.FilePath = strings.TrimPrefix(uri, "file://")
-	}
-	if rng, ok := item["range"].(map[string]interface{}); ok {
-		hierItem.Location = sm.extractLocationFromRange(rng, hierItem.Location.FilePath)
-	}
-
-	// Recursively build hierarchy if we haven't reached max depth
-	if currentDepth < maxDepth {
-		if direction == "incoming" || direction == "both" {
-			if incomingCalls, err := client.GetIncomingCalls(item); err == nil {
-				for _, call := range incomingCalls {
-					if fromItem, ok := call["from"].(map[string]interface{}); ok {
-						childItem := sm.buildCallHierarchyItem(fromItem, client, direction, maxDepth, currentDepth+1, includeExternal)
-						hierItem.IncomingCalls = append(hierItem.IncomingCalls, childItem)
-					}
-				}
-			}
-		}
-
-		if direction == "outgoing" || direction == "both" {
-			if outgoingCalls, err := client.GetOutgoingCalls(item); err == nil {
-				for _, call := range outgoingCalls {
-					if toItem, ok := call["to"].(map[string]interface{}); ok {
-						childItem := sm.buildCallHierarchyItem(toItem, client, direction, maxDepth, currentDepth+1, includeExternal)
-						hierItem.OutgoingCalls = append(hierItem.OutgoingCalls, childItem)
-					}
-				}
-			}
-		}
-	}
-
-	return hierItem
-}
-
-func (sm *SymbolManager) countCallHierarchyItems(item CallHierarchyItem) int {
-	count := 1
-	for _, child := range item.IncomingCalls {
-		count += sm.countCallHierarchyItems(child)
-	}
-	for _, child := range item.OutgoingCalls {
-		count += sm.countCallHierarchyItems(child)
-	}
-	return count
-}
\ No newline at end of file
pkg/semantic/types.go
@@ -1,272 +0,0 @@
-package semantic
-
-import "time"
-
-// Symbol represents a code symbol (function, class, variable, etc.)
-type Symbol struct {
-	Name         string            `json:"name"`
-	FullPath     string            `json:"full_path"`
-	Kind         SymbolKind        `json:"kind"`
-	Location     SourceLocation    `json:"location"`
-	Signature    string            `json:"signature,omitempty"`
-	Documentation string           `json:"documentation,omitempty"`
-	Visibility   string            `json:"visibility"`
-	Language     string            `json:"language"`
-	Children     []Symbol          `json:"children,omitempty"`
-	References   []SourceLocation  `json:"references,omitempty"`
-	Dependencies []string          `json:"dependencies,omitempty"`
-}
-
-// SymbolKind represents the type of a symbol
-type SymbolKind string
-
-const (
-	SymbolKindFile        SymbolKind = "file"
-	SymbolKindModule      SymbolKind = "module"
-	SymbolKindNamespace   SymbolKind = "namespace"
-	SymbolKindPackage     SymbolKind = "package"
-	SymbolKindClass       SymbolKind = "class"
-	SymbolKindMethod      SymbolKind = "method"
-	SymbolKindProperty    SymbolKind = "property"
-	SymbolKindField       SymbolKind = "field"
-	SymbolKindConstructor SymbolKind = "constructor"
-	SymbolKindEnum        SymbolKind = "enum"
-	SymbolKindInterface   SymbolKind = "interface"
-	SymbolKindFunction    SymbolKind = "function"
-	SymbolKindVariable    SymbolKind = "variable"
-	SymbolKindConstant    SymbolKind = "constant"
-	SymbolKindString      SymbolKind = "string"
-	SymbolKindNumber      SymbolKind = "number"
-	SymbolKindBoolean     SymbolKind = "boolean"
-	SymbolKindArray       SymbolKind = "array"
-	SymbolKindObject      SymbolKind = "object"
-	SymbolKindKey         SymbolKind = "key"
-	SymbolKindNull        SymbolKind = "null"
-	SymbolKindEnumMember  SymbolKind = "enum_member"
-	SymbolKindStruct      SymbolKind = "struct"
-	SymbolKindEvent       SymbolKind = "event"
-	SymbolKindOperator    SymbolKind = "operator"
-	SymbolKindTypeParameter SymbolKind = "type_parameter"
-)
-
-// SourceLocation represents a location in source code
-type SourceLocation struct {
-	FilePath  string `json:"file_path"`
-	Line      int    `json:"line"`
-	Column    int    `json:"column"`
-	EndLine   int    `json:"end_line,omitempty"`
-	EndColumn int    `json:"end_column,omitempty"`
-}
-
-// SymbolQuery represents a query for finding symbols
-type SymbolQuery struct {
-	Name            string     `json:"name"`
-	Kind            SymbolKind `json:"kind,omitempty"`
-	Scope           string     `json:"scope,omitempty"`
-	Language        string     `json:"language,omitempty"`
-	IncludeChildren bool       `json:"include_children,omitempty"`
-	MaxResults      int        `json:"max_results,omitempty"`
-}
-
-// SymbolOverview represents a high-level overview of symbols in a scope
-type SymbolOverview struct {
-	Path        string            `json:"path"`
-	TotalSymbols int              `json:"total_symbols"`
-	ByKind      map[string]int    `json:"by_kind"`
-	ByLanguage  map[string]int    `json:"by_language"`
-	TopLevel    []Symbol          `json:"top_level"`
-	Structure   map[string]interface{} `json:"structure"`
-}
-
-// SymbolDefinition represents detailed symbol definition information
-type SymbolDefinition struct {
-	Symbol          Symbol            `json:"symbol"`
-	Signature       string            `json:"signature,omitempty"`
-	Documentation   string            `json:"documentation,omitempty"`
-	Dependencies    []string          `json:"dependencies,omitempty"`
-	References      []SourceLocation  `json:"references,omitempty"`
-	RelatedSymbols  []Symbol          `json:"related_symbols,omitempty"`
-}
-
-// SymbolReference represents a reference to a symbol with context
-type SymbolReference struct {
-	Location    SourceLocation `json:"location"`
-	Context     string         `json:"context,omitempty"`     // Code context around the reference
-	Kind        string         `json:"kind,omitempty"`        // Type of reference (call, import, etc.)
-	Symbol      string         `json:"symbol"`                // The symbol being referenced
-}
-
-// SymbolReferences represents all references to a symbol
-type SymbolReferences struct {
-	Symbol      string            `json:"symbol"`
-	Definition  *SourceLocation   `json:"definition,omitempty"`
-	References  []SymbolReference `json:"references"`
-	TotalFound  int               `json:"total_found"`
-}
-
-// CallHierarchyItem represents a single item in the call hierarchy
-type CallHierarchyItem struct {
-	Symbol      string             `json:"symbol"`
-	Name        string             `json:"name"`
-	Kind        SymbolKind         `json:"kind"`
-	Location    SourceLocation     `json:"location"`
-	Signature   string             `json:"signature,omitempty"`
-	IncomingCalls []CallHierarchyItem `json:"incoming_calls,omitempty"`
-	OutgoingCalls []CallHierarchyItem `json:"outgoing_calls,omitempty"`
-	Depth       int                `json:"depth"`
-}
-
-// CallHierarchy represents the complete call hierarchy for a symbol
-type CallHierarchy struct {
-	Symbol      string             `json:"symbol"`
-	Root        CallHierarchyItem  `json:"root"`
-	Direction   string             `json:"direction"`
-	MaxDepth    int                `json:"max_depth"`
-	TotalItems  int                `json:"total_items"`
-}
-
-// DependencyNode represents a single dependency relationship
-type DependencyNode struct {
-	Symbol       string            `json:"symbol"`
-	Kind         SymbolKind        `json:"kind"`
-	Location     SourceLocation    `json:"location"`
-	Dependencies []string          `json:"dependencies,omitempty"`
-	Dependents   []string          `json:"dependents,omitempty"`
-	IsExternal   bool              `json:"is_external"`
-	IsUnused     bool              `json:"is_unused,omitempty"`
-}
-
-// DependencyAnalysis represents the result of dependency analysis
-type DependencyAnalysis struct {
-	Scope           string                    `json:"scope"`
-	GroupBy         string                    `json:"group_by"`
-	TotalSymbols    int                       `json:"total_symbols"`
-	ExternalDeps    int                       `json:"external_deps"`
-	UnusedSymbols   int                       `json:"unused_symbols,omitempty"`
-	Groups          map[string][]DependencyNode `json:"groups"`
-	DependencyGraph map[string][]string       `json:"dependency_graph"`
-	Summary         map[string]int            `json:"summary"`
-}
-
-// LSPRequest represents a Language Server Protocol request
-type LSPRequest struct {
-	JSONRPC string      `json:"jsonrpc"`
-	ID      int         `json:"id"`
-	Method  string      `json:"method"`
-	Params  interface{} `json:"params,omitempty"`
-}
-
-// LSPResponse represents a Language Server Protocol response
-type LSPResponse struct {
-	JSONRPC string      `json:"jsonrpc"`
-	ID      int         `json:"id,omitempty"`
-	Result  interface{} `json:"result,omitempty"`
-	Error   *LSPError   `json:"error,omitempty"`
-}
-
-// LSPError represents an LSP error
-type LSPError struct {
-	Code    int         `json:"code"`
-	Message string      `json:"message"`
-	Data    interface{} `json:"data,omitempty"`
-}
-
-// LSPPosition represents a position in an LSP document
-type LSPPosition struct {
-	Line      int `json:"line"`
-	Character int `json:"character"`
-}
-
-// LSPRange represents a range in an LSP document
-type LSPRange struct {
-	Start LSPPosition `json:"start"`
-	End   LSPPosition `json:"end"`
-}
-
-// LSPLocation represents a location in an LSP workspace
-type LSPLocation struct {
-	URI   string   `json:"uri"`
-	Range LSPRange `json:"range"`
-}
-
-// LSPSymbolInformation represents symbol information from LSP
-type LSPSymbolInformation struct {
-	Name          string      `json:"name"`
-	Kind          int         `json:"kind"`
-	Location      LSPLocation `json:"location"`
-	ContainerName string      `json:"containerName,omitempty"`
-}
-
-// LSPDocumentSymbol represents a document symbol from LSP
-type LSPDocumentSymbol struct {
-	Name           string              `json:"name"`
-	Detail         string              `json:"detail,omitempty"`
-	Kind           int                 `json:"kind"`
-	Range          LSPRange            `json:"range"`
-	SelectionRange LSPRange            `json:"selectionRange"`
-	Children       []LSPDocumentSymbol `json:"children,omitempty"`
-}
-
-// LanguageServerConfig represents configuration for a language server
-type LanguageServerConfig struct {
-	Language    string   `json:"language"`
-	ServerCmd   string   `json:"server_cmd"`
-	Args        []string `json:"args"`
-	FileExts    []string `json:"file_extensions"`
-	Initialized bool     `json:"initialized"`
-	Enabled     bool     `json:"enabled"`
-	Timeout     int      `json:"timeout"` // seconds
-}
-
-// ProjectConfig represents project configuration
-type ProjectConfig struct {
-	Name            string            `json:"name"`
-	RootPath        string            `json:"root_path"`
-	Languages       []string          `json:"languages"`
-	ExcludePatterns []string          `json:"exclude_patterns"`
-	IncludePatterns []string          `json:"include_patterns"`
-	CustomSettings  map[string]string `json:"custom_settings"`
-}
-
-// SymbolCache represents cached symbol information
-type SymbolCache struct {
-	Symbols    map[string][]Symbol       `json:"symbols"`     // file_path -> symbols
-	References map[string][]SourceLocation `json:"references"` // symbol_path -> references
-	Index      map[string][]string       `json:"index"`       // name -> file_paths
-	LastUpdate map[string]time.Time      `json:"last_update"` // file_path -> last_modified
-}
-
-// FileChange represents a file system change
-type FileChange struct {
-	Path      string `json:"path"`
-	Operation string `json:"operation"` // create, modify, delete, rename
-	Timestamp time.Time `json:"timestamp"`
-}
-
-// Default language server configurations
-var DefaultLanguageServers = map[string]LanguageServerConfig{
-	"go": {
-		Language:  "go",
-		ServerCmd: "gopls",
-		Args:      []string{"serve"},
-		FileExts:  []string{".go"},
-		Enabled:   true,
-		Timeout:   30,
-	},
-	"rust": {
-		Language:  "rust",
-		ServerCmd: "rust-analyzer",
-		Args:      []string{},
-		FileExts:  []string{".rs"},
-		Enabled:   true,
-		Timeout:   60,
-	},
-	"ruby": {
-		Language:  "ruby",
-		ServerCmd: "solargraph",
-		Args:      []string{"stdio"},
-		FileExts:  []string{".rb", ".rbw", ".rake", ".gemspec"},
-		Enabled:   true,
-		Timeout:   30,
-	},
-}
\ No newline at end of file
test/integration/main_test.go
@@ -282,13 +282,6 @@ func TestAllServers(t *testing.T) {
 			ExpectedServers: "bash",
 			MinResources:    90, // Bash server has bash builtins and coreutils resources
 		},
-		{
-			BinaryName:      "mcp-semantic",
-			Args:            []string{"--project-root", "."},
-			ExpectedTools:   []string{"semantic_find_symbol", "semantic_get_overview", "semantic_get_definition", "semantic_get_references", "semantic_get_call_hierarchy", "semantic_analyze_dependencies"},
-			ExpectedServers: "mcp-semantic",
-			MinResources:    0, // No static resources (discovers projects dynamically)
-		},
 	}
 
 	for _, config := range servers {
@@ -439,7 +432,6 @@ func TestServerStartupPerformance(t *testing.T) {
 		"mcp-maildir",
 		"mcp-imap",
 		"mcp-bash",
-		"mcp-semantic",
 	}
 
 	for _, serverName := range servers {
@@ -462,8 +454,6 @@ func TestServerStartupPerformance(t *testing.T) {
 				args = []string{tempDir}
 			case "mcp-imap":
 				args = []string{"--server", "example.com", "--username", "test", "--password", "test"}
-			case "mcp-semantic":
-				args = []string{"--project-root", "."}
 			}
 
 			server, err := NewMCPServer(binaryPath, args...)
Makefile
@@ -11,7 +11,7 @@ BINDIR = bin
 INSTALLDIR = /usr/local/bin
 
 # Server binaries
-SERVERS = git filesystem fetch memory sequential-thinking time maildir signal gitlab imap bash speech semantic
+SERVERS = git filesystem fetch memory sequential-thinking time maildir signal gitlab imap bash speech
 BINARIES = $(addprefix $(BINDIR)/mcp-,$(SERVERS))
 
 # Build flags
@@ -122,7 +122,6 @@ gitlab: $(BINDIR)/mcp-gitlab ## Build gitlab server only
 imap: $(BINDIR)/mcp-imap ## Build imap server only
 bash: $(BINDIR)/mcp-bash ## Build bash server only
 speech: $(BINDIR)/mcp-speech ## Build speech server only
-semantic: $(BINDIR)/mcp-semantic ## Build semantic server only
 
 help: ## Show this help message
 	@echo "Go MCP Servers - Available targets:"
@@ -130,4 +129,4 @@ help: ## Show this help message
 	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2}'
 	@echo ""
 	@echo "Individual servers:"
-	@echo "  git, filesystem, fetch, memory, sequential-thinking, time, maildir, signal, gitlab, imap, bash, speech, semantic"
+	@echo "  git, filesystem, fetch, memory, sequential-thinking, time, maildir, signal, gitlab, imap, bash, speech"