Commit 3a9fdfc

mo khan <mo@mokhan.ca>
2025-08-15 23:16:38
refactor: provide resources in server constructor
1 parent 1e27822
pkg/bash/server.go
@@ -91,7 +91,7 @@ func NewBashServer(config *Config) (*BashServer, error) {
 	}
 
 	// Create base MCP server
-	baseServer := mcp.NewServer("bash", "1.0.0")
+	baseServer := mcp.NewServer("bash", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 	
 	server := &BashServer{
 		Server:         baseServer,
pkg/fetch/server.go
@@ -33,7 +33,7 @@ type FetchResult struct {
 
 // New creates a new Fetch MCP server
 func New() *Server {
-	server := mcp.NewServer("mcp-fetch", "1.0.0")
+	server := mcp.NewServer("mcp-fetch", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	fetchServer := &Server{
 		Server: server,
pkg/filesystem/server.go
@@ -94,35 +94,80 @@ func New(allowedDirs []string) *Server {
     }),
   }
 
-  server := mcp.NewServer("filesystem", "0.2.0", tools...)
-  fsServer.Server = server
+  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)
+        }
 
-  fsServer.registerResources()
-  fsServer.registerRoots()
-  fsServer.setupResourceHandling()
+        filePath := req.URI[7:]
+        validPath, err := fsServer.validatePath(filePath)
+        if err != nil {
+          return mcp.ReadResourceResult{}, fmt.Errorf("access denied: %v", err)
+        }
 
-  return fsServer
-}
+        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
+        }
 
-func (fs *Server) registerResources() {
-  for _, dir := range fs.allowedDirectories {
+        return mcp.ReadResourceResult{
+          Contents: []mcp.Content{
+            mcp.NewTextContent(string(content)),
+          },
+        }, nil
+      },
+    ),
+  }
+
+  for _, dir := range normalizedDirs {
     fileURI := "file://" + dir
     dirName := filepath.Base(dir)
     if dirName == "." || dirName == "/" {
       dirName = dir
     }
 
-    resource := mcp.Resource{
-      URI:      fileURI,
-      Name:     fmt.Sprintf("Directory: %s", dirName),
-      MimeType: "inode/directory",
-    }
-
-    fs.Server.RegisterResourceWithDefinition(resource, fs.HandleFileResource)
+    resources = append(resources, mcp.NewResource(
+      fileURI,
+      fmt.Sprintf("Directory: %s", dirName),
+      "inode/directory",
+      func(req mcp.ReadResourceRequest) (mcp.ReadResourceResult, error) {
+        return mcp.ReadResourceResult{
+          Contents: []mcp.Content{
+            mcp.NewTextContent(fmt.Sprintf("Directory: %s", dir)),
+          },
+        }, nil
+      },
+    ))
   }
+
+  server := mcp.NewServer("filesystem", "0.2.0", tools, resources)
+  fsServer.Server = server
+
+  fsServer.registerRoots()
+  fsServer.setupResourceHandling()
+
+  return fsServer
 }
 
