Commit b9c1e47

mo khan <mo@mokhan.ca>
2025-08-16 19:33:34
refactor: use builder pattern
1 parent addde2a
pkg/fetch/server.go
@@ -13,14 +13,6 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Fetch MCP server
-type Server struct {
-	*mcp.Server
-	httpClient    *http.Client
-	userAgent     string
-	htmlProcessor *htmlprocessor.ContentExtractor
-}
-
 // FetchResult represents the result of a fetch operation
 type FetchResult struct {
 	URL         string `json:"url"`
@@ -31,231 +23,195 @@ type FetchResult struct {
 	NextIndex   int    `json:"next_index,omitempty"`
 }
 
-// New creates a new Fetch MCP server
-func New() *Server {
-	server := mcp.NewServer("mcp-fetch", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
+// FetchOperations provides HTTP client operations for fetching content
+type FetchOperations struct {
+	httpClient    *http.Client
+	userAgent     string
+	htmlProcessor *htmlprocessor.ContentExtractor
+}
 
-	fetchServer := &Server{
-		Server: server,
+// NewFetchOperations creates a new FetchOperations helper
+func NewFetchOperations() *FetchOperations {
+	return &FetchOperations{
 		httpClient: &http.Client{
 			Timeout: 30 * time.Second,
 		},
 		userAgent:     "ModelContextProtocol/1.0 (Fetch; +https://github.com/xlgmokha/mcp)",
 		htmlProcessor: htmlprocessor.NewContentExtractor(),
 	}
-
-	// Register all fetch tools and prompts
-	fetchServer.registerTools()
-	fetchServer.registerPrompts()
-
-	return fetchServer
 }
 
-// registerTools registers all Fetch tools with the server
-func (fs *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := fs.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "fetch":
-			handler = fs.HandleFetch
-		default:
-			continue
-		}
-		fs.RegisterToolWithDefinition(tool, handler)
-	}
-}
-
-// registerPrompts registers all Fetch prompts with the server
-func (fs *Server) registerPrompts() {
-	fetchPrompt := mcp.Prompt{
-		Name:        "fetch",
-		Description: "Prompt for manually entering a URL to fetch content from",
-		Arguments: []mcp.PromptArgument{
-			{
-				Name:        "url",
-				Description: "The URL to fetch content from",
-				Required:    true,
+// New creates a new Fetch MCP server
+func New() *mcp.Server {
+	fetch := NewFetchOperations()
+	builder := mcp.NewServerBuilder("mcp-fetch", "1.0.0")
+
+	// Add fetch tool
+	builder.AddTool(mcp.NewTool("fetch", "Fetches a URL from the internet and extracts its contents as markdown. Always returns successful response with content or error details.", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"url": map[string]interface{}{
+				"type":        "string",
+				"description": "URL to fetch",
+				"format":      "uri",
 			},
-			{
-				Name:        "reason",
-				Description: "Why you want to fetch this URL (optional context)",
-				Required:    false,
+			"max_length": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of characters to return. Defaults to 5000",
+				"minimum":     1,
+				"maximum":     999999,
+				"default":     5000,
 			},
-		},
-	}
-
-	fs.RegisterPrompt(fetchPrompt, fs.HandleFetchPrompt)
-}
-
-// ListTools returns all available Fetch tools
-func (fs *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "fetch",
-			Description: "Fetches a URL from the internet and extracts its contents as markdown. Always returns successful response with content or error details.",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"url": map[string]interface{}{
-						"type":        "string",
-						"description": "URL to fetch",
-						"format":      "uri",
-					},
-					"max_length": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of characters to return. Defaults to 5000",
-						"minimum":     1,
-						"maximum":     999999,
-						"default":     5000,
-					},
-					"start_index": map[string]interface{}{
-						"type":        "integer",
-						"description": "Start reading content from this character index. Defaults to 0",
-						"minimum":     0,
-						"default":     0,
-					},
-					"raw": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Get raw HTML content without markdown conversion. Defaults to false",
-						"default":     false,
-					},
-				},
-				"required": []string{"url"},
+			"start_index": map[string]interface{}{
+				"type":        "integer",
+				"description": "Start reading content from this character index. Defaults to 0",
+				"minimum":     0,
+				"default":     0,
+			},
+			"raw": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Get raw HTML content without markdown conversion. Defaults to false",
+				"default":     false,
 			},
 		},
-	}
-}
-
-// Tool handlers
-
-func (fs *Server) HandleFetch(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	urlStr, ok := req.Arguments["url"].(string)
-	if !ok {
-		return mcp.NewToolError("url is required"), nil
-	}
-
-	// Parse and validate URL
-	parsedURL, err := url.Parse(urlStr)
-	if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
-		return mcp.NewToolError("Invalid URL format"), nil
-	}
-
-	// Get optional parameters
-	maxLength := 5000
-	if ml, ok := req.Arguments["max_length"]; ok {
-		switch v := ml.(type) {
-		case float64:
-			maxLength = int(v)
-		case int:
-			maxLength = v
-		default:
-			return mcp.NewToolError("max_length must be a number"), nil
-		}
-		if maxLength < 1 || maxLength > 999999 {
-			return mcp.NewToolError("max_length must be between 1 and 999999"), nil
+		"required": []string{"url"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		urlStr, ok := req.Arguments["url"].(string)
+		if !ok {
+			return mcp.NewToolError("url is required"), nil
 		}
-	}
 
-	startIndex := 0
-	if si, ok := req.Arguments["start_index"]; ok {
-		switch v := si.(type) {
-		case float64:
-			startIndex = int(v)
-		case int:
-			startIndex = v
-		default:
-			return mcp.NewToolError("start_index must be a number"), nil
+		// Parse and validate URL
+		parsedURL, err := url.Parse(urlStr)
+		if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
+			return mcp.NewToolError("Invalid URL format"), nil
 		}
-		if startIndex < 0 {
-			return mcp.NewToolError("start_index must be >= 0"), nil
+
+		// Get optional parameters
+		maxLength := 5000
+		if ml, ok := req.Arguments["max_length"]; ok {
+			switch v := ml.(type) {
+			case float64:
+				maxLength = int(v)
+			case int:
+				maxLength = v
+			default:
+				return mcp.NewToolError("max_length must be a number"), nil
+			}
+			if maxLength < 1 || maxLength > 999999 {
+				return mcp.NewToolError("max_length must be between 1 and 999999"), nil
+			}
 		}
-	}
 
-	raw := false
-	if r, ok := req.Arguments["raw"]; ok {
-		if rBool, ok := r.(bool); ok {
-			raw = rBool
+		startIndex := 0
+		if si, ok := req.Arguments["start_index"]; ok {
+			switch v := si.(type) {
+			case float64:
+				startIndex = int(v)
+			case int:
+				startIndex = v
+			default:
+				return mcp.NewToolError("start_index must be a number"), nil
+			}
+			if startIndex < 0 {
+				return mcp.NewToolError("start_index must be >= 0"), nil
+			}
 		}
-	}
 
-	// Fetch the content
-	result, err := fs.fetchContent(parsedURL.String(), maxLength, startIndex, raw)
-	if err != nil {
-		return mcp.NewToolError(err.Error()), nil
-	}
+		raw := false
+		if r, ok := req.Arguments["raw"]; ok {
+			if rBool, ok := r.(bool); ok {
+				raw = rBool
+			}
+		}
 
-	// Format result as JSON
-	jsonResult, err := json.MarshalIndent(result, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
-	}
+		// Fetch the content
+		result, err := fetch.fetchContent(parsedURL.String(), maxLength, startIndex, raw)
+		if err != nil {
+			return mcp.NewToolError(err.Error()), nil
+		}
 
-	return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
-}
+		// Format result as JSON
+		jsonResult, err := json.MarshalIndent(result, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
+		}
 
-// Prompt handlers
+		return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
+	}))
 
-func (fs *Server) HandleFetchPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
-	url, hasURL := req.Arguments["url"].(string)
-	reason, hasReason := req.Arguments["reason"].(string)
+	// Add fetch prompt
+	builder.AddPrompt(mcp.NewPrompt("fetch", "Prompt for manually entering a URL to fetch content from", []mcp.PromptArgument{
+		{
+			Name:        "url",
+			Description: "The URL to fetch content from",
+			Required:    true,
+		},
+		{
+			Name:        "reason",
+			Description: "Why you want to fetch this URL (optional context)",
+			Required:    false,
+		},
+	}, func(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+		url, hasURL := req.Arguments["url"].(string)
+		reason, hasReason := req.Arguments["reason"].(string)
 
-	if !hasURL || url == "" {
-		return mcp.GetPromptResult{}, fmt.Errorf("url argument is required")
-	}
+		if !hasURL || url == "" {
+			return mcp.GetPromptResult{}, fmt.Errorf("url argument is required")
+		}
 
-	// Create the prompt messages
-	var messages []mcp.PromptMessage
+		// Create the prompt messages
+		var messages []mcp.PromptMessage
 
-	// User message with the URL and optional reason
-	userContent := fmt.Sprintf("Please fetch the content from this URL: %s", url)
-	if hasReason && reason != "" {
-		userContent += fmt.Sprintf("\n\nReason: %s", reason)
-	}
+		// User message with the URL and optional reason
+		userContent := fmt.Sprintf("Please fetch the content from this URL: %s", url)
+		if hasReason && reason != "" {
+			userContent += fmt.Sprintf("\n\nReason: %s", reason)
+		}
 
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "user",
-		Content: mcp.NewTextContent(userContent),
-	})
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "user",
+			Content: mcp.NewTextContent(userContent),
+		})
 
-	// Assistant message suggesting the fetch tool usage
-	assistantContent := fmt.Sprintf(`I'll fetch the content from %s for you.
+		// Assistant message suggesting the fetch tool usage
+		assistantContent := fmt.Sprintf(`I'll fetch the content from %s for you.
 
 Let me use the fetch tool to retrieve and process the content:`, url)
 
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "assistant",
-		Content: mcp.NewTextContent(assistantContent),
-	})
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "assistant",
+			Content: mcp.NewTextContent(assistantContent),
+		})
 
-	description := "Manual URL fetch prompt"
-	if hasReason && reason != "" {
-		description = fmt.Sprintf("Manual URL fetch: %s", reason)
-	}
+		description := "Manual URL fetch prompt"
+		if hasReason && reason != "" {
+			description = fmt.Sprintf("Manual URL fetch: %s", reason)
+		}
+
+		return mcp.GetPromptResult{
+			Description: description,
+			Messages:    messages,
+		}, nil
+	}))
 
-	return mcp.GetPromptResult{
-		Description: description,
-		Messages:    messages,
-	}, nil
+	return builder.Build()
 }
 
-// Helper methods
+// Helper methods for FetchOperations
 
-func (fs *Server) fetchContent(urlStr string, maxLength, startIndex int, raw bool) (*FetchResult, error) {
+func (fetch *FetchOperations) fetchContent(urlStr string, maxLength, startIndex int, raw bool) (*FetchResult, error) {
 	// Create HTTP request
 	req, err := http.NewRequest("GET", urlStr, nil)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to create request: %v", err)
 	}
 
-	req.Header.Set("User-Agent", fs.userAgent)
+	req.Header.Set("User-Agent", fetch.userAgent)
 	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
 
 	// Perform HTTP request
-	resp, err := fs.httpClient.Do(req)
+	resp, err := fetch.httpClient.Do(req)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to fetch URL: %v", err)
 	}
@@ -282,7 +238,7 @@ func (fs *Server) fetchContent(urlStr string, maxLength, startIndex int, raw boo
 	} else {
 		// Convert HTML to markdown using improved processor
 		var err error
-		content, err = fs.htmlProcessor.ToMarkdown(string(body))
+		content, err = fetch.htmlProcessor.ToMarkdown(string(body))
 		if err != nil {
 			// Fallback to raw content if markdown conversion fails
 			content = string(body)
pkg/filesystem/server.go
@@ -12,111 +12,112 @@ import (
 func New(allowedDirs []string) *mcp.Server {
 	tree := NewTree(allowedDirs)
 
-	tools := []mcp.Tool{
-		mcp.NewTool("read_file", "Read the contents of a file", map[string]interface{}{
-			"type": "object",
-			"properties": map[string]interface{}{
-				"path": map[string]interface{}{
-					"type": "string",
-				},
+	builder := mcp.NewServerBuilder("filesystem", "0.2.0")
+
+	// Add tools
+	builder.AddTool(mcp.NewTool("read_file", "Read the contents of a file", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"path": map[string]interface{}{
+				"type": "string",
 			},
-			"required": []string{"path"},
-		}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-			pathStr, ok := req.Arguments["path"].(string)
-			if !ok {
-				return mcp.NewToolError("path is required"), nil
-			}
+		},
+		"required": []string{"path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		pathStr, ok := req.Arguments["path"].(string)
+		if !ok {
+			return mcp.NewToolError("path is required"), nil
+		}
 
-			validPath, err := tree.validatePath(pathStr)
-			if err != nil {
-				return mcp.NewToolError(err.Error()), nil
-			}
+		validPath, err := tree.validatePath(pathStr)
+		if err != nil {
+			return mcp.NewToolError(err.Error()), nil
+		}
 
-			content, err := os.ReadFile(validPath)
-			if err != nil {
-				return mcp.NewToolError(fmt.Sprintf("Failed to read file: %v", err)), nil
-			}
+		content, err := os.ReadFile(validPath)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to read file: %v", err)), nil
+		}
 
-			return mcp.NewToolResult(mcp.NewTextContent(string(content))), nil
-		}),
+		return mcp.NewToolResult(mcp.NewTextContent(string(content))), nil
+	}))
 
-		mcp.NewTool("write_file", "Write content to a file", map[string]interface{}{
-			"type": "object",
-			"properties": map[string]interface{}{
-				"path": map[string]interface{}{
-					"type": "string",
-				},
-				"content": map[string]interface{}{
-					"type": "string",
-				},
+	builder.AddTool(mcp.NewTool("write_file", "Write content to a file", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"path": map[string]interface{}{
+				"type": "string",
 			},
-			"required": []string{"path", "content"},
-		}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-			pathStr, ok := req.Arguments["path"].(string)
-			if !ok {
-				return mcp.NewToolError("path is required"), nil
-			}
+			"content": map[string]interface{}{
+				"type": "string",
+			},
+		},
+		"required": []string{"path", "content"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		pathStr, ok := req.Arguments["path"].(string)
+		if !ok {
+			return mcp.NewToolError("path is required"), nil
+		}
+
+		content, ok := req.Arguments["content"].(string)
+		if !ok {
+			return mcp.NewToolError("content is required"), nil
+		}
 
-			content, ok := req.Arguments["content"].(string)
-			if !ok {
-				return mcp.NewToolError("content is required"), nil
+		validPath, err := tree.validatePath(pathStr)
+		if err != nil {
+			return mcp.NewToolError(err.Error()), nil
+		}
+
+		err = os.WriteFile(validPath, []byte(content), 0644)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to write file: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Successfully wrote to %s", pathStr))), nil
+	}))
+
+	// Add pattern resource for file:// scheme
+	builder.AddResource(mcp.NewResource(
+		"file://",
+		"File System",
+		"",
+		func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
+			if !strings.HasPrefix(req.URI, "file://") {
+				return mcp.ReadResourceResult{}, fmt.Errorf("invalid file URI: %s", req.URI)
 			}
 
-			validPath, err := tree.validatePath(pathStr)
+			filePath := req.URI[7:]
+			validPath, err := tree.validatePath(filePath)
 			if err != nil {
-				return mcp.NewToolError(err.Error()), nil
+				return mcp.ReadResourceResult{}, fmt.Errorf("access denied: %v", err)
 			}
 
-			err = os.WriteFile(validPath, []byte(content), 0644)
+			content, err := os.ReadFile(validPath)
 			if err != nil {
-				return mcp.NewToolError(fmt.Sprintf("Failed to write file: %v", err)), nil
+				return mcp.ReadResourceResult{}, fmt.Errorf("failed to read file: %v", err)
 			}
 
-			return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Successfully wrote to %s", pathStr))), nil
-		}),
-	}
-
-	resources := []mcp.Resource{
-		mcp.NewResource(
-			"file://",
-			"File System",
-			"",
-			func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
-				if !strings.HasPrefix(req.URI, "file://") {
-					return mcp.ReadResourceResult{}, fmt.Errorf("invalid file URI: %s", req.URI)
-				}
-
-				filePath := req.URI[7:]
-				validPath, err := tree.validatePath(filePath)
-				if err != nil {
-					return mcp.ReadResourceResult{}, fmt.Errorf("access denied: %v", err)
-				}
-
-				content, err := os.ReadFile(validPath)
-				if err != nil {
-					return mcp.ReadResourceResult{}, fmt.Errorf("failed to read file: %v", err)
-				}
-
-				if isBinaryContent(content) {
-					return mcp.ReadResourceResult{
-						Contents: []mcp.Content{
-							mcp.TextContent{
-								Type: "text",
-								Text: fmt.Sprintf("Binary file (size: %d bytes)", len(content)),
-							},
-						},
-					}, nil
-				}
-
+			if isBinaryContent(content) {
 				return mcp.ReadResourceResult{
 					Contents: []mcp.Content{
-						mcp.NewTextContent(string(content)),
+						mcp.TextContent{
+							Type: "text",
+							Text: fmt.Sprintf("Binary file (size: %d bytes)", len(content)),
+						},
 					},
 				}, nil
-			},
-		),
-	}
+			}
+
+			return mcp.ReadResourceResult{
+				Contents: []mcp.Content{
+					mcp.NewTextContent(string(content)),
+				},
+			}, nil
+		},
+	))
 
+	// Add directory resources and discover files
 	for _, dir := range tree.Directories {
 		fileURI := "file://" + dir
 		dirName := filepath.Base(dir)
@@ -124,7 +125,7 @@ func New(allowedDirs []string) *mcp.Server {
 			dirName = dir
 		}
 
-		resources = append(resources, mcp.NewResource(
+		builder.AddResource(mcp.NewResource(
 			fileURI,
 			fmt.Sprintf("Directory: %s", dirName),
 			"inode/directory",
@@ -139,18 +140,20 @@ func New(allowedDirs []string) *mcp.Server {
 
 		// Discover files in this directory at construction time
 		fileResources := tree.discoverFiles(dir)
-		resources = append(resources, fileResources...)
+		for _, resource := range fileResources {
+			builder.AddResource(resource)
+		}
 	}
 
-	var roots []mcp.Root
+	// Add roots
 	for _, dir := range tree.Directories {
 		fileURI := "file://" + dir
 		dirName := filepath.Base(dir)
 		if dirName == "." || dirName == "/" {
 			dirName = dir
 		}
-		roots = append(roots, mcp.NewRoot(fileURI, fmt.Sprintf("Directory: %s", dirName)))
+		builder.AddRoot(mcp.NewRoot(fileURI, fmt.Sprintf("Directory: %s", dirName)))
 	}
 
-	return mcp.NewServer("filesystem", "0.2.0", tools, resources, roots)
+	return builder.Build()
 }
pkg/filesystem/tree.go
@@ -88,11 +88,14 @@ func (fs *Tree) discoverFiles(dirPath string) []mcp.Resource {
 		fileURI := "file://" + path
 		relPath, _ := filepath.Rel(dirPath, path)
 
-		resource := mcp.Resource{
-			URI:      fileURI,
-			Name:     relPath,
-			MimeType: mimeType,
-		}
+		resource := mcp.NewResource(
+			fileURI,
+			relPath,
+			mimeType,
+			func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
+				return mcp.ReadResourceResult{}, fmt.Errorf("individual file resources are handled by the pattern handler")
+			},
+		)
 
 		resources = append(resources, resource)
 		fileCount++
pkg/git/server.go
@@ -1,7 +1,6 @@
 package git
 
 import (
-	"encoding/json"
 	"fmt"
 	"os"
 	"os/exec"
@@ -12,259 +11,583 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Git MCP server
-type Server struct {
-	*mcp.Server
+// Commit represents a git commit
+type Commit struct {
+	Hash    string
+	Message string
+	Author  string
+	Date    string
+}
+
+// GitOperations provides git operations for a specific repository
+type GitOperations struct {
 	repoPath string
 }
 
+// NewGitOperations creates a new GitOperations helper
+func NewGitOperations(repoPath string) *GitOperations {
+	return &GitOperations{repoPath: repoPath}
+}
+
 // New creates a new Git MCP server
-func New(repoPath string) *Server {
-	server := mcp.NewServer("mcp-git", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
+func New(repoPath string) *mcp.Server {
+	git := NewGitOperations(repoPath)
+	builder := mcp.NewServerBuilder("mcp-git", "1.0.0")
+
+	// Add git_status tool
+	builder.AddTool(mcp.NewTool("git_status", "Shows the working tree status", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
 
-	gitServer := &Server{
-		Server:   server,
-		repoPath: repoPath,
-	}
+		output, err := git.runGitCommand(repoPath, "status")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git status failed: %v", err)), nil
+		}
 
-	// Register all git tools, prompts, resources, and roots
-	gitServer.registerTools()
-	gitServer.registerPrompts()
-	gitServer.registerResources()
-	gitServer.registerRoots()
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Repository status:\n%s", output))), nil
+	}))
 
-	// Set up dynamic resource listing
-	gitServer.setupResourceHandling()
+	// Add git_diff_unstaged tool
+	builder.AddTool(mcp.NewTool("git_diff_unstaged", "Shows changes in the working directory that are not yet staged", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
 
-	return gitServer
-}
+		output, err := git.runGitCommand(repoPath, "diff")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git diff failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Unstaged changes:\n%s", output))), nil
+	}))
 
-// setupResourceHandling configures custom resource handling for lazy loading
-func (gs *Server) setupResourceHandling() {
-	// Custom handler that calls our ListResources method
-	customListResourcesHandler := func(req mcp.JSONRPCRequest) mcp.JSONRPCResponse {
-		resources := gs.ListResources()
-		result := mcp.ListResourcesResult{Resources: resources}
-		id := req.ID
-		bytes, _ := json.Marshal(result)
-		rawMsg := json.RawMessage(bytes)
-		resultBytes := &rawMsg
-		return mcp.JSONRPCResponse{
-			JSONRPC: "2.0",
-			ID:      id,
-			Result:  resultBytes,
+	// Add git_diff_staged tool
+	builder.AddTool(mcp.NewTool("git_diff_staged", "Shows changes that are staged for commit", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
 		}
-	}
-	
-	handlers := make(map[string]func(mcp.JSONRPCRequest) mcp.JSONRPCResponse)
-	handlers["resources/list"] = customListResourcesHandler
-	gs.SetCustomRequestHandler(handlers)
-}
 
-// ListResources dynamically discovers and returns git resources
-func (gs *Server) ListResources() []mcp.Resource {
-	resources := make([]mcp.Resource, 0)
+		output, err := git.runGitCommand(repoPath, "diff", "--cached")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git diff --cached failed: %v", err)), nil
+		}
 
-	// Check if this is a git repository
-	gitDir := filepath.Join(gs.repoPath, ".git")
-	if _, err := os.Stat(gitDir); os.IsNotExist(err) {
-		return resources // Return empty for non-git repositories
-	}
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Staged changes:\n%s", output))), nil
+	}))
 
-	// Get current branch (only when needed)
-	currentBranch, err := gs.getCurrentBranch()
-	if err != nil {
-		currentBranch = "unknown"
-	}
+	// Add git_diff tool
+	builder.AddTool(mcp.NewTool("git_diff", "Shows differences between branches or commits", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"target": map[string]interface{}{
+				"type":        "string",
+				"description": "Target branch or commit to diff against",
+			},
+		},
+		"required": []string{"repo_path", "target"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
 
-	// Get tracked files (only when requested)
-	trackedFiles, err := gs.getTrackedFiles()
-	if err != nil {
-		return resources // Return empty on error
-	}
+		target, ok := req.Arguments["target"].(string)
+		if !ok {
+			return mcp.NewToolError("target is required"), nil
+		}
 
-	// Create resources for tracked files (limited to first 500 for performance)
-	limit := 500
-	for i, filePath := range trackedFiles {
-		if i >= limit {
-			break // Prevent loading too many resources at once
+		output, err := git.runGitCommand(repoPath, "diff", target)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git diff failed: %v", err)), nil
 		}
 
-		// Create git:// URI: git://repo/branch/path
-		gitURI := fmt.Sprintf("git://%s/%s/%s", gs.repoPath, currentBranch, filePath)
-		
-		// Determine MIME type
-		mimeType := getGitMimeType(filePath)
-
-		// Create resource definition
-		resource := mcp.Resource{
-			URI:         gitURI,
-			Name:        filepath.Base(filePath),
-			Description: fmt.Sprintf("Git file: %s (branch: %s)", filePath, currentBranch),
-			MimeType:    mimeType,
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Diff with %s:\n%s", target, output))), nil
+	}))
+
+	// Add git_commit tool
+	builder.AddTool(mcp.NewTool("git_commit", "Records changes to the repository", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"message": map[string]interface{}{
+				"type":        "string",
+				"description": "Commit message",
+			},
+		},
+		"required": []string{"repo_path", "message"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
 		}
-		resources = append(resources, resource)
-	}
 
-	// Add branch resources (limited set)
-	branches, err := gs.getBranches()
-	if err == nil {
-		for i, branch := range branches {
-			if i >= 10 { // Limit to 10 branches
-				break
-			}
-			branchURI := fmt.Sprintf("git://%s/branch/%s", gs.repoPath, branch)
-			resource := mcp.Resource{
-				URI:         branchURI,
-				Name:        fmt.Sprintf("Branch: %s", branch),
-				Description: fmt.Sprintf("Git branch: %s", branch),
-				MimeType:    "application/x-git-branch",
-			}
-			resources = append(resources, resource)
+		message, ok := req.Arguments["message"].(string)
+		if !ok {
+			return mcp.NewToolError("message is required"), nil
+		}
+
+		output, err := git.runGitCommand(repoPath, "commit", "-m", message)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git commit failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Changes committed successfully:\n%s", output))), nil
+	}))
+
+	// Add git_add tool
+	builder.AddTool(mcp.NewTool("git_add", "Adds file contents to the staging area", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"files": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "string",
+				},
+				"description": "List of files to add",
+			},
+		},
+		"required": []string{"repo_path", "files"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		filesInterface, ok := req.Arguments["files"]
+		if !ok {
+			return mcp.NewToolError("files is required"), nil
+		}
+
+		files, err := convertToStringSlice(filesInterface)
+		if err != nil {
+			return mcp.NewToolError("files must be an array of strings"), nil
 		}
-	}
 
-	// Add recent commit resources (limited set)
-	commits, err := gs.getRecentCommits(10)
-	if err == nil {
-		for _, commit := range commits {
-			commitURI := fmt.Sprintf("git://%s/commit/%s", gs.repoPath, commit.Hash)
-			resource := mcp.Resource{
-				URI:         commitURI,
-				Name:        fmt.Sprintf("Commit: %s", commit.Hash[:8]),
-				Description: fmt.Sprintf("Git commit: %s - %s", commit.Hash[:8], commit.Message),
-				MimeType:    "application/x-git-commit",
+		args := append([]string{"add"}, files...)
+		_, err = git.runGitCommand(repoPath, args...)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git add failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent("Files staged successfully")), nil
+	}))
+
+	// Add git_reset tool
+	builder.AddTool(mcp.NewTool("git_reset", "Unstages all staged changes", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		_, err := git.runGitCommand(repoPath, "reset")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git reset failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent("All staged changes reset")), nil
+	}))
+
+	// Add git_log tool
+	builder.AddTool(mcp.NewTool("git_log", "Shows the commit logs", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"max_count": map[string]interface{}{
+				"type":        "integer",
+				"description": "Maximum number of commits to show",
+				"default":     10,
+			},
+		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		maxCount := 10
+		if mc, exists := req.Arguments["max_count"]; exists {
+			if count, ok := mc.(float64); ok {
+				maxCount = int(count)
 			}
-			resources = append(resources, resource)
 		}
-	}
 
-	return resources
-}
+		output, err := git.runGitCommand(repoPath, "log", "--oneline", "-n", strconv.Itoa(maxCount))
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git log failed: %v", err)), nil
+		}
 
-// registerTools registers all Git tools with the server
-func (gs *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := gs.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "git_status":
-			handler = gs.HandleGitStatus
-		case "git_diff_unstaged":
-			handler = gs.HandleGitDiffUnstaged
-		case "git_diff_staged":
-			handler = gs.HandleGitDiffStaged
-		case "git_diff":
-			handler = gs.HandleGitDiff
-		case "git_commit":
-			handler = gs.HandleGitCommit
-		case "git_add":
-			handler = gs.HandleGitAdd
-		case "git_reset":
-			handler = gs.HandleGitReset
-		case "git_log":
-			handler = gs.HandleGitLog
-		case "git_create_branch":
-			handler = gs.HandleGitCreateBranch
-		case "git_checkout":
-			handler = gs.HandleGitCheckout
-		case "git_show":
-			handler = gs.HandleGitShow
-		case "git_init":
-			handler = gs.HandleGitInit
-		default:
-			continue
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Commit history:\n%s", output))), nil
+	}))
+
+	// Add git_create_branch tool
+	builder.AddTool(mcp.NewTool("git_create_branch", "Creates a new branch from an optional base branch", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"branch_name": map[string]interface{}{
+				"type":        "string",
+				"description": "Name of the new branch",
+			},
+			"base_branch": map[string]interface{}{
+				"type":        "string",
+				"description": "Base branch to create from (optional)",
+			},
+		},
+		"required": []string{"repo_path", "branch_name"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		branchName, ok := req.Arguments["branch_name"].(string)
+		if !ok {
+			return mcp.NewToolError("branch_name is required"), nil
 		}
-		gs.RegisterToolWithDefinition(tool, handler)
-	}
-}
 
-// registerPrompts registers all Git prompts with the server
-func (gs *Server) registerPrompts() {
-	commitPrompt := mcp.Prompt{
-		Name:        "commit-message",
-		Description: "Prompt for crafting a well-structured git commit message",
-		Arguments: []mcp.PromptArgument{
-			{
-				Name:        "changes",
-				Description: "Description of the changes being committed",
-				Required:    true,
+		baseBranch, _ := req.Arguments["base_branch"].(string)
+
+		var args []string
+		if baseBranch != "" {
+			args = []string{"checkout", "-b", branchName, baseBranch}
+		} else {
+			args = []string{"checkout", "-b", branchName}
+		}
+
+		_, err := git.runGitCommand(repoPath, args...)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git create branch failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Created branch '%s'", branchName))), nil
+	}))
+
+	// Add git_checkout tool
+	builder.AddTool(mcp.NewTool("git_checkout", "Switches branches", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
+			},
+			"branch_name": map[string]interface{}{
+				"type":        "string",
+				"description": "Name of the branch to checkout",
+			},
+		},
+		"required": []string{"repo_path", "branch_name"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		branchName, ok := req.Arguments["branch_name"].(string)
+		if !ok {
+			return mcp.NewToolError("branch_name is required"), nil
+		}
+
+		_, err := git.runGitCommand(repoPath, "checkout", branchName)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git checkout failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Switched to branch '%s'", branchName))), nil
+	}))
+
+	// Add git_show tool
+	builder.AddTool(mcp.NewTool("git_show", "Shows the contents of a commit", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path to the Git repository",
 			},
-			{
-				Name:        "type",
-				Description: "Type of change (feat, fix, docs, style, refactor, test, chore)",
-				Required:    false,
+			"revision": map[string]interface{}{
+				"type":        "string",
+				"description": "Commit hash or reference to show",
 			},
-			{
-				Name:        "breaking",
-				Description: "Whether this is a breaking change (true/false)",
-				Required:    false,
+		},
+		"required": []string{"repo_path", "revision"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		revision, ok := req.Arguments["revision"].(string)
+		if !ok {
+			return mcp.NewToolError("revision is required"), nil
+		}
+
+		output, err := git.runGitCommand(repoPath, "show", revision)
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git show failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(output)), nil
+	}))
+
+	// Add git_init tool
+	builder.AddTool(mcp.NewTool("git_init", "Initialize a new Git repository", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"repo_path": map[string]interface{}{
+				"type":        "string",
+				"description": "Path where to initialize the Git repository",
 			},
 		},
+		"required": []string{"repo_path"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		repoPath, ok := req.Arguments["repo_path"].(string)
+		if !ok {
+			repoPath = git.repoPath
+		}
+
+		if err := os.MkdirAll(repoPath, 0755); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("failed to create directory: %v", err)), nil
+		}
+
+		_, err := git.runGitCommand(repoPath, "init")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("git init failed: %v", err)), nil
+		}
+
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Initialized empty Git repository in %s", repoPath))), nil
+	}))
+
+	// Add commit-message prompt
+	builder.AddPrompt(mcp.NewPrompt("commit-message", "Prompt for crafting a well-structured git commit message", []mcp.PromptArgument{
+		{
+			Name:        "changes",
+			Description: "Description of the changes being committed",
+			Required:    true,
+		},
+		{
+			Name:        "type",
+			Description: "Type of change (feat, fix, docs, style, refactor, test, chore)",
+			Required:    false,
+		},
+		{
+			Name:        "breaking",
+			Description: "Whether this is a breaking change (true/false)",
+			Required:    false,
+		},
+	}, func(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+		changes, hasChanges := req.Arguments["changes"].(string)
+		commitType, hasType := req.Arguments["type"].(string)
+		breaking, hasBreaking := req.Arguments["breaking"]
+
+		if !hasChanges || changes == "" {
+			return mcp.GetPromptResult{}, fmt.Errorf("changes argument is required")
+		}
+
+		if !hasType || commitType == "" {
+			commitType = "feat"
+		}
+
+		isBreaking := false
+		if hasBreaking {
+			if breakingBool, ok := breaking.(bool); ok {
+				isBreaking = breakingBool
+			} else if breakingStr, ok := breaking.(string); ok {
+				isBreaking = breakingStr == "true"
+			}
+		}
+
+		var messages []mcp.PromptMessage
+
+		userContent := fmt.Sprintf(`I need help writing a git commit message for the following changes:
+
+%s
+
+Please help me craft a well-structured commit message following conventional commit format.`, changes)
+
+		if hasType {
+			userContent += fmt.Sprintf("\n\nCommit type: %s", commitType)
+		}
+		if isBreaking {
+			userContent += "\n\nThis is a BREAKING CHANGE."
+		}
+
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "user",
+			Content: mcp.NewTextContent(userContent),
+		})
+
+		breakingPrefix := ""
+		if isBreaking {
+			breakingPrefix = "!"
+		}
+
+		assistantContent := fmt.Sprintf(`I'll help you create a conventional commit message. Here's the suggested format:
+
+**Commit message:**
+%s%s: %s
+
+**Format explanation:**
+- Type: %s (indicates the nature of the change)
+- Description: Clear, concise summary in present tense
+%s
+
+**Additional guidelines:**
+- Keep the subject line under 50 characters
+- Use imperative mood ("add" not "added")
+- Don't end subject line with a period
+- Include body if needed to explain what and why`,
+			commitType, breakingPrefix, changes,
+			commitType,
+			func() string {
+				if isBreaking {
+					return "- Breaking change: This change breaks backward compatibility"
+				}
+				return ""
+			}())
+
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "assistant",
+			Content: mcp.NewTextContent(assistantContent),
+		})
+
+		description := fmt.Sprintf("Commit message guidance for %s changes", commitType)
+		if isBreaking {
+			description += " (BREAKING)"
+		}
+
+		return mcp.GetPromptResult{
+			Description: description,
+			Messages:    messages,
+		}, nil
+	}))
+
+	// Add git:// pattern resource for dynamic file access
+	builder.AddResource(mcp.NewResource(
+		"git://",
+		"Git Repository",
+		"",
+		func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
+			return git.handleGitResource(req)
+		},
+	))
+
+	// Add repository root if it's a git repository
+	gitDir := filepath.Join(git.repoPath, ".git")
+	if _, err := os.Stat(gitDir); err == nil {
+		currentBranch, err := git.getCurrentBranch()
+		if err != nil {
+			currentBranch = "unknown"
+		}
+
+		gitURI := "git://" + git.repoPath
+		repoName := filepath.Base(git.repoPath)
+		if repoName == "." || repoName == "/" {
+			repoName = git.repoPath
+		}
+
+		rootName := fmt.Sprintf("Git Repository: %s (branch: %s)", repoName, currentBranch)
+		builder.AddRoot(mcp.NewRoot(gitURI, rootName))
 	}
 
-	gs.RegisterPrompt(commitPrompt, gs.HandleCommitMessagePrompt)
+	return builder.Build()
 }
 
-// registerResources sets up resource handling (lazy loading)
-func (gs *Server) registerResources() {
-	// Register pattern-based git resource handlers instead of discovering all files
-	// This avoids loading all repository files into memory at startup
-	gs.Server.RegisterResource("git://", gs.HandleGitResource)
-}
+// Helper methods for GitOperations
 
-// registerRoots registers git repository as a root
-func (gs *Server) registerRoots() {
-	// Check if this is a git repository
-	gitDir := filepath.Join(gs.repoPath, ".git")
-	if _, err := os.Stat(gitDir); os.IsNotExist(err) {
-		// Not a git repository, skip root registration
-		return
+func (git *GitOperations) runGitCommand(repoPath string, args ...string) (string, error) {
+	if _, err := os.Stat(repoPath); os.IsNotExist(err) {
+		return "", fmt.Errorf("repository path does not exist: %s", repoPath)
 	}
 
-	// Get current branch for additional info
-	currentBranch, err := gs.getCurrentBranch()
-	if err != nil {
-		currentBranch = "unknown"
+	if len(args) > 0 && args[0] != "init" {
+		gitDir := filepath.Join(repoPath, ".git")
+		if _, err := os.Stat(gitDir); os.IsNotExist(err) {
+			return "", fmt.Errorf("not a git repository: %s", repoPath)
+		}
 	}
 
-	// Create git:// URI for the repository
-	gitURI := "git://" + gs.repoPath
+	cmd := exec.Command("git", args...)
+	cmd.Dir = repoPath
 
-	// Create a user-friendly name from the repository path
-	repoName := filepath.Base(gs.repoPath)
-	if repoName == "." || repoName == "/" {
-		repoName = gs.repoPath
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		return "", fmt.Errorf("%v: %s", err, string(output))
 	}
 
-	// Include current branch information in the name
-	rootName := fmt.Sprintf("Git Repository: %s (branch: %s)", repoName, currentBranch)
-
-	root := mcp.NewRoot(gitURI, rootName)
-	gs.RegisterRoot(root)
+	return strings.TrimSpace(string(output)), nil
 }
 
-
-// getCurrentBranch gets the current git branch
-func (gs *Server) getCurrentBranch() (string, error) {
-	output, err := gs.runGitCommand(gs.repoPath, "branch", "--show-current")
+func (git *GitOperations) getCurrentBranch() (string, error) {
+	output, err := git.runGitCommand(git.repoPath, "branch", "--show-current")
 	if err != nil {
 		return "", err
 	}
 	branch := strings.TrimSpace(output)
 	if branch == "" {
-		// Fallback for detached HEAD
 		branch = "HEAD"
 	}
 	return branch, nil
 }
 
-// getTrackedFiles gets list of tracked files in the repository
-func (gs *Server) getTrackedFiles() ([]string, error) {
-	output, err := gs.runGitCommand(gs.repoPath, "ls-files")
+func (git *GitOperations) getTrackedFiles() ([]string, error) {
+	output, err := git.runGitCommand(git.repoPath, "ls-files")
 	if err != nil {
 		return nil, err
 	}
@@ -278,21 +601,16 @@ func (gs *Server) getTrackedFiles() ([]string, error) {
 
 	for _, file := range files {
 		file = strings.TrimSpace(file)
-		if file != "" {
-			// Skip hidden files and certain patterns
-			if !strings.HasPrefix(file, ".") {
-				filteredFiles = append(filteredFiles, file)
-			}
+		if file != "" && !strings.HasPrefix(file, ".") {
+			filteredFiles = append(filteredFiles, file)
 		}
 	}
 
 	return filteredFiles, nil
 }
 
-
-// getBranches gets list of git branches
-func (gs *Server) getBranches() ([]string, error) {
-	output, err := gs.runGitCommand(gs.repoPath, "branch", "--format=%(refname:short)")
+func (git *GitOperations) getBranches() ([]string, error) {
+	output, err := git.runGitCommand(git.repoPath, "branch", "--format=%(refname:short)")
 	if err != nil {
 		return nil, err
 	}
@@ -314,17 +632,8 @@ func (gs *Server) getBranches() ([]string, error) {
 	return filteredBranches, nil
 }
 
-// Commit represents a git commit
-type Commit struct {
-	Hash    string
-	Message string
-	Author  string
-	Date    string
-}
-
-// getRecentCommits gets recent git commits
-func (gs *Server) getRecentCommits(count int) ([]Commit, error) {
-	output, err := gs.runGitCommand(gs.repoPath, "log", "--format=%H|%s|%an|%ad", "--date=short", "-n", strconv.Itoa(count))
+func (git *GitOperations) getRecentCommits(count int) ([]Commit, error) {
+	output, err := git.runGitCommand(git.repoPath, "log", "--format=%H|%s|%an|%ad", "--date=short", "-n", strconv.Itoa(count))
 	if err != nil {
 		return nil, err
 	}
@@ -356,14 +665,12 @@ func (gs *Server) getRecentCommits(count int) ([]Commit, error) {
 	return commits, nil
 }
 
-// HandleGitResource handles git:// resource requests
-func (gs *Server) HandleGitResource(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
-	// Parse git:// URI: git://repo/branch/path or git://repo/commit/hash or git://repo/branch/name
+func (git *GitOperations) handleGitResource(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
 	if !strings.HasPrefix(req.URI, "git://") {
 		return mcp.ReadResourceResult{}, fmt.Errorf("invalid git URI: %s", req.URI)
 	}
 
-	uriPath := req.URI[6:] // Remove "git://" prefix
+	uriPath := req.URI[6:]
 	parts := strings.Split(uriPath, "/")
 
 	if len(parts) < 3 {
@@ -374,27 +681,23 @@ func (gs *Server) HandleGitResource(req mcp.ReadResourceRequest) (mcp.ReadResour
 	resourceType := parts[1]
 	resourcePath := strings.Join(parts[2:], "/")
 
-	// Validate repository path
-	if repoPath != gs.repoPath {
+	if repoPath != git.repoPath {
 		return mcp.ReadResourceResult{}, fmt.Errorf("access denied: repository path mismatch")
 	}
 
 	switch resourceType {
 	case "branch":
-		return gs.handleBranchResource(resourcePath)
+		return git.handleBranchResource(resourcePath)
 	case "commit":
-		return gs.handleCommitResource(resourcePath)
+		return git.handleCommitResource(resourcePath)
 	default:
-		// Treat as file path with branch
-		return gs.handleFileResource(resourceType, resourcePath)
+		return git.handleFileResource(resourceType, resourcePath)
 	}
 }
 
-// handleFileResource handles git file resources
-func (gs *Server) handleFileResource(branch, filePath string) (mcp.ReadResourceResult, error) {
-	// Use git show to get file content from specific branch
+func (git *GitOperations) handleFileResource(branch, filePath string) (mcp.ReadResourceResult, error) {
 	gitPath := fmt.Sprintf("%s:%s", branch, filePath)
-	output, err := gs.runGitCommand(gs.repoPath, "show", gitPath)
+	output, err := git.runGitCommand(git.repoPath, "show", gitPath)
 	if err != nil {
 		return mcp.ReadResourceResult{}, fmt.Errorf("failed to read git file: %v", err)
 	}
@@ -406,10 +709,8 @@ func (gs *Server) handleFileResource(branch, filePath string) (mcp.ReadResourceR
 	}, nil
 }
 
-// handleBranchResource handles git branch resources
-func (gs *Server) handleBranchResource(branchName string) (mcp.ReadResourceResult, error) {
-	// Get branch information
-	output, err := gs.runGitCommand(gs.repoPath, "log", "--oneline", "-n", "5", branchName)
+func (git *GitOperations) handleBranchResource(branchName string) (mcp.ReadResourceResult, error) {
+	output, err := git.runGitCommand(git.repoPath, "log", "--oneline", "-n", "5", branchName)
 	if err != nil {
 		return mcp.ReadResourceResult{}, fmt.Errorf("failed to get branch info: %v", err)
 	}
@@ -423,10 +724,8 @@ func (gs *Server) handleBranchResource(branchName string) (mcp.ReadResourceResul
 	}, nil
 }
 
-// handleCommitResource handles git commit resources
-func (gs *Server) handleCommitResource(commitHash string) (mcp.ReadResourceResult, error) {
-	// Get commit details
-	output, err := gs.runGitCommand(gs.repoPath, "show", "--stat", commitHash)
+func (git *GitOperations) handleCommitResource(commitHash string) (mcp.ReadResourceResult, error) {
+	output, err := git.runGitCommand(git.repoPath, "show", "--stat", commitHash)
 	if err != nil {
 		return mcp.ReadResourceResult{}, fmt.Errorf("failed to get commit info: %v", err)
 	}
@@ -438,6 +737,26 @@ func (gs *Server) handleCommitResource(commitHash string) (mcp.ReadResourceResul
 	}, nil
 }
 
+// Helper function to convert interface{} to []string
+func convertToStringSlice(input interface{}) ([]string, error) {
+	switch v := input.(type) {
+	case []interface{}:
+		result := make([]string, len(v))
+		for i, item := range v {
+			str, ok := item.(string)
+			if !ok {
+				return nil, fmt.Errorf("item at index %d is not a string", i)
+			}
+			result[i] = str
+		}
+		return result, nil
+	case []string:
+		return v, nil
+	default:
+		return nil, fmt.Errorf("input is not a slice")
+	}
+}
+
 // Helper function to determine MIME type for git files
 func getGitMimeType(filePath string) string {
 	ext := strings.ToLower(filepath.Ext(filePath))
@@ -468,582 +787,3 @@ func getGitMimeType(filePath string) string {
 		return "text/plain"
 	}
 }
-
-// ListTools returns all available Git tools
-func (gs *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "git_status",
-			Description: "Shows the working tree status",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-		{
-			Name:        "git_diff_unstaged",
-			Description: "Shows changes in the working directory that are not yet staged",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-		{
-			Name:        "git_diff_staged",
-			Description: "Shows changes that are staged for commit",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-		{
-			Name:        "git_diff",
-			Description: "Shows differences between branches or commits",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"target": map[string]interface{}{
-						"type":        "string",
-						"description": "Target branch or commit to diff against",
-					},
-				},
-				"required": []string{"repo_path", "target"},
-			},
-		},
-		{
-			Name:        "git_commit",
-			Description: "Records changes to the repository",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"message": map[string]interface{}{
-						"type":        "string",
-						"description": "Commit message",
-					},
-				},
-				"required": []string{"repo_path", "message"},
-			},
-		},
-		{
-			Name:        "git_add",
-			Description: "Adds file contents to the staging area",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"files": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "string",
-						},
-						"description": "List of files to add",
-					},
-				},
-				"required": []string{"repo_path", "files"},
-			},
-		},
-		{
-			Name:        "git_reset",
-			Description: "Unstages all staged changes",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-		{
-			Name:        "git_log",
-			Description: "Shows the commit logs",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"max_count": map[string]interface{}{
-						"type":        "integer",
-						"description": "Maximum number of commits to show",
-						"default":     10,
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-		{
-			Name:        "git_create_branch",
-			Description: "Creates a new branch from an optional base branch",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"branch_name": map[string]interface{}{
-						"type":        "string",
-						"description": "Name of the new branch",
-					},
-					"base_branch": map[string]interface{}{
-						"type":        "string",
-						"description": "Base branch to create from (optional)",
-					},
-				},
-				"required": []string{"repo_path", "branch_name"},
-			},
-		},
-		{
-			Name:        "git_checkout",
-			Description: "Switches branches",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"branch_name": map[string]interface{}{
-						"type":        "string",
-						"description": "Name of the branch to checkout",
-					},
-				},
-				"required": []string{"repo_path", "branch_name"},
-			},
-		},
-		{
-			Name:        "git_show",
-			Description: "Shows the contents of a commit",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path to the Git repository",
-					},
-					"revision": map[string]interface{}{
-						"type":        "string",
-						"description": "Commit hash or reference to show",
-					},
-				},
-				"required": []string{"repo_path", "revision"},
-			},
-		},
-		{
-			Name:        "git_init",
-			Description: "Initialize a new Git repository",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"repo_path": map[string]interface{}{
-						"type":        "string",
-						"description": "Path where to initialize the Git repository",
-					},
-				},
-				"required": []string{"repo_path"},
-			},
-		},
-	}
-}
-
-// Tool handlers
-
-func (gs *Server) HandleGitStatus(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	output, err := gs.runGitCommand(repoPath, "status")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git status failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Repository status:\n%s", output))), nil
-}
-
-func (gs *Server) HandleGitDiffUnstaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	output, err := gs.runGitCommand(repoPath, "diff")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git diff failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Unstaged changes:\n%s", output))), nil
-}
-
-func (gs *Server) HandleGitDiffStaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	output, err := gs.runGitCommand(repoPath, "diff", "--cached")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git diff --cached failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Staged changes:\n%s", output))), nil
-}
-
-func (gs *Server) HandleGitDiff(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	target, ok := req.Arguments["target"].(string)
-	if !ok {
-		return mcp.NewToolError("target is required"), nil
-	}
-
-	output, err := gs.runGitCommand(repoPath, "diff", target)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git diff failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Diff with %s:\n%s", target, output))), nil
-}
-
-func (gs *Server) HandleGitCommit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	message, ok := req.Arguments["message"].(string)
-	if !ok {
-		return mcp.NewToolError("message is required"), nil
-	}
-
-	output, err := gs.runGitCommand(repoPath, "commit", "-m", message)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git commit failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Changes committed successfully:\n%s", output))), nil
-}
-
-func (gs *Server) HandleGitAdd(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	filesInterface, ok := req.Arguments["files"]
-	if !ok {
-		return mcp.NewToolError("files is required"), nil
-	}
-
-	files, err := gs.convertToStringSlice(filesInterface)
-	if err != nil {
-		return mcp.NewToolError("files must be an array of strings"), nil
-	}
-
-	args := append([]string{"add"}, files...)
-	_, err = gs.runGitCommand(repoPath, args...)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git add failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent("Files staged successfully")), nil
-}
-
-func (gs *Server) HandleGitReset(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	_, err := gs.runGitCommand(repoPath, "reset")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git reset failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent("All staged changes reset")), nil
-}
-
-func (gs *Server) HandleGitLog(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	maxCount := 10
-	if mc, exists := req.Arguments["max_count"]; exists {
-		if count, ok := mc.(float64); ok {
-			maxCount = int(count)
-		}
-	}
-
-	output, err := gs.runGitCommand(repoPath, "log", "--oneline", "-n", strconv.Itoa(maxCount))
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git log failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Commit history:\n%s", output))), nil
-}
-
-func (gs *Server) HandleGitCreateBranch(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	branchName, ok := req.Arguments["branch_name"].(string)
-	if !ok {
-		return mcp.NewToolError("branch_name is required"), nil
-	}
-
-	baseBranch, _ := req.Arguments["base_branch"].(string)
-
-	var args []string
-	if baseBranch != "" {
-		args = []string{"checkout", "-b", branchName, baseBranch}
-	} else {
-		args = []string{"checkout", "-b", branchName}
-	}
-
-	_, err := gs.runGitCommand(repoPath, args...)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git create branch failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Created branch '%s'", branchName))), nil
-}
-
-func (gs *Server) HandleGitCheckout(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	branchName, ok := req.Arguments["branch_name"].(string)
-	if !ok {
-		return mcp.NewToolError("branch_name is required"), nil
-	}
-
-	_, err := gs.runGitCommand(repoPath, "checkout", branchName)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git checkout failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Switched to branch '%s'", branchName))), nil
-}
-
-func (gs *Server) HandleGitShow(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	revision, ok := req.Arguments["revision"].(string)
-	if !ok {
-		return mcp.NewToolError("revision is required"), nil
-	}
-
-	output, err := gs.runGitCommand(repoPath, "show", revision)
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git show failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(output)), nil
-}
-
-func (gs *Server) HandleGitInit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	repoPath, ok := req.Arguments["repo_path"].(string)
-	if !ok {
-		repoPath = gs.repoPath
-	}
-
-	// Ensure directory exists
-	if err := os.MkdirAll(repoPath, 0755); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("failed to create directory: %v", err)), nil
-	}
-
-	_, err := gs.runGitCommand(repoPath, "init")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("git init failed: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Initialized empty Git repository in %s", repoPath))), nil
-}
-
-// Helper methods
-
-func (gs *Server) runGitCommand(repoPath string, args ...string) (string, error) {
-	// Check if path exists
-	if _, err := os.Stat(repoPath); os.IsNotExist(err) {
-		return "", fmt.Errorf("repository path does not exist: %s", repoPath)
-	}
-
-	// Check if it's a git repository (except for init command)
-	if len(args) > 0 && args[0] != "init" {
-		gitDir := filepath.Join(repoPath, ".git")
-		if _, err := os.Stat(gitDir); os.IsNotExist(err) {
-			return "", fmt.Errorf("not a git repository: %s", repoPath)
-		}
-	}
-
-	cmd := exec.Command("git", args...)
-	cmd.Dir = repoPath
-
-	output, err := cmd.CombinedOutput()
-	if err != nil {
-		return "", fmt.Errorf("%v: %s", err, string(output))
-	}
-
-	return strings.TrimSpace(string(output)), nil
-}
-
-// Prompt handlers
-
-func (gs *Server) HandleCommitMessagePrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
-	changes, hasChanges := req.Arguments["changes"].(string)
-	commitType, hasType := req.Arguments["type"].(string)
-	breaking, hasBreaking := req.Arguments["breaking"]
-
-	if !hasChanges || changes == "" {
-		return mcp.GetPromptResult{}, fmt.Errorf("changes argument is required")
-	}
-
-	// Default type if not provided
-	if !hasType || commitType == "" {
-		commitType = "feat" // Default to feature
-	}
-
-	// Parse breaking change flag
-	isBreaking := false
-	if hasBreaking {
-		if breakingBool, ok := breaking.(bool); ok {
-			isBreaking = breakingBool
-		} else if breakingStr, ok := breaking.(string); ok {
-			isBreaking = breakingStr == "true"
-		}
-	}
-
-	// Create the prompt messages
-	var messages []mcp.PromptMessage
-
-	// User message describing the changes
-	userContent := fmt.Sprintf(`I need help writing a git commit message for the following changes:
-
-%s
-
-Please help me craft a well-structured commit message following conventional commit format.`, changes)
-
-	if hasType {
-		userContent += fmt.Sprintf("\n\nCommit type: %s", commitType)
-	}
-	if isBreaking {
-		userContent += "\n\nThis is a BREAKING CHANGE."
-	}
-
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "user",
-		Content: mcp.NewTextContent(userContent),
-	})
-
-	// Assistant message with suggested commit format
-	breakingPrefix := ""
-	if isBreaking {
-		breakingPrefix = "!"
-	}
-
-	assistantContent := fmt.Sprintf(`I'll help you create a conventional commit message. Here's the suggested format:
-
-**Commit message:**
-%s%s: %s
-
-**Format explanation:**
-- Type: %s (indicates the nature of the change)
-- Description: Clear, concise summary in present tense
-%s
-
-**Additional guidelines:**
-- Keep the subject line under 50 characters
-- Use imperative mood ("add" not "added")
-- Don't end subject line with a period
-- Include body if needed to explain what and why`,
-		commitType, breakingPrefix, changes,
-		commitType,
-		func() string {
-			if isBreaking {
-				return "- Breaking change: This change breaks backward compatibility"
-			}
-			return ""
-		}())
-
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "assistant",
-		Content: mcp.NewTextContent(assistantContent),
-	})
-
-	description := fmt.Sprintf("Commit message guidance for %s changes", commitType)
-	if isBreaking {
-		description += " (BREAKING)"
-	}
-
-	return mcp.GetPromptResult{
-		Description: description,
-		Messages:    messages,
-	}, nil
-}
-
-// Helper methods
-
-func (gs *Server) convertToStringSlice(input interface{}) ([]string, error) {
-	switch v := input.(type) {
-	case []interface{}:
-		result := make([]string, len(v))
-		for i, item := range v {
-			str, ok := item.(string)
-			if !ok {
-				return nil, fmt.Errorf("item at index %d is not a string", i)
-			}
-			result[i] = str
-		}
-		return result, nil
-	case []string:
-		return v, nil
-	default:
-		return nil, fmt.Errorf("input is not a slice")
-	}
-}
pkg/mcp/server.go
@@ -8,49 +8,148 @@ import (
 	"log"
 	"os"
 	"strings"
-	"sync"
 )
 
-// Server represents an MCP server
+// ServerBuilder helps build immutable MCP servers with a fluent API
+type ServerBuilder struct {
+	name    string
+	version string
+	tools   []Tool
+	prompts []Prompt
+	resources []Resource
+	roots   []Root
+	
+	// Optional handlers
+	initializeHandler func(InitializeRequest) (InitializeResult, error)
+	shutdownHandler   func() error
+}
+
+// Server represents an immutable MCP server
 type Server struct {
 	name         string
 	version      string
 	capabilities ServerCapabilities
 
-	// Handler functions
+	// Immutable component definitions (handlers embedded in structs)
 	toolDefinitions     map[string]Tool
-	promptHandlers      map[string]PromptHandler
 	promptDefinitions   map[string]Prompt
-	resourceHandlers    map[string]ResourceHandler
 	resourceDefinitions map[string]Resource
 	rootDefinitions     map[string]Root
 
 	// Lifecycle handlers
 	initializeHandler func(InitializeRequest) (InitializeResult, error)
 	shutdownHandler   func() error
-
-	// Custom request handlers for overriding default behavior
-	customRequestHandlers map[string]func(JSONRPCRequest) JSONRPCResponse
-
-	mu sync.RWMutex
 }
 
 // Handler types
-type PromptHandler func(GetPromptRequest) (GetPromptResult, error)
 type ResourceHandler func(ReadResourceRequest) (ReadResourceResult, error)
 
-// NewServer creates a new MCP server
+// NewServerBuilder creates a new server builder
+func NewServerBuilder(name, version string) *ServerBuilder {
+	return &ServerBuilder{
+		name:    name,
+		version: version,
+		tools:   []Tool{},
+		prompts: []Prompt{},
+		resources: []Resource{},
+		roots:   []Root{},
+	}
+}
+
+// AddTool adds a tool to the server
+func (b *ServerBuilder) AddTool(tool Tool) *ServerBuilder {
+	b.tools = append(b.tools, tool)
+	return b
+}
+
+// AddPrompt adds a prompt to the server
+func (b *ServerBuilder) AddPrompt(prompt Prompt) *ServerBuilder {
+	b.prompts = append(b.prompts, prompt)
+	return b
+}
+
+// AddResource adds a resource to the server
+func (b *ServerBuilder) AddResource(resource Resource) *ServerBuilder {
+	b.resources = append(b.resources, resource)
+	return b
+}
+
+// AddRoot adds a root to the server
+func (b *ServerBuilder) AddRoot(root Root) *ServerBuilder {
+	b.roots = append(b.roots, root)
+	return b
+}
+
+// SetInitializeHandler sets the initialize handler
+func (b *ServerBuilder) SetInitializeHandler(handler func(InitializeRequest) (InitializeResult, error)) *ServerBuilder {
+	b.initializeHandler = handler
+	return b
+}
+
+// SetShutdownHandler sets the shutdown handler
+func (b *ServerBuilder) SetShutdownHandler(handler func() error) *ServerBuilder {
+	b.shutdownHandler = handler
+	return b
+}
+
+// Build creates an immutable server with dynamic capabilities
+func (b *ServerBuilder) Build() *Server {
+	// Build dynamic capabilities based on what components are present
+	capabilities := ServerCapabilities{
+		Logging: &LoggingCapability{}, // Always present
+	}
+	
+	if len(b.tools) > 0 {
+		capabilities.Tools = &ToolsCapability{}
+	}
+	if len(b.prompts) > 0 {
+		capabilities.Prompts = &PromptsCapability{}
+	}
+	if len(b.resources) > 0 {
+		capabilities.Resources = &ResourcesCapability{}
+	}
+	if len(b.roots) > 0 {
+		capabilities.Roots = &RootsCapability{}
+	}
+	
+	server := &Server{
+		name:         b.name,
+		version:      b.version,
+		capabilities: capabilities,
+		toolDefinitions:     make(map[string]Tool),
+		promptDefinitions:   make(map[string]Prompt),
+		resourceDefinitions: make(map[string]Resource),
+		rootDefinitions:     make(map[string]Root),
+		initializeHandler:   b.initializeHandler,
+		shutdownHandler:     b.shutdownHandler,
+	}
+
+	// Register all components
+	for _, tool := range b.tools {
+		server.toolDefinitions[tool.Name] = tool
+	}
+	for _, prompt := range b.prompts {
+		server.promptDefinitions[prompt.Name] = prompt
+	}
+	for _, resource := range b.resources {
+		server.resourceDefinitions[resource.URI] = resource
+	}
+	for _, root := range b.roots {
+		server.rootDefinitions[root.URI] = root
+	}
+
+	return server
+}
+
+// NewServer creates a new MCP server (deprecated - use ServerBuilder instead)
 func NewServer(name, version string, tools []Tool, resources []Resource, roots []Root) *Server {
 	server := &Server{
-		name:                  name,
-		version:               version,
-		toolDefinitions:       make(map[string]Tool),
-		promptHandlers:        make(map[string]PromptHandler),
-		promptDefinitions:     make(map[string]Prompt),
-		resourceHandlers:      make(map[string]ResourceHandler),
-		resourceDefinitions:   make(map[string]Resource),
-		rootDefinitions:       make(map[string]Root),
-		customRequestHandlers: make(map[string]func(JSONRPCRequest) JSONRPCResponse),
+		name:                name,
+		version:             version,
+		toolDefinitions:     make(map[string]Tool),
+		promptDefinitions:   make(map[string]Prompt),
+		resourceDefinitions: make(map[string]Resource),
+		rootDefinitions:     make(map[string]Root),
 		capabilities: ServerCapabilities{
 			Tools:     &ToolsCapability{},
 			Prompts:   &PromptsCapability{},
@@ -65,7 +164,6 @@ func NewServer(name, version string, tools []Tool, resources []Resource, roots [
 	}
 
 	for _, resource := range resources {
-		server.resourceHandlers[resource.URI] = resource.Handler
 		server.resourceDefinitions[resource.URI] = resource
 	}
 
@@ -76,43 +174,49 @@ func NewServer(name, version string, tools []Tool, resources []Resource, roots [
 	return server
 }
 
+// RegisterRoot registers a root with the server (immutable servers should use ServerBuilder)
+func (s *Server) RegisterRoot(root Root) {
+	s.rootDefinitions[root.URI] = root
+}
+
+// Compatibility methods for existing servers (deprecated - use ServerBuilder instead)
+
 // RegisterToolWithDefinition registers a tool with its full definition and handler
 func (s *Server) RegisterToolWithDefinition(tool Tool, handler ToolHandler) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
+	tool.Handler = handler
 	s.toolDefinitions[tool.Name] = tool
 }
 
 // RegisterPrompt registers a prompt with its definition and handler
 func (s *Server) RegisterPrompt(prompt Prompt, handler PromptHandler) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	s.promptHandlers[prompt.Name] = handler
+	prompt.Handler = handler
 	s.promptDefinitions[prompt.Name] = prompt
 }
 
 // RegisterResource registers a resource handler with minimal definition
 func (s *Server) RegisterResource(uri string, handler ResourceHandler) {
+	name := extractResourceName(uri)
+	if name == "" {
+		name = uri // Use the full URI as name if extraction fails
+	}
 	resource := Resource{
-		URI:  uri,
-		Name: extractResourceName(uri),
+		URI:     uri,
+		Name:    name,
+		Handler: handler,
 	}
 	s.RegisterResourceWithDefinition(resource, handler)
 }
 
 // RegisterResourceWithDefinition registers a resource with its full definition and handler
 func (s *Server) RegisterResourceWithDefinition(resource Resource, handler ResourceHandler) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	s.resourceHandlers[resource.URI] = handler
+	resource.Handler = handler
 	s.resourceDefinitions[resource.URI] = resource
 }
 
-// RegisterRoot registers a root with the server
-func (s *Server) RegisterRoot(root Root) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	s.rootDefinitions[root.URI] = root
+// SetCustomRequestHandler sets custom request handlers for overriding default behavior
+func (s *Server) SetCustomRequestHandler(handlers map[string]func(JSONRPCRequest) JSONRPCResponse) {
+	// For now, just log that this is deprecated - we removed custom handlers from immutable architecture
+	// This is a compatibility shim
 }
 
 // SetInitializeHandler sets the initialize handler
@@ -125,64 +229,40 @@ func (s *Server) SetShutdownHandler(handler func() error) {
 	s.shutdownHandler = handler
 }
 
-// SetCustomRequestHandler sets custom request handlers for overriding default behavior
-func (s *Server) SetCustomRequestHandler(handlers map[string]func(JSONRPCRequest) JSONRPCResponse) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	for method, handler := range handlers {
-		s.customRequestHandlers[method] = handler
-	}
-}
 
 // ListTools returns all registered tools
 func (s *Server) ListTools() []Tool {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	tools := make([]Tool, 0, len(s.toolDefinitions))
 	for _, tool := range s.toolDefinitions {
 		tools = append(tools, tool)
 	}
-
 	return tools
 }
 
 // ListPrompts returns all registered prompts
 func (s *Server) ListPrompts() []Prompt {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	prompts := make([]Prompt, 0, len(s.promptDefinitions))
 	for _, prompt := range s.promptDefinitions {
 		prompts = append(prompts, prompt)
 	}
-
 	return prompts
 }
 
 // ListResources returns all registered resources
 func (s *Server) ListResources() []Resource {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	resources := make([]Resource, 0, len(s.resourceDefinitions))
 	for _, resource := range s.resourceDefinitions {
 		resources = append(resources, resource)
 	}
-
 	return resources
 }
 
 // ListRoots returns all registered roots
 func (s *Server) ListRoots() []Root {
-	s.mu.RLock()
-	defer s.mu.RUnlock()
-
 	roots := make([]Root, 0, len(s.rootDefinitions))
 	for _, root := range s.rootDefinitions {
 		roots = append(roots, root)
 	}
-
 	return roots
 }
 
@@ -220,15 +300,6 @@ func (s *Server) Run(ctx context.Context) error {
 
 // handleRequest processes a JSON-RPC request
 func (s *Server) handleRequest(req JSONRPCRequest) JSONRPCResponse {
-	// Check for custom handlers first
-	s.mu.RLock()
-	if customHandler, exists := s.customRequestHandlers[req.Method]; exists {
-		s.mu.RUnlock()
-		return customHandler(req)
-	}
-	s.mu.RUnlock()
-
-	// Default handlers
 	switch req.Method {
 	case "initialize":
 		return s.handleInitialize(req)
@@ -307,10 +378,7 @@ func (s *Server) handleCallTool(req JSONRPCRequest) JSONRPCResponse {
 		return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
 	}
 
-	s.mu.RLock()
 	tool, exists := s.toolDefinitions[callReq.Name]
-	s.mu.RUnlock()
-
 	if !exists {
 		return s.createErrorResponse(req.ID, MethodNotFound, "Tool not found")
 	}
@@ -335,15 +403,12 @@ func (s *Server) handleGetPrompt(req JSONRPCRequest) JSONRPCResponse {
 		return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
 	}
 
-	s.mu.RLock()
-	handler, exists := s.promptHandlers[promptReq.Name]
-	s.mu.RUnlock()
-
+	prompt, exists := s.promptDefinitions[promptReq.Name]
 	if !exists {
 		return s.createErrorResponse(req.ID, MethodNotFound, "Prompt not found")
 	}
 
-	result, err := handler(promptReq)
+	result, err := prompt.Handler(promptReq)
 	if err != nil {
 		return s.createErrorResponse(req.ID, InternalError, err.Error())
 	}
@@ -369,27 +434,25 @@ func (s *Server) handleReadResource(req JSONRPCRequest) JSONRPCResponse {
 		return s.createErrorResponse(req.ID, InvalidParams, "Invalid params")
 	}
 
-	s.mu.RLock()
-	handler, exists := s.resourceHandlers[readReq.URI]
+	resource, exists := s.resourceDefinitions[readReq.URI]
 	if !exists {
 		// Try to find a pattern-based handler (e.g., for "file://" prefix)
-		for pattern, h := range s.resourceHandlers {
+		for pattern, r := range s.resourceDefinitions {
 			if pattern != "" && readReq.URI != pattern &&
 				((pattern == "file://" && strings.HasPrefix(readReq.URI, "file://")) ||
 					(strings.HasSuffix(pattern, "*") && strings.HasPrefix(readReq.URI, strings.TrimSuffix(pattern, "*")))) {
-				handler = h
+				resource = r
 				exists = true
 				break
 			}
 		}
 	}
-	s.mu.RUnlock()
 
 	if !exists {
 		return s.createErrorResponse(req.ID, MethodNotFound, "Resource not found")
 	}
 
-	result, err := handler(readReq)
+	result, err := resource.Handler(readReq)
 	if err != nil {
 		return s.createErrorResponse(req.ID, InternalError, err.Error())
 	}
@@ -471,6 +534,16 @@ func NewResource(uri, name, mimeType string, handler ResourceHandler) Resource {
 	}
 }
 
+// Helper function to create a new prompt with all fields
+func NewPrompt(name, description string, arguments []PromptArgument, handler PromptHandler) Prompt {
+	return Prompt{
+		Name:        name,
+		Description: description,
+		Arguments:   arguments,
+		Handler:     handler,
+	}
+}
+
 // Helper function to extract resource name from URI
 func extractResourceName(uri string) string {
 	// Find the last "/" in the URI and extract the part after it
pkg/mcp/types.go
@@ -138,11 +138,15 @@ func (i ImageContent) GetType() string {
 	return i.Type
 }
 
+// Handler types
+type PromptHandler func(GetPromptRequest) (GetPromptResult, error)
+
 // Prompt types
 type Prompt struct {
 	Name        string           `json:"name"`
 	Description string           `json:"description"`
 	Arguments   []PromptArgument `json:"arguments,omitempty"`
+	Handler     PromptHandler    `json:"-"`
 }
 
 type PromptArgument struct {
pkg/memory/server.go
@@ -10,15 +10,6 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Memory MCP server with knowledge graph functionality
-type Server struct {
-	*mcp.Server
-	memoryFile string
-	graph      *KnowledgeGraph
-	mu         sync.RWMutex
-	loaded     bool
-}
-
 // KnowledgeGraph represents the in-memory knowledge graph
 type KnowledgeGraph struct {
 	Entities  map[string]*Entity  `json:"entities"`
@@ -39,1003 +30,828 @@ type Relation struct {
 	RelationType string `json:"relationType"`
 }
 
-// New creates a new Memory MCP server
-func New(memoryFile string) *Server {
-	server := mcp.NewServer("mcp-memory", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
+// MemoryOperations provides memory graph operations
+type MemoryOperations struct {
+	memoryFile string
+	graph      *KnowledgeGraph
+	mu         sync.RWMutex
+	loaded     bool
+}
 
-	memoryServer := &Server{
-		Server:     server,
+// NewMemoryOperations creates a new MemoryOperations helper
+func NewMemoryOperations(memoryFile string) *MemoryOperations {
+	return &MemoryOperations{
 		memoryFile: memoryFile,
 		graph: &KnowledgeGraph{
 			Entities:  make(map[string]*Entity),
 			Relations: make(map[string]Relation),
 		},
 	}
-
-	// Register all memory tools, prompts, resources, and roots
-	memoryServer.registerTools()
-	memoryServer.registerPrompts()
-	memoryServer.registerResources()
-	memoryServer.registerRoots()
-
-	return memoryServer
 }
 
-
-// ensureGraphLoaded loads the knowledge graph only when needed
-func (ms *Server) ensureGraphLoaded() error {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-	
-	// Check if graph is already loaded
-	if !ms.loaded {
-		ms.loaded = true
-		
-		// Load from file if it exists
-		return ms.loadGraphInternal()
-	}
-	return nil
-}
-
-
-// registerTools registers all Memory tools with the server
-func (ms *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := ms.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "create_entities":
-			handler = ms.HandleCreateEntities
-		case "create_relations":
-			handler = ms.HandleCreateRelations
-		case "add_observations":
-			handler = ms.HandleAddObservations
-		case "delete_entities":
-			handler = ms.HandleDeleteEntities
-		case "delete_observations":
-			handler = ms.HandleDeleteObservations
-		case "delete_relations":
-			handler = ms.HandleDeleteRelations
-		case "read_graph":
-			handler = ms.HandleReadGraph
-		case "search_nodes":
-			handler = ms.HandleSearchNodes
-		case "open_nodes":
-			handler = ms.HandleOpenNodes
-		default:
-			continue
-		}
-		ms.RegisterToolWithDefinition(tool, handler)
-	}
-}
-
-// registerPrompts registers all Memory prompts with the server
-func (ms *Server) registerPrompts() {
-	knowledgePrompt := mcp.Prompt{
-		Name:        "knowledge-query",
-		Description: "Prompt for querying and exploring the knowledge graph",
-		Arguments: []mcp.PromptArgument{
-			{
-				Name:        "query",
-				Description: "What you want to search for or ask about in the knowledge graph",
-				Required:    true,
-			},
-			{
-				Name:        "context",
-				Description: "Additional context about your question (optional)",
-				Required:    false,
-			},
-		},
-	}
-
-	ms.RegisterPrompt(knowledgePrompt, ms.HandleKnowledgeQueryPrompt)
-}
-
-// registerResources sets up resource handling (lazy loading)
-func (ms *Server) registerResources() {
-	// Register a placeholder memory resource to make it discoverable
-	memoryURI := "memory://graph"
-	resource := mcp.Resource{
-		URI:         memoryURI,
-		Name:        "Knowledge Graph",
-		Description: "In-memory knowledge graph with entities and relations",
-		MimeType:    "application/json",
-	}
-	
-	ms.Server.RegisterResourceWithDefinition(resource, ms.HandleMemoryResource)
-}
-
-// registerRoots registers memory knowledge graph as a root (without live statistics)
-func (ms *Server) registerRoots() {
-	// Create memory:// URI for the knowledge graph
-	memoryURI := "memory://graph"
-
-	// Create a simple name without requiring graph loading
-	rootName := "Knowledge Graph"
-
-	root := mcp.NewRoot(memoryURI, rootName)
-	ms.RegisterRoot(root)
-}
-
-// ListTools returns all available Memory tools
-func (ms *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "create_entities",
-			Description: "Create multiple new entities in the knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"entities": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "object",
-							"properties": map[string]interface{}{
-								"name": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity",
-								},
-								"entityType": map[string]interface{}{
-									"type":        "string",
-									"description": "The type of the entity",
-								},
-								"observations": map[string]interface{}{
-									"type": "array",
-									"items": map[string]interface{}{
-										"type": "string",
-									},
-									"description": "An array of observation contents associated with the entity",
-								},
-							},
-							"required": []string{"name", "entityType", "observations"},
-						},
-					},
-				},
-				"required": []string{"entities"},
-			},
-		},
-		{
-			Name:        "create_relations",
-			Description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"relations": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "object",
-							"properties": map[string]interface{}{
-								"from": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity where the relation starts",
-								},
-								"to": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity where the relation ends",
-								},
-								"relationType": map[string]interface{}{
-									"type":        "string",
-									"description": "The type of the relation",
-								},
-							},
-							"required": []string{"from", "to", "relationType"},
-						},
-					},
-				},
-				"required": []string{"relations"},
-			},
-		},
-		{
-			Name:        "add_observations",
-			Description: "Add new observations to existing entities in the knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"observations": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "object",
-							"properties": map[string]interface{}{
-								"entityName": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity to add the observations to",
-								},
-								"contents": map[string]interface{}{
-									"type": "array",
-									"items": map[string]interface{}{
-										"type": "string",
-									},
-									"description": "An array of observation contents to add",
-								},
-							},
-							"required": []string{"entityName", "contents"},
-						},
-					},
-				},
-				"required": []string{"observations"},
-			},
-		},
-		{
-			Name:        "delete_entities",
-			Description: "Delete multiple entities and their associated relations from the knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"entityNames": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "string",
+// New creates a new Memory MCP server
+func New(memoryFile string) *mcp.Server {
+	memory := NewMemoryOperations(memoryFile)
+	builder := mcp.NewServerBuilder("mcp-memory", "1.0.0")
+
+	// Add create_entities tool
+	builder.AddTool(mcp.NewTool("create_entities", "Create multiple new entities in the knowledge graph", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"entities": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "object",
+					"properties": map[string]interface{}{
+						"name": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity",
 						},
-						"description": "An array of entity names to delete",
-					},
-				},
-				"required": []string{"entityNames"},
-			},
-		},
-		{
-			Name:        "delete_observations",
-			Description: "Delete specific observations from entities in the knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"deletions": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "object",
-							"properties": map[string]interface{}{
-								"entityName": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity containing the observations",
-								},
-								"observations": map[string]interface{}{
-									"type": "array",
-									"items": map[string]interface{}{
-										"type": "string",
-									},
-									"description": "An array of observations to delete",
-								},
-							},
-							"required": []string{"entityName", "observations"},
+						"entityType": map[string]interface{}{
+							"type":        "string",
+							"description": "The type of the entity",
 						},
-					},
-				},
-				"required": []string{"deletions"},
-			},
-		},
-		{
-			Name:        "delete_relations",
-			Description: "Delete multiple relations from the knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"relations": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "object",
-							"properties": map[string]interface{}{
-								"from": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity where the relation starts",
-								},
-								"to": map[string]interface{}{
-									"type":        "string",
-									"description": "The name of the entity where the relation ends",
-								},
-								"relationType": map[string]interface{}{
-									"type":        "string",
-									"description": "The type of the relation",
-								},
+						"observations": map[string]interface{}{
+							"type": "array",
+							"items": map[string]interface{}{
+								"type": "string",
 							},
-							"required": []string{"from", "to", "relationType"},
-						},
-					},
-				},
-				"required": []string{"relations"},
-			},
-		},
-		{
-			Name:        "read_graph",
-			Description: "Read the entire knowledge graph",
-			InputSchema: map[string]interface{}{
-				"type":       "object",
-				"properties": map[string]interface{}{},
-			},
-		},
-		{
-			Name:        "search_nodes",
-			Description: "Search for nodes in the knowledge graph based on a query",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"query": map[string]interface{}{
-						"type":        "string",
-						"description": "The search query to match against entity names, types, and observation content",
-					},
-				},
-				"required": []string{"query"},
-			},
-		},
-		{
-			Name:        "open_nodes",
-			Description: "Open specific nodes in the knowledge graph by their names",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"names": map[string]interface{}{
-						"type": "array",
-						"items": map[string]interface{}{
-							"type": "string",
+							"description": "An array of observation contents associated with the entity",
 						},
-						"description": "An array of entity names to retrieve",
 					},
+					"required": []string{"name", "entityType", "observations"},
 				},
-				"required": []string{"names"},
 			},
 		},
-	}
-}
-
-// Tool handlers
-
-func (ms *Server) HandleCreateEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	// Ensure graph is loaded before accessing
-	if err := ms.ensureGraphLoaded(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
-	}
-
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
-
-	entitiesArg, ok := req.Arguments["entities"]
-	if !ok {
-		return mcp.NewToolError("entities parameter is required"), nil
-	}
-
-	entitiesSlice, ok := entitiesArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("entities must be an array"), nil
-	}
-
-	var createdEntities []string
-
-	for _, entityArg := range entitiesSlice {
-		entityMap, ok := entityArg.(map[string]interface{})
-		if !ok {
-			return mcp.NewToolError("each entity must be an object"), nil
+		"required": []string{"entities"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		name, ok := entityMap["name"].(string)
-		if !ok {
-			return mcp.NewToolError("entity name must be a string"), nil
-		}
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
 
-		entityType, ok := entityMap["entityType"].(string)
+		entitiesArg, ok := req.Arguments["entities"]
 		if !ok {
-			return mcp.NewToolError("entity entityType must be a string"), nil
+			return mcp.NewToolError("entities parameter is required"), nil
 		}
 
-		observationsArg, ok := entityMap["observations"]
+		entitiesSlice, ok := entitiesArg.([]interface{})
 		if !ok {
-			return mcp.NewToolError("entity observations is required"), nil
+			return mcp.NewToolError("entities must be an array"), nil
 		}
 
-		observationsSlice, ok := observationsArg.([]interface{})
-		if !ok {
-			return mcp.NewToolError("entity observations must be an array"), nil
-		}
+		var createdEntities []string
 
-		var observations []string
-		for _, obs := range observationsSlice {
-			obsStr, ok := obs.(string)
+		for _, entityArg := range entitiesSlice {
+			entityMap, ok := entityArg.(map[string]interface{})
 			if !ok {
-				return mcp.NewToolError("each observation must be a string"), nil
+				return mcp.NewToolError("each entity must be an object"), nil
 			}
-			observations = append(observations, obsStr)
-		}
 
-		// Create entity
-		entity := &Entity{
-			Name:         name,
-			EntityType:   entityType,
-			Observations: observations,
-		}
+			name, ok := entityMap["name"].(string)
+			if !ok {
+				return mcp.NewToolError("entity name must be a string"), nil
+			}
 
-		ms.graph.Entities[name] = entity
-		createdEntities = append(createdEntities, name)
-	}
+			entityType, ok := entityMap["entityType"].(string)
+			if !ok {
+				return mcp.NewToolError("entity type must be a string"), nil
+			}
 
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
+			observationsArg, ok := entityMap["observations"]
+			if !ok {
+				return mcp.NewToolError("entity observations are required"), nil
+			}
 
-	result := fmt.Sprintf("Successfully created %d entities: %s", len(createdEntities), strings.Join(createdEntities, ", "))
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+			observationsSlice, ok := observationsArg.([]interface{})
+			if !ok {
+				return mcp.NewToolError("entity observations must be an array"), nil
+			}
 
-func (ms *Server) HandleCreateRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
+			var observations []string
+			for _, obs := range observationsSlice {
+				obsStr, ok := obs.(string)
+				if !ok {
+					return mcp.NewToolError("each observation must be a string"), nil
+				}
+				observations = append(observations, obsStr)
+			}
 
-	relationsArg, ok := req.Arguments["relations"]
-	if !ok {
-		return mcp.NewToolError("relations parameter is required"), nil
-	}
+			memory.graph.Entities[name] = &Entity{
+				Name:         name,
+				EntityType:   entityType,
+				Observations: observations,
+			}
+			createdEntities = append(createdEntities, name)
+		}
 
-	relationsSlice, ok := relationsArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("relations must be an array"), nil
-	}
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
+		}
 
-	var createdRelations []string
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Created %d entities: %s", len(createdEntities), strings.Join(createdEntities, ", ")))), nil
+	}))
 
-	for _, relationArg := range relationsSlice {
-		relationMap, ok := relationArg.(map[string]interface{})
-		if !ok {
-			return mcp.NewToolError("each relation must be an object"), nil
+	// Add create_relations tool
+	builder.AddTool(mcp.NewTool("create_relations", "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"relations": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "object",
+					"properties": map[string]interface{}{
+						"from": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity where the relation starts",
+						},
+						"to": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity where the relation ends",
+						},
+						"relationType": map[string]interface{}{
+							"type":        "string",
+							"description": "The type of the relation",
+						},
+					},
+					"required": []string{"from", "to", "relationType"},
+				},
+			},
+		},
+		"required": []string{"relations"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		from, ok := relationMap["from"].(string)
-		if !ok {
-			return mcp.NewToolError("relation from must be a string"), nil
-		}
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
 
-		to, ok := relationMap["to"].(string)
+		relationsArg, ok := req.Arguments["relations"]
 		if !ok {
-			return mcp.NewToolError("relation to must be a string"), nil
+			return mcp.NewToolError("relations parameter is required"), nil
 		}
 
-		relationType, ok := relationMap["relationType"].(string)
+		relationsSlice, ok := relationsArg.([]interface{})
 		if !ok {
-			return mcp.NewToolError("relation relationType must be a string"), nil
+			return mcp.NewToolError("relations must be an array"), nil
 		}
 
-		// Check that entities exist
-		if _, exists := ms.graph.Entities[from]; !exists {
-			return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", from)), nil
-		}
-
-		if _, exists := ms.graph.Entities[to]; !exists {
-			return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", to)), nil
-		}
+		var createdRelations []string
 
-		// Create relation key
-		relationKey := fmt.Sprintf("%s-%s-%s", from, relationType, to)
+		for _, relationArg := range relationsSlice {
+			relationMap, ok := relationArg.(map[string]interface{})
+			if !ok {
+				return mcp.NewToolError("each relation must be an object"), nil
+			}
 
-		// Create relation
-		relation := Relation{
-			From:         from,
-			To:           to,
-			RelationType: relationType,
-		}
+			from, ok := relationMap["from"].(string)
+			if !ok {
+				return mcp.NewToolError("relation 'from' must be a string"), nil
+			}
 
-		ms.graph.Relations[relationKey] = relation
-		createdRelations = append(createdRelations, fmt.Sprintf("%s %s %s", from, relationType, to))
-	}
+			to, ok := relationMap["to"].(string)
+			if !ok {
+				return mcp.NewToolError("relation 'to' must be a string"), nil
+			}
 
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
+			relationType, ok := relationMap["relationType"].(string)
+			if !ok {
+				return mcp.NewToolError("relation type must be a string"), nil
+			}
 
-	result := fmt.Sprintf("Successfully created %d relations: %s", len(createdRelations), strings.Join(createdRelations, ", "))
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+			if _, exists := memory.graph.Entities[from]; !exists {
+				return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", from)), nil
+			}
 
-func (ms *Server) HandleAddObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
+			if _, exists := memory.graph.Entities[to]; !exists {
+				return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", to)), nil
+			}
 
-	observationsArg, ok := req.Arguments["observations"]
-	if !ok {
-		return mcp.NewToolError("observations parameter is required"), nil
-	}
+			relationKey := fmt.Sprintf("%s-%s-%s", from, relationType, to)
+			memory.graph.Relations[relationKey] = Relation{
+				From:         from,
+				To:           to,
+				RelationType: relationType,
+			}
+			createdRelations = append(createdRelations, fmt.Sprintf("%s %s %s", from, relationType, to))
+		}
 
-	observationsSlice, ok := observationsArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("observations must be an array"), nil
-	}
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
+		}
 
-	var addedCount int
-	var addedObservations []string
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Created %d relations: %s", len(createdRelations), strings.Join(createdRelations, ", ")))), nil
+	}))
 
-	for _, observationArg := range observationsSlice {
-		observationMap, ok := observationArg.(map[string]interface{})
-		if !ok {
-			return mcp.NewToolError("each observation must be an object"), nil
+	// Add add_observations tool
+	builder.AddTool(mcp.NewTool("add_observations", "Add new observations to existing entities in the knowledge graph", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"observations": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "object",
+					"properties": map[string]interface{}{
+						"entityName": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity to add the observations to",
+						},
+						"contents": map[string]interface{}{
+							"type": "array",
+							"items": map[string]interface{}{
+								"type": "string",
+							},
+							"description": "An array of observation contents to add",
+						},
+					},
+					"required": []string{"entityName", "contents"},
+				},
+			},
+		},
+		"required": []string{"observations"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		entityName, ok := observationMap["entityName"].(string)
-		if !ok {
-			return mcp.NewToolError("observation entityName must be a string"), nil
-		}
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
 
-		contentsArg, ok := observationMap["contents"]
+		observationsArg, ok := req.Arguments["observations"]
 		if !ok {
-			return mcp.NewToolError("observation contents is required"), nil
+			return mcp.NewToolError("observations parameter is required"), nil
 		}
 
-		contentsSlice, ok := contentsArg.([]interface{})
+		observationsSlice, ok := observationsArg.([]interface{})
 		if !ok {
-			return mcp.NewToolError("observation contents must be an array"), nil
+			return mcp.NewToolError("observations must be an array"), nil
 		}
 
-		// Check that entity exists
-		entity, exists := ms.graph.Entities[entityName]
-		if !exists {
-			return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", entityName)), nil
-		}
+		var addedCount int
 
-		// Add observations
-		for _, content := range contentsSlice {
-			contentStr, ok := content.(string)
+		for _, obsArg := range observationsSlice {
+			obsMap, ok := obsArg.(map[string]interface{})
 			if !ok {
-				return mcp.NewToolError("each observation content must be a string"), nil
+				return mcp.NewToolError("each observation must be an object"), nil
 			}
-			entity.Observations = append(entity.Observations, contentStr)
-			addedObservations = append(addedObservations, contentStr)
-			addedCount++
-		}
-	}
 
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
+			entityName, ok := obsMap["entityName"].(string)
+			if !ok {
+				return mcp.NewToolError("entity name must be a string"), nil
+			}
 
-	result := fmt.Sprintf("Successfully added %d observations: %s", addedCount, strings.Join(addedObservations, ", "))
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+			contentsArg, ok := obsMap["contents"]
+			if !ok {
+				return mcp.NewToolError("observation contents are required"), nil
+			}
 
-func (ms *Server) HandleDeleteEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
+			contentsSlice, ok := contentsArg.([]interface{})
+			if !ok {
+				return mcp.NewToolError("observation contents must be an array"), nil
+			}
 
-	entityNamesArg, ok := req.Arguments["entityNames"]
-	if !ok {
-		return mcp.NewToolError("entityNames parameter is required"), nil
-	}
+			entity, exists := memory.graph.Entities[entityName]
+			if !exists {
+				return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", entityName)), nil
+			}
 
-	entityNamesSlice, ok := entityNamesArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("entityNames must be an array"), nil
-	}
+			for _, content := range contentsSlice {
+				contentStr, ok := content.(string)
+				if !ok {
+					return mcp.NewToolError("each observation content must be a string"), nil
+				}
+				entity.Observations = append(entity.Observations, contentStr)
+				addedCount++
+			}
+		}
 
-	var deletedEntities []string
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
+		}
 
-	for _, entityNameArg := range entityNamesSlice {
-		entityName, ok := entityNameArg.(string)
-		if !ok {
-			return mcp.NewToolError("each entity name must be a string"), nil
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Added %d observations", addedCount))), nil
+	}))
+
+	// Add delete_entities tool
+	builder.AddTool(mcp.NewTool("delete_entities", "Delete multiple entities and their associated relations from the knowledge graph", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"entityNames": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "string",
+				},
+				"description": "An array of entity names to delete",
+			},
+		},
+		"required": []string{"entityNames"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		// Delete entity
-		if _, exists := ms.graph.Entities[entityName]; exists {
-			delete(ms.graph.Entities, entityName)
-			deletedEntities = append(deletedEntities, entityName)
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
 
-			// Delete related relations
-			for key, relation := range ms.graph.Relations {
-				if relation.From == entityName || relation.To == entityName {
-					delete(ms.graph.Relations, key)
-				}
-			}
+		entityNamesArg, ok := req.Arguments["entityNames"]
+		if !ok {
+			return mcp.NewToolError("entityNames parameter is required"), nil
 		}
-	}
 
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
+		entityNamesSlice, ok := entityNamesArg.([]interface{})
+		if !ok {
+			return mcp.NewToolError("entityNames must be an array"), nil
+		}
 
-	result := fmt.Sprintf("Successfully deleted %d entities: %s", len(deletedEntities), strings.Join(deletedEntities, ", "))
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+		var deletedEntities []string
+		var deletedRelations int
 
-func (ms *Server) HandleDeleteObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
+		for _, nameArg := range entityNamesSlice {
+			name, ok := nameArg.(string)
+			if !ok {
+				return mcp.NewToolError("each entity name must be a string"), nil
+			}
 
-	deletionsArg, ok := req.Arguments["deletions"]
-	if !ok {
-		return mcp.NewToolError("deletions parameter is required"), nil
-	}
+			if _, exists := memory.graph.Entities[name]; !exists {
+				continue
+			}
 
-	deletionsSlice, ok := deletionsArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("deletions must be an array"), nil
-	}
+			delete(memory.graph.Entities, name)
+			deletedEntities = append(deletedEntities, name)
 
-	var deletedCount int
+			for key, relation := range memory.graph.Relations {
+				if relation.From == name || relation.To == name {
+					delete(memory.graph.Relations, key)
+					deletedRelations++
+				}
+			}
+		}
 
-	for _, deletionArg := range deletionsSlice {
-		deletionMap, ok := deletionArg.(map[string]interface{})
-		if !ok {
-			return mcp.NewToolError("each deletion must be an object"), nil
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
 		}
 
-		entityName, ok := deletionMap["entityName"].(string)
-		if !ok {
-			return mcp.NewToolError("deletion entityName must be a string"), nil
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Deleted %d entities and %d relations", len(deletedEntities), deletedRelations))), nil
+	}))
+
+	// Add delete_observations tool
+	builder.AddTool(mcp.NewTool("delete_observations", "Delete specific observations from entities in the knowledge graph", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"deletions": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "object",
+					"properties": map[string]interface{}{
+						"entityName": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity containing the observations",
+						},
+						"observations": map[string]interface{}{
+							"type": "array",
+							"items": map[string]interface{}{
+								"type": "string",
+							},
+							"description": "An array of observations to delete",
+						},
+					},
+					"required": []string{"entityName", "observations"},
+				},
+			},
+		},
+		"required": []string{"deletions"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		observationsArg, ok := deletionMap["observations"]
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
+
+		deletionsArg, ok := req.Arguments["deletions"]
 		if !ok {
-			return mcp.NewToolError("deletion observations is required"), nil
+			return mcp.NewToolError("deletions parameter is required"), nil
 		}
 
-		observationsSlice, ok := observationsArg.([]interface{})
+		deletionsSlice, ok := deletionsArg.([]interface{})
 		if !ok {
-			return mcp.NewToolError("deletion observations must be an array"), nil
+			return mcp.NewToolError("deletions must be an array"), nil
 		}
 
-		// Check that entity exists
-		entity, exists := ms.graph.Entities[entityName]
-		if !exists {
-			return mcp.NewToolError(fmt.Sprintf("entity '%s' does not exist", entityName)), nil
-		}
+		var deletedCount int
 
-		// Delete observations
-		for _, obsArg := range observationsSlice {
-			obsStr, ok := obsArg.(string)
+		for _, delArg := range deletionsSlice {
+			delMap, ok := delArg.(map[string]interface{})
 			if !ok {
-				return mcp.NewToolError("each observation must be a string"), nil
+				return mcp.NewToolError("each deletion must be an object"), nil
 			}
 
-			// Remove observation from entity
-			var newObservations []string
-			for _, existingObs := range entity.Observations {
-				if existingObs != obsStr {
-					newObservations = append(newObservations, existingObs)
-				} else {
-					deletedCount++
-				}
+			entityName, ok := delMap["entityName"].(string)
+			if !ok {
+				return mcp.NewToolError("entity name must be a string"), nil
 			}
-			entity.Observations = newObservations
-		}
-	}
-
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
 
-	result := fmt.Sprintf("Successfully deleted %d observations", deletedCount)
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+			observationsArg, ok := delMap["observations"]
+			if !ok {
+				return mcp.NewToolError("observations are required"), nil
+			}
 
-func (ms *Server) HandleDeleteRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.Lock()
-	defer ms.mu.Unlock()
+			observationsSlice, ok := observationsArg.([]interface{})
+			if !ok {
+				return mcp.NewToolError("observations must be an array"), nil
+			}
 
-	relationsArg, ok := req.Arguments["relations"]
-	if !ok {
-		return mcp.NewToolError("relations parameter is required"), nil
-	}
+			entity, exists := memory.graph.Entities[entityName]
+			if !exists {
+				continue
+			}
 
-	relationsSlice, ok := relationsArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("relations must be an array"), nil
-	}
+			for _, obsArg := range observationsSlice {
+				obsStr, ok := obsArg.(string)
+				if !ok {
+					continue
+				}
 
-	var deletedRelations []string
+				for i, existingObs := range entity.Observations {
+					if existingObs == obsStr {
+						entity.Observations = append(entity.Observations[:i], entity.Observations[i+1:]...)
+						deletedCount++
+						break
+					}
+				}
+			}
+		}
 
-	for _, relationArg := range relationsSlice {
-		relationMap, ok := relationArg.(map[string]interface{})
-		if !ok {
-			return mcp.NewToolError("each relation must be an object"), nil
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
 		}
 
-		from, ok := relationMap["from"].(string)
-		if !ok {
-			return mcp.NewToolError("relation from must be a string"), nil
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Deleted %d observations", deletedCount))), nil
+	}))
+
+	// Add delete_relations tool
+	builder.AddTool(mcp.NewTool("delete_relations", "Delete multiple relations from the knowledge graph", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"relations": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "object",
+					"properties": map[string]interface{}{
+						"from": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity where the relation starts",
+						},
+						"to": map[string]interface{}{
+							"type":        "string",
+							"description": "The name of the entity where the relation ends",
+						},
+						"relationType": map[string]interface{}{
+							"type":        "string",
+							"description": "The type of the relation",
+						},
+					},
+					"required": []string{"from", "to", "relationType"},
+				},
+			},
+		},
+		"required": []string{"relations"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		to, ok := relationMap["to"].(string)
+		memory.mu.Lock()
+		defer memory.mu.Unlock()
+
+		relationsArg, ok := req.Arguments["relations"]
 		if !ok {
-			return mcp.NewToolError("relation to must be a string"), nil
+			return mcp.NewToolError("relations parameter is required"), nil
 		}
 
-		relationType, ok := relationMap["relationType"].(string)
+		relationsSlice, ok := relationsArg.([]interface{})
 		if !ok {
-			return mcp.NewToolError("relation relationType must be a string"), nil
+			return mcp.NewToolError("relations must be an array"), nil
 		}
 
-		// Create relation key
-		relationKey := fmt.Sprintf("%s-%s-%s", from, relationType, to)
+		var deletedCount int
 
-		// Delete relation
-		if _, exists := ms.graph.Relations[relationKey]; exists {
-			delete(ms.graph.Relations, relationKey)
-			deletedRelations = append(deletedRelations, fmt.Sprintf("%s %s %s", from, relationType, to))
-		}
-	}
-
-	// Save to file
-	if err := ms.saveGraph(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
-	}
+		for _, relationArg := range relationsSlice {
+			relationMap, ok := relationArg.(map[string]interface{})
+			if !ok {
+				continue
+			}
 
-	result := fmt.Sprintf("Successfully deleted %d relations: %s", len(deletedRelations), strings.Join(deletedRelations, ", "))
-	return mcp.NewToolResult(mcp.NewTextContent(result)), nil
-}
+			from, ok := relationMap["from"].(string)
+			if !ok {
+				continue
+			}
 
-func (ms *Server) HandleReadGraph(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	// Ensure graph is loaded before accessing
-	if err := ms.ensureGraphLoaded(); err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
-	}
+			to, ok := relationMap["to"].(string)
+			if !ok {
+				continue
+			}
 
-	ms.mu.RLock()
-	defer ms.mu.RUnlock()
+			relationType, ok := relationMap["relationType"].(string)
+			if !ok {
+				continue
+			}
 
-	// Return the entire graph as JSON
-	graphJSON, err := json.MarshalIndent(ms.graph, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal graph: %v", err)), nil
-	}
+			relationKey := fmt.Sprintf("%s-%s-%s", from, relationType, to)
+			if _, exists := memory.graph.Relations[relationKey]; exists {
+				delete(memory.graph.Relations, relationKey)
+				deletedCount++
+			}
+		}
 
-	return mcp.NewToolResult(mcp.NewTextContent(string(graphJSON))), nil
-}
+		if err := memory.saveGraph(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to save graph: %v", err)), nil
+		}
 
-func (ms *Server) HandleSearchNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.RLock()
-	defer ms.mu.RUnlock()
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Deleted %d relations", deletedCount))), nil
+	}))
 
-	query, ok := req.Arguments["query"].(string)
-	if !ok {
-		return mcp.NewToolError("query parameter is required and must be a string"), nil
-	}
+	// Add read_graph tool
+	builder.AddTool(mcp.NewTool("read_graph", "Read the entire knowledge graph", map[string]interface{}{
+		"type":       "object",
+		"properties": map[string]interface{}{},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
+		}
 
-	query = strings.ToLower(query)
-	var matchedEntities []*Entity
+		memory.mu.RLock()
+		defer memory.mu.RUnlock()
 
-	// Search entities
-	for _, entity := range ms.graph.Entities {
-		// Check name
-		if strings.Contains(strings.ToLower(entity.Name), query) {
-			matchedEntities = append(matchedEntities, entity)
-			continue
+		graphData, err := json.MarshalIndent(memory.graph, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to serialize graph: %v", err)), nil
 		}
 
-		// Check type
-		if strings.Contains(strings.ToLower(entity.EntityType), query) {
-			matchedEntities = append(matchedEntities, entity)
-			continue
+		return mcp.NewToolResult(mcp.NewTextContent(string(graphData))), nil
+	}))
+
+	// Add search_nodes tool
+	builder.AddTool(mcp.NewTool("search_nodes", "Search for nodes in the knowledge graph based on a query", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"query": map[string]interface{}{
+				"type":        "string",
+				"description": "The search query to match against entity names, types, and observation content",
+			},
+		},
+		"required": []string{"query"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
 		}
 
-		// Check observations
-		for _, obs := range entity.Observations {
-			if strings.Contains(strings.ToLower(obs), query) {
-				matchedEntities = append(matchedEntities, entity)
-				break
-			}
+		memory.mu.RLock()
+		defer memory.mu.RUnlock()
+
+		query, ok := req.Arguments["query"].(string)
+		if !ok {
+			return mcp.NewToolError("query parameter is required"), nil
 		}
-	}
 
-	// Return matched entities as JSON
-	searchResult := map[string]interface{}{
-		"query":    query,
-		"entities": matchedEntities,
-	}
+		query = strings.ToLower(query)
+		var matchedEntities []*Entity
 
-	resultJSON, err := json.MarshalIndent(searchResult, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal search result: %v", err)), nil
-	}
+		for _, entity := range memory.graph.Entities {
+			if strings.Contains(strings.ToLower(entity.Name), query) ||
+				strings.Contains(strings.ToLower(entity.EntityType), query) {
+				matchedEntities = append(matchedEntities, entity)
+				continue
+			}
 
-	return mcp.NewToolResult(mcp.NewTextContent(string(resultJSON))), nil
-}
+			for _, observation := range entity.Observations {
+				if strings.Contains(strings.ToLower(observation), query) {
+					matchedEntities = append(matchedEntities, entity)
+					break
+				}
+			}
+		}
 
-func (ms *Server) HandleOpenNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	ms.mu.RLock()
-	defer ms.mu.RUnlock()
+		resultData, err := json.MarshalIndent(matchedEntities, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to serialize results: %v", err)), nil
+		}
 
-	namesArg, ok := req.Arguments["names"]
-	if !ok {
-		return mcp.NewToolError("names parameter is required"), nil
-	}
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Found %d matching entities:\n%s", len(matchedEntities), string(resultData)))), nil
+	}))
 
-	namesSlice, ok := namesArg.([]interface{})
-	if !ok {
-		return mcp.NewToolError("names must be an array"), nil
-	}
+	// Add open_nodes tool
+	builder.AddTool(mcp.NewTool("open_nodes", "Open specific nodes in the knowledge graph by their names", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"names": map[string]interface{}{
+				"type": "array",
+				"items": map[string]interface{}{
+					"type": "string",
+				},
+				"description": "An array of entity names to retrieve",
+			},
+		},
+		"required": []string{"names"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		if err := memory.ensureGraphLoaded(); err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to load graph: %v", err)), nil
+		}
 
-	var foundEntities []*Entity
+		memory.mu.RLock()
+		defer memory.mu.RUnlock()
 
-	for _, nameArg := range namesSlice {
-		name, ok := nameArg.(string)
+		namesArg, ok := req.Arguments["names"]
 		if !ok {
-			return mcp.NewToolError("each name must be a string"), nil
+			return mcp.NewToolError("names parameter is required"), nil
 		}
 
-		if entity, exists := ms.graph.Entities[name]; exists {
-			foundEntities = append(foundEntities, entity)
+		namesSlice, ok := namesArg.([]interface{})
+		if !ok {
+			return mcp.NewToolError("names must be an array"), nil
 		}
-	}
-
-	// Return found entities as JSON
-	openResult := map[string]interface{}{
-		"entities": foundEntities,
-	}
 
-	resultJSON, err := json.MarshalIndent(openResult, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal open result: %v", err)), nil
-	}
-
-	return mcp.NewToolResult(mcp.NewTextContent(string(resultJSON))), nil
-}
+		var foundEntities []*Entity
 
-// HandleMemoryResource handles memory:// resource requests
-func (ms *Server) HandleMemoryResource(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
-	ms.mu.RLock()
-	defer ms.mu.RUnlock()
+		for _, nameArg := range namesSlice {
+			name, ok := nameArg.(string)
+			if !ok {
+				continue
+			}
 
-	// Parse memory:// URI: memory://entity/name or memory://relations/all
-	if !strings.HasPrefix(req.URI, "memory://") {
-		return mcp.ReadResourceResult{}, fmt.Errorf("invalid memory URI: %s", req.URI)
-	}
+			if entity, exists := memory.graph.Entities[name]; exists {
+				foundEntities = append(foundEntities, entity)
+			}
+		}
 
-	uriPath := req.URI[9:] // Remove "memory://" prefix
-	parts := strings.Split(uriPath, "/")
+		resultData, err := json.MarshalIndent(foundEntities, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to serialize results: %v", err)), nil
+		}
 
-	if len(parts) < 2 {
-		return mcp.ReadResourceResult{}, fmt.Errorf("invalid memory URI format: %s", req.URI)
-	}
+		return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Found %d entities:\n%s", len(foundEntities), string(resultData)))), nil
+	}))
 
-	resourceType := parts[0]
-	resourcePath := strings.Join(parts[1:], "/")
+	// Add knowledge-query prompt
+	builder.AddPrompt(mcp.NewPrompt("knowledge-query", "Prompt for querying and exploring the knowledge graph", []mcp.PromptArgument{
+		{
+			Name:        "query",
+			Description: "What you want to search for or ask about in the knowledge graph",
+			Required:    true,
+		},
+		{
+			Name:        "context",
+			Description: "Additional context about your question (optional)",
+			Required:    false,
+		},
+	}, func(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+		query, hasQuery := req.Arguments["query"].(string)
+		context, hasContext := req.Arguments["context"].(string)
 
-	switch resourceType {
-	case "entity":
-		return ms.handleEntityResource(resourcePath)
-	case "relations":
-		return ms.handleRelationsResource(resourcePath)
-	default:
-		return mcp.ReadResourceResult{}, fmt.Errorf("unknown memory resource type: %s", resourceType)
-	}
-}
+		if !hasQuery || query == "" {
+			return mcp.GetPromptResult{}, fmt.Errorf("query argument is required")
+		}
 
-// handleEntityResource handles memory://entity/name resources
-func (ms *Server) handleEntityResource(entityName string) (mcp.ReadResourceResult, error) {
-	entity, exists := ms.graph.Entities[entityName]
-	if !exists {
-		return mcp.ReadResourceResult{}, fmt.Errorf("entity not found: %s", entityName)
-	}
+		var messages []mcp.PromptMessage
 
-	// Create detailed entity information including related relations
-	var relatedRelations []Relation
-	for _, relation := range ms.graph.Relations {
-		if relation.From == entityName || relation.To == entityName {
-			relatedRelations = append(relatedRelations, relation)
+		userContent := fmt.Sprintf(`I want to search the knowledge graph for: %s`, query)
+		if hasContext && context != "" {
+			userContent += fmt.Sprintf("\n\nAdditional context: %s", context)
 		}
-	}
 
-	entityInfo := map[string]interface{}{
-		"entity":    entity,
-		"relations": relatedRelations,
-	}
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "user",
+			Content: mcp.NewTextContent(userContent),
+		})
 
-	jsonData, err := json.MarshalIndent(entityInfo, "", "  ")
-	if err != nil {
-		return mcp.ReadResourceResult{}, fmt.Errorf("failed to marshal entity data: %v", err)
-	}
+		assistantContent := fmt.Sprintf(`I'll help you search the knowledge graph for "%s". Here are some strategies you can use:
 
-	return mcp.ReadResourceResult{
-		Contents: []mcp.Content{
-			mcp.NewTextContent(string(jsonData)),
-		},
-	}, nil
-}
+**Search Commands:**
+- Use "search_nodes" tool with query: "%s"
+- Use "read_graph" tool to see the entire knowledge structure
+- Use "open_nodes" tool if you know specific entity names
 