+
+
+
 func (fs *Server) registerRoots() {
   for _, dir := range fs.allowedDirectories {
     fileURI := "file://" + dir
@@ -260,40 +305,6 @@ func (fs *Server) discoverFiles(dirPath string) []mcp.Resource {
   return resources
 }
 
-func (fs *Server) HandleFileResource(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 := fs.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
-  }
-
-  return mcp.ReadResourceResult{
-    Contents: []mcp.Content{
-      mcp.NewTextContent(string(content)),
-    },
-  }, nil
-}
 
 func isBinaryContent(content []byte) bool {
   checkBytes := content
pkg/git/server.go
@@ -20,7 +20,7 @@ type Server struct {
 
 // New creates a new Git MCP server
 func New(repoPath string) *Server {
-	server := mcp.NewServer("mcp-git", "1.0.0")
+	server := mcp.NewServer("mcp-git", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	gitServer := &Server{
 		Server:   server,
pkg/gitlab/server.go
@@ -97,7 +97,7 @@ type GitLabUser struct {
 }
 
 func NewServer(gitlabURL, token string) (*Server, error) {
-	baseServer := mcp.NewServer("gitlab", "0.1.0")
+	baseServer := mcp.NewServer("gitlab", "0.1.0", []mcp.Tool{}, []mcp.Resource{})
 	
 	// Initialize cache with default configuration
 	cache, err := NewCache(CacheConfig{
pkg/imap/server.go
@@ -67,7 +67,7 @@ type ConnectionInfo struct {
 
 func NewServer(server, username, password string, port int, useTLS bool) *Server {
 	s := &Server{
-		Server:   mcp.NewServer("imap", "IMAP email server for reading and managing emails"),
+		Server:   mcp.NewServer("imap", "IMAP email server for reading and managing emails", []mcp.Tool{}, []mcp.Resource{}),
 		server:   server,
 		username: username,
 		password: password,
pkg/maildir/server.go
@@ -67,7 +67,7 @@ type ContactInfo struct {
 
 // New creates a new Maildir MCP server
 func New(allowedPaths []string) *Server {
-	server := mcp.NewServer("maildir-server", "1.0.0")
+	server := mcp.NewServer("maildir-server", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	// Normalize and validate allowed paths
 	normalizedPaths := make([]string, len(allowedPaths))
pkg/mcp/server.go
@@ -42,7 +42,7 @@ type PromptHandler func(GetPromptRequest) (GetPromptResult, error)
 type ResourceHandler func(ReadResourceRequest) (ReadResourceResult, error)
 
 // NewServer creates a new MCP server
-func NewServer(name, version string, tools ...Tool) *Server {
+func NewServer(name, version string, tools []Tool, resources []Resource) *Server {
 	server := &Server{
 		name:                  name,
 		version:               version,
@@ -68,6 +68,11 @@ func NewServer(name, version string, tools ...Tool) *Server {
 		server.toolDefinitions[tool.Name] = tool
 	}
 
+	for _, resource := range resources {
+		server.resourceHandlers[resource.URI] = resource.Handler
+		server.resourceDefinitions[resource.URI] = resource
+	}
+
 	return server
 }
 
@@ -458,6 +463,16 @@ func NewTool(name, description string, inputSchema interface{}, handler ToolHand
 	}
 }
 
+// Helper function to create a new resource with all fields
+func NewResource(uri, name, mimeType string, handler ResourceHandler) Resource {
+	return Resource{
+		URI:      uri,
+		Name:     name,
+		MimeType: mimeType,
+		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
@@ -170,10 +170,11 @@ type GetPromptResult struct {
 
 // Resource types
 type Resource struct {
-	URI         string `json:"uri"`
-	Name        string `json:"name"`
-	Description string `json:"description,omitempty"`
-	MimeType    string `json:"mimeType,omitempty"`
+	URI         string          `json:"uri"`
+	Name        string          `json:"name"`
+	Description string          `json:"description,omitempty"`
+	MimeType    string          `json:"mimeType,omitempty"`
+	Handler     ResourceHandler `json:"-"`
 }
 
 type ListResourcesResult struct {
pkg/memory/server.go
@@ -41,7 +41,7 @@ type Relation struct {
 
 // New creates a new Memory MCP server
 func New(memoryFile string) *Server {
-	server := mcp.NewServer("mcp-memory", "1.0.0")
+	server := mcp.NewServer("mcp-memory", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	memoryServer := &Server{
 		Server:     server,
pkg/packages/server.go
@@ -20,7 +20,7 @@ type Server struct {
 
 // NewServer creates a new Package Manager MCP server
 func NewServer() *Server {
-	baseServer := mcp.NewServer("mcp-packages", "1.0.0")
+	baseServer := mcp.NewServer("mcp-packages", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	server := &Server{
 		Server: baseServer,
pkg/semantic/server.go
@@ -19,7 +19,7 @@ type Server struct {
 
 // NewServer creates a new Semantic MCP server
 func NewServer() *Server {
-	baseServer := mcp.NewServer("mcp-semantic", "1.0.0")
+	baseServer := mcp.NewServer("mcp-semantic", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 	
 	lspManager := NewLSPManager()
 	projectManager := NewProjectManager()
pkg/signal/server.go
@@ -63,7 +63,7 @@ type Attachment struct {
 }
 
 func NewServer(signalPath string) (*Server, error) {
-	baseServer := mcp.NewServer("signal", "0.1.0")
+	baseServer := mcp.NewServer("signal", "0.1.0", []mcp.Tool{}, []mcp.Resource{})
 	
 	server := &Server{
 		Server: baseServer,
pkg/speech/server.go
@@ -36,7 +36,7 @@ type Server struct {
 
 // NewServer creates a new Speech MCP server
 func NewServer() *Server {
-	baseServer := mcp.NewServer("mcp-speech", "1.0.0")
+	baseServer := mcp.NewServer("mcp-speech", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 	
 	// Select appropriate TTS backend based on OS
 	var backend TTSBackend
pkg/thinking/server.go
@@ -75,7 +75,7 @@ func New() *Server {
 
 // 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")
+	server := mcp.NewServer("mcp-sequential-thinking", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	thinkingServer := &Server{
 		Server:      server,
pkg/time/server.go
@@ -32,7 +32,7 @@ type TimeConversionResult struct {
 
 // New creates a new Time MCP server
 func New() *Server {
-	server := mcp.NewServer("mcp-time", "1.0.0")
+	server := mcp.NewServer("mcp-time", "1.0.0", []mcp.Tool{}, []mcp.Resource{})
 
 	// Get local timezone
 	localTZ := getLocalTimezone()