-// handleRelationsResource handles memory://relations/all resources
-func (ms *Server) handleRelationsResource(resourcePath string) (mcp.ReadResourceResult, error) {
-	if resourcePath != "all" {
-		return mcp.ReadResourceResult{}, fmt.Errorf("invalid relations resource path: %s", resourcePath)
-	}
+**What to look for:**
+- Entities with names containing "%s"
+- Entity types that match your query
+- Observations that mention "%s"
+- Related entities through relationships
 
-	relationsInfo := map[string]interface{}{
-		"total_relations": len(ms.graph.Relations),
-		"relations":       ms.graph.Relations,
-	}
+**Next steps:**
+1. Start with a broad search using search_nodes
+2. Examine the results to find relevant entities
+3. Use open_nodes to get detailed information about specific entities
+4. Look at relationships to find connected information
 
-	jsonData, err := json.MarshalIndent(relationsInfo, "", "  ")
-	if err != nil {
-		return mcp.ReadResourceResult{}, fmt.Errorf("failed to marshal relations data: %v", err)
-	}
+Would you like me to search for this information in the knowledge graph?`, query, query, query, query)
 
-	return mcp.ReadResourceResult{
-		Contents: []mcp.Content{
-			mcp.NewTextContent(string(jsonData)),
-		},
-	}, nil
-}
+		messages = append(messages, mcp.PromptMessage{
+			Role:    "assistant",
+			Content: mcp.NewTextContent(assistantContent),
+		})
 
-// Prompt handlers
+		description := fmt.Sprintf("Knowledge graph search guidance for: %s", query)
 
-func (ms *Server) HandleKnowledgeQueryPrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
-	query, hasQuery := req.Arguments["query"].(string)
-	context, hasContext := req.Arguments["context"].(string)
+		return mcp.GetPromptResult{
+			Description: description,
+			Messages:    messages,
+		}, nil
+	}))
 
-	if !hasQuery || query == "" {
-		return mcp.GetPromptResult{}, fmt.Errorf("query argument is required")
-	}
+	// Add memory:// pattern resource
+	builder.AddResource(mcp.NewResource(
+		"memory://graph",
+		"Knowledge Graph",
+		"application/json",
+		func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
+			if err := memory.ensureGraphLoaded(); err != nil {
+				return mcp.ReadResourceResult{}, fmt.Errorf("failed to load graph: %v", err)
+			}
 
-	// Create the prompt messages
-	var messages []mcp.PromptMessage
+			memory.mu.RLock()
+			defer memory.mu.RUnlock()
 
-	// User message with the query and optional context
-	userContent := fmt.Sprintf("I want to query the knowledge graph: %s", query)
-	if hasContext && context != "" {
-		userContent += fmt.Sprintf("\n\nAdditional context: %s", context)
-	}
+			graphData, err := json.MarshalIndent(memory.graph, "", "  ")
+			if err != nil {
+				return mcp.ReadResourceResult{}, fmt.Errorf("failed to serialize graph: %v", err)
+			}
 
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "user",
-		Content: mcp.NewTextContent(userContent),
-	})
+			return mcp.ReadResourceResult{
+				Contents: []mcp.Content{
+					mcp.NewTextContent(string(graphData)),
+				},
+			}, nil
+		},
+	))
 
-	// Assistant message with guidance on using the memory tools
-	assistantContent := fmt.Sprintf(`I'll help you explore the knowledge graph to answer your query: "%s"
+	// Add knowledge graph root
+	rootName := fmt.Sprintf("Knowledge Graph (%d entities, %d relations)", len(memory.graph.Entities), len(memory.graph.Relations))
+	builder.AddRoot(mcp.NewRoot("memory://graph", rootName))
 
-Let me start by searching the knowledge graph for relevant information:`, query)
+	return builder.Build()
+}
 
-	if hasContext && context != "" {
-		assistantContent += fmt.Sprintf("\n\nWith context: %s", context)
-	}
+// Helper methods for MemoryOperations
 
-	messages = append(messages, mcp.PromptMessage{
-		Role:    "assistant",
-		Content: mcp.NewTextContent(assistantContent),
-	})
+func (memory *MemoryOperations) ensureGraphLoaded() error {
+	memory.mu.Lock()
+	defer memory.mu.Unlock()
 
-	description := fmt.Sprintf("Knowledge graph exploration for: %s", query)
-	if hasContext && context != "" {
-		description += fmt.Sprintf(" (%s)", context)
+	if !memory.loaded {
+		memory.loaded = true
+		return memory.loadGraphInternal()
 	}
-
-	return mcp.GetPromptResult{
-		Description: description,
-		Messages:    messages,
-	}, nil
+	return nil
 }
 
-// Helper methods
-
-func (ms *Server) loadGraphInternal() error {
-	if _, err := os.Stat(ms.memoryFile); os.IsNotExist(err) {
-		// File doesn't exist, start with empty graph
+func (memory *MemoryOperations) loadGraphInternal() error {
+	if memory.memoryFile == "" {
 		return nil
 	}
 
-	data, err := os.ReadFile(ms.memoryFile)
+	data, err := os.ReadFile(memory.memoryFile)
+	if os.IsNotExist(err) {
+		return nil
+	}
 	if err != nil {
-		return err
+		return fmt.Errorf("failed to read memory file: %v", err)
 	}
 
 	if len(data) == 0 {
-		// Empty file, start with empty graph
 		return nil
 	}
 
-	return json.Unmarshal(data, ms.graph)
+	var loadedGraph KnowledgeGraph
+	if err := json.Unmarshal(data, &loadedGraph); err != nil {
+		return fmt.Errorf("failed to parse memory file: %v", err)
+	}
+
+	if loadedGraph.Entities != nil {
+		memory.graph.Entities = loadedGraph.Entities
+	}
+	if loadedGraph.Relations != nil {
+		memory.graph.Relations = loadedGraph.Relations
+	}
+
+	return nil
 }
 
-func (ms *Server) saveGraph() error {
-	data, err := json.MarshalIndent(ms.graph, "", "  ")
-	if err != nil {
-		return err
+func (memory *MemoryOperations) saveGraph() error {
+	if memory.memoryFile == "" {
+		return nil
 	}
 
-	err = os.WriteFile(ms.memoryFile, data, 0644)
+	data, err := json.MarshalIndent(memory.graph, "", "  ")
 	if err != nil {
-		return err
+		return fmt.Errorf("failed to serialize graph: %v", err)
+	}
+
+	if err := os.WriteFile(memory.memoryFile, data, 0644); err != nil {
+		return fmt.Errorf("failed to write memory file: %v", err)
 	}
 
-	// No need to re-register resources since they're discovered dynamically
 	return nil
-}
+}
\ No newline at end of file
pkg/thinking/server.go
@@ -12,9 +12,8 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Sequential Thinking MCP server
-type Server struct {
-	*mcp.Server
+// ThinkingOperations provides thinking session management operations
+type ThinkingOperations struct {
 	sessions     map[string]*ThinkingSession
 	branches     map[string]*Branch
 	mu           sync.RWMutex
@@ -68,17 +67,9 @@ type ThinkingResponse struct {
 	BranchContext      string   `json:"branch_context,omitempty"`
 }
 
-// New creates a new Sequential Thinking MCP server
-func New() *Server {
-	return NewWithPersistence("")
-}
-
-// NewWithPersistence creates a new Sequential Thinking MCP server with optional persistence
-func NewWithPersistence(persistFile string) *Server {
-	server := mcp.NewServer("mcp-sequential-thinking", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
-
-	thinkingServer := &Server{
-		Server:      server,
+// NewThinkingOperations creates a new ThinkingOperations helper
+func NewThinkingOperations(persistFile string) *ThinkingOperations {
+	thinking := &ThinkingOperations{
 		sessions:    make(map[string]*ThinkingSession),
 		branches:    make(map[string]*Branch),
 		persistFile: persistFile,
@@ -86,167 +77,145 @@ func NewWithPersistence(persistFile string) *Server {
 
 	// Load existing sessions if persistence file is provided
 	if persistFile != "" {
-		thinkingServer.loadSessions()
+		thinking.loadSessions()
 	}
 
-	// Register all sequential thinking tools
-	thinkingServer.registerTools()
-
-	return thinkingServer
+	return thinking
 }
 
-// registerTools registers all Sequential Thinking tools with the server
-func (sts *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := sts.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "sequentialthinking":
-			handler = sts.HandleSequentialThinking
-		case "get_session_history":
-			handler = sts.HandleGetSessionHistory
-		case "list_sessions":
-			handler = sts.HandleListSessions
-		case "get_branch_history":
-			handler = sts.HandleGetBranchHistory
-		case "clear_session":
-			handler = sts.HandleClearSession
-		default:
-			continue
-		}
-		sts.RegisterToolWithDefinition(tool, handler)
-	}
+// New creates a new Sequential Thinking MCP server
+func New() *mcp.Server {
+	return NewWithPersistence("")
 }
 
-// ListTools returns all available Sequential Thinking tools
-func (sts *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "sequentialthinking",
-			Description: "A detailed tool for dynamic and reflective problem-solving through thoughts. This tool helps analyze problems through a flexible thinking process that can adapt and evolve. Each thought can build on, question, or revise previous insights as understanding deepens.",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"thought": map[string]interface{}{
-						"type":        "string",
-						"description": "Your current thinking step",
-					},
-					"nextThoughtNeeded": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Whether another thought step is needed",
-					},
-					"thoughtNumber": map[string]interface{}{
-						"type":        "integer",
-						"minimum":     1,
-						"description": "Current thought number",
-					},
-					"totalThoughts": map[string]interface{}{
-						"type":        "integer",
-						"minimum":     1,
-						"description": "Estimated total thoughts needed",
-					},
-					"isRevision": map[string]interface{}{
-						"type":        "boolean",
-						"description": "Whether this revises previous thinking",
-						"default":     false,
-					},
-					"revisesThought": map[string]interface{}{
-						"type":        "integer",
-						"minimum":     1,
-						"description": "Which thought is being reconsidered",
-					},
-					"branchFromThought": map[string]interface{}{
-						"type":        "integer",
-						"minimum":     1,
-						"description": "Branching point thought number",
-					},
-					"branchId": map[string]interface{}{
-						"type":        "string",
-						"description": "Branch identifier",
-					},
-					"needsMoreThoughts": map[string]interface{}{
-						"type":        "boolean",
-						"description": "If more thoughts are needed",
-						"default":     false,
-					},
-					"sessionId": map[string]interface{}{
-						"type":        "string",
-						"description": "Session ID for thought continuity (optional, auto-generated if not provided)",
-					},
-				},
-				"required": []string{"thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"},
+// NewWithPersistence creates a new Sequential Thinking MCP server with optional persistence
+func NewWithPersistence(persistFile string) *mcp.Server {
+	thinking := NewThinkingOperations(persistFile)
+	builder := mcp.NewServerBuilder("mcp-sequential-thinking", "1.0.0")
+
+	// Add sequentialthinking tool
+	builder.AddTool(mcp.NewTool("sequentialthinking", "A detailed tool for dynamic and reflective problem-solving through thoughts. This tool helps analyze problems through a flexible thinking process that can adapt and evolve. Each thought can build on, question, or revise previous insights as understanding deepens.", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"thought": map[string]interface{}{
+				"type":        "string",
+				"description": "Your current thinking step",
 			},
-		},
-		{
-			Name:        "get_session_history",
-			Description: "Get the complete thought history for a thinking session",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"sessionId": map[string]interface{}{
-						"type":        "string",
-						"description": "Session ID to get history for",
-					},
-				},
-				"required": []string{"sessionId"},
+			"nextThoughtNeeded": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Whether another thought step is needed",
+			},
+			"thoughtNumber": map[string]interface{}{
+				"type":        "integer",
+				"minimum":     1,
+				"description": "Current thought number",
+			},
+			"totalThoughts": map[string]interface{}{
+				"type":        "integer",
+				"minimum":     1,
+				"description": "Estimated total thoughts needed",
+			},
+			"isRevision": map[string]interface{}{
+				"type":        "boolean",
+				"description": "Whether this revises previous thinking",
+				"default":     false,
+			},
+			"revisesThought": map[string]interface{}{
+				"type":        "integer",
+				"minimum":     1,
+				"description": "Which thought is being reconsidered",
+			},
+			"branchFromThought": map[string]interface{}{
+				"type":        "integer",
+				"minimum":     1,
+				"description": "Branching point thought number",
+			},
+			"branchId": map[string]interface{}{
+				"type":        "string",
+				"description": "Branch identifier",
+			},
+			"needsMoreThoughts": map[string]interface{}{
+				"type":        "boolean",
+				"description": "If more thoughts are needed",
+				"default":     false,
+			},
+			"sessionId": map[string]interface{}{
+				"type":        "string",
+				"description": "Session ID for thought continuity (optional, auto-generated if not provided)",
 			},
 		},
-		{
-			Name:        "list_sessions",
-			Description: "List all active thinking sessions",
-			InputSchema: map[string]interface{}{
-				"type":       "object",
-				"properties": map[string]interface{}{},
+		"required": []string{"thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return thinking.handleSequentialThinking(req)
+	}))
+
+	// Add get_session_history tool
+	builder.AddTool(mcp.NewTool("get_session_history", "Get the complete thought history for a thinking session", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"sessionId": map[string]interface{}{
+				"type":        "string",
+				"description": "Session ID to get history for",
 			},
 		},
-		{
-			Name:        "get_branch_history",
-			Description: "Get the thought history for a specific reasoning branch",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"branchId": map[string]interface{}{
-						"type":        "string",
-						"description": "Branch ID to get history for",
-					},
-				},
-				"required": []string{"branchId"},
+		"required": []string{"sessionId"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return thinking.handleGetSessionHistory(req)
+	}))
+
+	// Add list_sessions tool
+	builder.AddTool(mcp.NewTool("list_sessions", "List all active thinking sessions", map[string]interface{}{
+		"type":       "object",
+		"properties": map[string]interface{}{},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return thinking.handleListSessions(req)
+	}))
+
+	// Add get_branch_history tool
+	builder.AddTool(mcp.NewTool("get_branch_history", "Get the thought history for a specific reasoning branch", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"branchId": map[string]interface{}{
+				"type":        "string",
+				"description": "Branch ID to get history for",
 			},
 		},
-		{
-			Name:        "clear_session",
-			Description: "Clear a thinking session and all its branches",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"sessionId": map[string]interface{}{
-						"type":        "string",
-						"description": "Session ID to clear",
-					},
-				},
-				"required": []string{"sessionId"},
+		"required": []string{"branchId"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return thinking.handleGetBranchHistory(req)
+	}))
+
+	// Add clear_session tool
+	builder.AddTool(mcp.NewTool("clear_session", "Clear a thinking session and all its branches", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"sessionId": map[string]interface{}{
+				"type":        "string",
+				"description": "Session ID to clear",
 			},
 		},
-	}
+		"required": []string{"sessionId"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		return thinking.handleClearSession(req)
+	}))
+
+	return builder.Build()
 }
 
-// Tool handlers
+// Helper methods for ThinkingOperations
 
-func (sts *Server) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (thinking *ThinkingOperations) handleSequentialThinking(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	// Parse and validate input parameters
-	params, err := sts.parseThinkingParameters(req.Arguments)
+	params, err := thinking.parseThinkingParameters(req.Arguments)
 	if err != nil {
 		return mcp.NewToolError(err.Error()), nil
 	}
 
-	sts.mu.Lock()
-	defer sts.mu.Unlock()
+	thinking.mu.Lock()
+	defer thinking.mu.Unlock()
 
 	// Get or create session
-	session := sts.getOrCreateSession(params.SessionID)
+	session := thinking.getOrCreateSession(params.SessionID)
 	
 	// Create thought object
 	currentThought := Thought{
@@ -262,7 +231,7 @@ func (sts *Server) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallTo
 	// Handle branching
 	var activeBranch *Branch
 	if params.BranchFromThought != nil && params.BranchID != "" {
-		activeBranch = sts.getOrCreateBranch(session.ID, params.BranchID, *params.BranchFromThought)
+		activeBranch = thinking.getOrCreateBranch(session.ID, params.BranchID, *params.BranchFromThought)
 		activeBranch.Thoughts = append(activeBranch.Thoughts, currentThought)
 		activeBranch.LastActivity = time.Now()
 	} else {
@@ -276,7 +245,7 @@ func (sts *Server) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallTo
 	session.LastActivity = time.Now()
 
 	// Save to persistence if configured
-	sts.saveSessions()
+	thinking.saveSessions()
 
 	// Determine status
 	status := "thinking"
@@ -306,11 +275,11 @@ func (sts *Server) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallTo
 
 	// If this is the final thought, try to extract a solution
 	if status == "completed" {
-		response.Solution = sts.extractSolution(params.Thought)
+		response.Solution = thinking.extractSolution(params.Thought)
 	}
 
 	// Format the result with session context
-	resultText := sts.formatThinkingResultWithSession(response, currentThought, session, activeBranch)
+	resultText := thinking.formatThinkingResultWithSession(response, currentThought, session, activeBranch)
 
 	return mcp.NewToolResult(mcp.NewTextContent(resultText)), nil
 }
@@ -324,16 +293,16 @@ type PersistentData struct {
 }
 
 // loadSessions loads sessions from persistence file
-func (sts *Server) loadSessions() error {
-	if sts.persistFile == "" {
+func (thinking *ThinkingOperations) loadSessions() error {
+	if thinking.persistFile == "" {
 		return nil
 	}
 
-	if _, err := os.Stat(sts.persistFile); os.IsNotExist(err) {
+	if _, err := os.Stat(thinking.persistFile); os.IsNotExist(err) {
 		return nil // File doesn't exist, start fresh
 	}
 
-	data, err := os.ReadFile(sts.persistFile)
+	data, err := os.ReadFile(thinking.persistFile)
 	if err != nil {
 		return err
 	}
@@ -347,29 +316,29 @@ func (sts *Server) loadSessions() error {
 		return err
 	}
 
-	sts.sessions = persistentData.Sessions
-	sts.branches = persistentData.Branches
+	thinking.sessions = persistentData.Sessions
+	thinking.branches = persistentData.Branches
 
 	// Initialize maps if nil
-	if sts.sessions == nil {
-		sts.sessions = make(map[string]*ThinkingSession)
+	if thinking.sessions == nil {
+		thinking.sessions = make(map[string]*ThinkingSession)
 	}
-	if sts.branches == nil {
-		sts.branches = make(map[string]*Branch)
+	if thinking.branches == nil {
+		thinking.branches = make(map[string]*Branch)
 	}
 
 	return nil
 }
 
 // saveSessions saves sessions to persistence file
-func (sts *Server) saveSessions() error {
-	if sts.persistFile == "" {
+func (thinking *ThinkingOperations) saveSessions() error {
+	if thinking.persistFile == "" {
 		return nil
 	}
 
 	persistentData := PersistentData{
-		Sessions: sts.sessions,
-		Branches: sts.branches,
+		Sessions: thinking.sessions,
+		Branches: thinking.branches,
 	}
 
 	data, err := json.MarshalIndent(persistentData, "", "  ")
@@ -377,7 +346,7 @@ func (sts *Server) saveSessions() error {
 		return err
 	}
 
-	return os.WriteFile(sts.persistFile, data, 0644)
+	return os.WriteFile(thinking.persistFile, data, 0644)
 }
 
 // ThinkingParameters holds parsed parameters for thinking operations
@@ -395,7 +364,7 @@ type ThinkingParameters struct {
 }
 
 // parseThinkingParameters parses and validates input parameters
-func (sts *Server) parseThinkingParameters(args map[string]interface{}) (*ThinkingParameters, error) {
+func (thinking *ThinkingOperations) parseThinkingParameters(args map[string]interface{}) (*ThinkingParameters, error) {
 	params := &ThinkingParameters{}
 
 	// Required parameters
@@ -488,12 +457,12 @@ func (sts *Server) parseThinkingParameters(args map[string]interface{}) (*Thinki
 }
 
 // getOrCreateSession gets existing session or creates new one
-func (sts *Server) getOrCreateSession(sessionID string) *ThinkingSession {
+func (thinking *ThinkingOperations) getOrCreateSession(sessionID string) *ThinkingSession {
 	if sessionID == "" {
-		sessionID = sts.generateSessionID()
+		sessionID = thinking.generateSessionID()
 	}
 
-	if session, exists := sts.sessions[sessionID]; exists {
+	if session, exists := thinking.sessions[sessionID]; exists {
 		return session
 	}
 
@@ -508,13 +477,13 @@ func (sts *Server) getOrCreateSession(sessionID string) *ThinkingSession {
 		ActiveBranches: make([]string, 0),
 	}
 
-	sts.sessions[sessionID] = session
+	thinking.sessions[sessionID] = session
 	return session
 }
 
 // getOrCreateBranch gets existing branch or creates new one
-func (sts *Server) getOrCreateBranch(sessionID, branchID string, fromThought int) *Branch {
-	if branch, exists := sts.branches[branchID]; exists {
+func (thinking *ThinkingOperations) getOrCreateBranch(sessionID, branchID string, fromThought int) *Branch {
+	if branch, exists := thinking.branches[branchID]; exists {
 		return branch
 	}
 
@@ -527,10 +496,10 @@ func (sts *Server) getOrCreateBranch(sessionID, branchID string, fromThought int
 		LastActivity: time.Now(),
 	}
 
-	sts.branches[branchID] = branch
+	thinking.branches[branchID] = branch
 
 	// Add to session's active branches
-	if session, exists := sts.sessions[sessionID]; exists {
+	if session, exists := thinking.sessions[sessionID]; exists {
 		session.ActiveBranches = append(session.ActiveBranches, branchID)
 	}
 
@@ -538,12 +507,12 @@ func (sts *Server) getOrCreateBranch(sessionID, branchID string, fromThought int
 }
 
 // generateSessionID generates a unique session ID
-func (sts *Server) generateSessionID() string {
+func (thinking *ThinkingOperations) generateSessionID() string {
 	return fmt.Sprintf("session_%d", time.Now().UnixNano())
 }
 
 // formatThinkingResultWithSession formats result with session context
-func (sts *Server) formatThinkingResultWithSession(response ThinkingResponse, thought Thought, session *ThinkingSession, branch *Branch) string {
+func (thinking *ThinkingOperations) formatThinkingResultWithSession(response ThinkingResponse, thought Thought, session *ThinkingSession, branch *Branch) string {
 	var result strings.Builder
 
 	// Header with session info
@@ -585,7 +554,7 @@ func (sts *Server) formatThinkingResultWithSession(response ThinkingResponse, th
 	result.WriteString(response.Thought + "\n\n")
 
 	// Progress indicator
-	progressBar := sts.createProgressBar(response.ThoughtNumber, response.TotalThoughts)
+	progressBar := thinking.createProgressBar(response.ThoughtNumber, response.TotalThoughts)
 	result.WriteString("๐Ÿ“Š Progress: " + progressBar + "\n\n")
 
 	// Status
@@ -617,7 +586,7 @@ func (sts *Server) formatThinkingResultWithSession(response ThinkingResponse, th
 	return result.String()
 }
 
-func (sts *Server) extractSolution(finalThought string) string {
+func (thinking *ThinkingOperations) extractSolution(finalThought string) string {
 	// Simple heuristic to extract a solution from the final thought
 	content := strings.ToLower(finalThought)
 
@@ -670,7 +639,7 @@ func (sts *Server) extractSolution(finalThought string) string {
 	return "Solution extracted from final thought"
 }
 
-func (sts *Server) formatThinkingResult(response ThinkingResponse, thought Thought, contextInfo []string) string {
+func (thinking *ThinkingOperations) formatThinkingResult(response ThinkingResponse, thought Thought, contextInfo []string) string {
 	var result strings.Builder
 
 	// Header
@@ -688,7 +657,7 @@ func (sts *Server) formatThinkingResult(response ThinkingResponse, thought Thoug
 	result.WriteString(response.Thought + "\n\n")
 
 	// Progress indicator
-	progressBar := sts.createProgressBar(response.ThoughtNumber, response.TotalThoughts)
+	progressBar := thinking.createProgressBar(response.ThoughtNumber, response.TotalThoughts)
 	result.WriteString("๐Ÿ“Š Progress: " + progressBar + "\n\n")
 
 	// Status
@@ -720,7 +689,7 @@ func (sts *Server) formatThinkingResult(response ThinkingResponse, thought Thoug
 	return result.String()
 }
 
-func (sts *Server) createProgressBar(current, total int) string {
+func (thinking *ThinkingOperations) createProgressBar(current, total int) string {
 	if total <= 0 {
 		return "[โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ] 100%"
 	}
@@ -748,16 +717,16 @@ func (sts *Server) createProgressBar(current, total int) string {
 
 // New tool handlers for session management
 
-func (sts *Server) HandleGetSessionHistory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (thinking *ThinkingOperations) handleGetSessionHistory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	sessionID, ok := req.Arguments["sessionId"].(string)
 	if !ok {
 		return mcp.NewToolError("sessionId parameter is required"), nil
 	}
 
-	sts.mu.RLock()
-	defer sts.mu.RUnlock()
+	thinking.mu.RLock()
+	defer thinking.mu.RUnlock()
 
-	session, exists := sts.sessions[sessionID]
+	session, exists := thinking.sessions[sessionID]
 	if !exists {
 		return mcp.NewToolError(fmt.Sprintf("Session %s not found", sessionID)), nil
 	}
@@ -776,12 +745,12 @@ func (sts *Server) HandleGetSessionHistory(req mcp.CallToolRequest) (mcp.CallToo
 	return mcp.NewToolResult(mcp.NewTextContent(string(jsonData))), nil
 }
 
-func (sts *Server) HandleListSessions(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	sts.mu.RLock()
-	defer sts.mu.RUnlock()
+func (thinking *ThinkingOperations) handleListSessions(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+	thinking.mu.RLock()
+	defer thinking.mu.RUnlock()
 
-	sessions := make([]map[string]interface{}, 0, len(sts.sessions))
-	for _, session := range sts.sessions {
+	sessions := make([]map[string]interface{}, 0, len(thinking.sessions))
+	for _, session := range thinking.sessions {
 		sessionInfo := map[string]interface{}{
 			"sessionId":      session.ID,
 			"status":         session.Status,
@@ -802,16 +771,16 @@ func (sts *Server) HandleListSessions(req mcp.CallToolRequest) (mcp.CallToolResu
 	return mcp.NewToolResult(mcp.NewTextContent(string(jsonData))), nil
 }
 
-func (sts *Server) HandleGetBranchHistory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (thinking *ThinkingOperations) handleGetBranchHistory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	branchID, ok := req.Arguments["branchId"].(string)
 	if !ok {
 		return mcp.NewToolError("branchId parameter is required"), nil
 	}
 
-	sts.mu.RLock()
-	defer sts.mu.RUnlock()
+	thinking.mu.RLock()
+	defer thinking.mu.RUnlock()
 
-	branch, exists := sts.branches[branchID]
+	branch, exists := thinking.branches[branchID]
 	if !exists {
 		return mcp.NewToolError(fmt.Sprintf("Branch %s not found", branchID)), nil
 	}
@@ -830,30 +799,30 @@ func (sts *Server) HandleGetBranchHistory(req mcp.CallToolRequest) (mcp.CallTool
 	return mcp.NewToolResult(mcp.NewTextContent(string(jsonData))), nil
 }
 
-func (sts *Server) HandleClearSession(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (thinking *ThinkingOperations) handleClearSession(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
 	sessionID, ok := req.Arguments["sessionId"].(string)
 	if !ok {
 		return mcp.NewToolError("sessionId parameter is required"), nil
 	}
 
-	sts.mu.Lock()
-	defer sts.mu.Unlock()
+	thinking.mu.Lock()
+	defer thinking.mu.Unlock()
 
-	session, exists := sts.sessions[sessionID]
+	session, exists := thinking.sessions[sessionID]
 	if !exists {
 		return mcp.NewToolError(fmt.Sprintf("Session %s not found", sessionID)), nil
 	}
 
 	// Remove associated branches
 	for _, branchID := range session.ActiveBranches {
-		delete(sts.branches, branchID)
+		delete(thinking.branches, branchID)
 	}
 
 	// Remove the session
-	delete(sts.sessions, sessionID)
+	delete(thinking.sessions, sessionID)
 
 	// Save to persistence if configured
-	sts.saveSessions()
+	thinking.saveSessions()
 
 	result := map[string]interface{}{
 		"message":       fmt.Sprintf("Session %s and %d branches cleared", sessionID, len(session.ActiveBranches)),
pkg/time/server.go
@@ -10,12 +10,6 @@ import (
 	"github.com/xlgmokha/mcp/pkg/mcp"
 )
 
-// Server implements the Time MCP server
-type Server struct {
-	*mcp.Server
-	localTimezone string
-}
-
 // TimeResult represents the result of a time operation
 type TimeResult struct {
 	Timezone string `json:"timezone"`
@@ -30,139 +24,105 @@ type TimeConversionResult struct {
 	TimeDifference string     `json:"time_difference"`
 }
 
-// New creates a new Time MCP server
-func New() *Server {
-	server := mcp.NewServer("mcp-time", "1.0.0", []mcp.Tool{}, []mcp.Resource{}, []mcp.Root{})
-
-	// Get local timezone
-	localTZ := getLocalTimezone()
-
-	timeServer := &Server{
-		Server:        server,
-		localTimezone: localTZ,
-	}
-
-	// Register all time tools
-	timeServer.registerTools()
-
-	return timeServer
+// TimeOperations provides time operations and timezone handling
+type TimeOperations struct {
+	localTimezone string
 }
 
-// registerTools registers all Time tools with the server
-func (ts *Server) registerTools() {
-	// Get all tool definitions from ListTools method
-	tools := ts.ListTools()
-	
-	// Register each tool with its proper definition
-	for _, tool := range tools {
-		var handler mcp.ToolHandler
-		switch tool.Name {
-		case "get_current_time":
-			handler = ts.HandleGetCurrentTime
-		case "convert_time":
-			handler = ts.HandleConvertTime
-		default:
-			continue
-		}
-		ts.RegisterToolWithDefinition(tool, handler)
+// NewTimeOperations creates a new TimeOperations helper
+func NewTimeOperations() *TimeOperations {
+	return &TimeOperations{
+		localTimezone: getLocalTimezone(),
 	}
 }
 
-// ListTools returns all available Time tools
-func (ts *Server) ListTools() []mcp.Tool {
-	return []mcp.Tool{
-		{
-			Name:        "get_current_time",
-			Description: "Get current time in a specific timezone",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"timezone": map[string]interface{}{
-						"type":        "string",
-						"description": fmt.Sprintf("IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use '%s' as local timezone if no timezone provided by the user.", ts.localTimezone),
-					},
-				},
-				"required": []string{"timezone"},
-			},
-		},
-		{
-			Name:        "convert_time",
-			Description: "Convert time between timezones",
-			InputSchema: map[string]interface{}{
-				"type": "object",
-				"properties": map[string]interface{}{
-					"source_timezone": map[string]interface{}{
-						"type":        "string",
-						"description": fmt.Sprintf("Source IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use '%s' as local timezone if no source timezone provided by the user.", ts.localTimezone),
-					},
-					"time": map[string]interface{}{
-						"type":        "string",
-						"description": "Time to convert in 24-hour format (HH:MM)",
-					},
-					"target_timezone": map[string]interface{}{
-						"type":        "string",
-						"description": fmt.Sprintf("Target IANA timezone name (e.g., 'Asia/Tokyo', 'America/San_Francisco'). Use '%s' as local timezone if no target timezone provided by the user.", ts.localTimezone),
-					},
-				},
-				"required": []string{"source_timezone", "time", "target_timezone"},
+// New creates a new Time MCP server
+func New() *mcp.Server {
+	timeOps := NewTimeOperations()
+	builder := mcp.NewServerBuilder("mcp-time", "1.0.0")
+
+	// Add get_current_time tool
+	builder.AddTool(mcp.NewTool("get_current_time", "Get current time in a specific timezone", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"timezone": map[string]interface{}{
+				"type":        "string",
+				"description": fmt.Sprintf("IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use '%s' as local timezone if no timezone provided by the user.", timeOps.localTimezone),
 			},
 		},
-	}
-}
-
-// Tool handlers
+		"required": []string{"timezone"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		timezone, ok := req.Arguments["timezone"].(string)
+		if !ok {
+			return mcp.NewToolError("timezone is required"), nil
+		}
 
-func (ts *Server) HandleGetCurrentTime(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	timezone, ok := req.Arguments["timezone"].(string)
-	if !ok {
-		return mcp.NewToolError("timezone is required"), nil
-	}
+		result, err := timeOps.getCurrentTime(timezone)
+		if err != nil {
+			return mcp.NewToolError(err.Error()), nil
+		}
 
-	result, err := ts.getCurrentTime(timezone)
-	if err != nil {
-		return mcp.NewToolError(err.Error()), nil
-	}
+		jsonResult, err := json.MarshalIndent(result, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
+		}
 
-	jsonResult, err := json.MarshalIndent(result, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
-	}
+		return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
+	}))
 
-	return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
-}
+	// Add convert_time tool
+	builder.AddTool(mcp.NewTool("convert_time", "Convert time between timezones", map[string]interface{}{
+		"type": "object",
+		"properties": map[string]interface{}{
+			"source_timezone": map[string]interface{}{
+				"type":        "string",
+				"description": fmt.Sprintf("Source IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use '%s' as local timezone if no source timezone provided by the user.", timeOps.localTimezone),
+			},
+			"time": map[string]interface{}{
+				"type":        "string",
+				"description": "Time to convert in 24-hour format (HH:MM)",
+			},
+			"target_timezone": map[string]interface{}{
+				"type":        "string",
+				"description": fmt.Sprintf("Target IANA timezone name (e.g., 'Asia/Tokyo', 'America/San_Francisco'). Use '%s' as local timezone if no target timezone provided by the user.", timeOps.localTimezone),
+			},
+		},
+		"required": []string{"source_timezone", "time", "target_timezone"},
+	}, func(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+		sourceTimezone, ok := req.Arguments["source_timezone"].(string)
+		if !ok {
+			return mcp.NewToolError("source_timezone is required"), nil
+		}
 
-func (ts *Server) HandleConvertTime(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
-	sourceTimezone, ok := req.Arguments["source_timezone"].(string)
-	if !ok {
-		return mcp.NewToolError("source_timezone is required"), nil
-	}
+		timeStr, ok := req.Arguments["time"].(string)
+		if !ok {
+			return mcp.NewToolError("time is required"), nil
+		}
 
-	timeStr, ok := req.Arguments["time"].(string)
-	if !ok {
-		return mcp.NewToolError("time is required"), nil
-	}
+		targetTimezone, ok := req.Arguments["target_timezone"].(string)
+		if !ok {
+			return mcp.NewToolError("target_timezone is required"), nil
+		}
 
-	targetTimezone, ok := req.Arguments["target_timezone"].(string)
-	if !ok {
-		return mcp.NewToolError("target_timezone is required"), nil
-	}
+		result, err := timeOps.convertTime(sourceTimezone, timeStr, targetTimezone)
+		if err != nil {
+			return mcp.NewToolError(err.Error()), nil
+		}
 
-	result, err := ts.convertTime(sourceTimezone, timeStr, targetTimezone)
-	if err != nil {
-		return mcp.NewToolError(err.Error()), nil
-	}
+		jsonResult, err := json.MarshalIndent(result, "", "  ")
+		if err != nil {
+			return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
+		}
 
-	jsonResult, err := json.MarshalIndent(result, "", "  ")
-	if err != nil {
-		return mcp.NewToolError(fmt.Sprintf("Failed to marshal result: %v", err)), nil
-	}
+		return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
+	}))
 
-	return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
+	return builder.Build()
 }
 
-// Helper methods
+// Helper methods for TimeOperations
 
-func (ts *Server) getCurrentTime(timezone string) (*TimeResult, error) {
+func (timeOps *TimeOperations) getCurrentTime(timezone string) (*TimeResult, error) {
 	loc, err := time.LoadLocation(timezone)
 	if err != nil {
 		return nil, fmt.Errorf("Invalid timezone: %v", err)
@@ -177,7 +137,7 @@ func (ts *Server) getCurrentTime(timezone string) (*TimeResult, error) {
 	}, nil
 }
 
-func (ts *Server) convertTime(sourceTimezone, timeStr, targetTimezone string) (*TimeConversionResult, error) {
+func (timeOps *TimeOperations) convertTime(sourceTimezone, timeStr, targetTimezone string) (*TimeConversionResult, error) {
 	sourceLoc, err := time.LoadLocation(sourceTimezone)
 	if err != nil {
 		return nil, fmt.Errorf("Invalid source timezone: %v", err)