Commit 0bff639
Changed files (20)
cmd
pkg
fetchserver
fsserver
gitserver
memoryserver
thinkingserver
timeserver
cmd/fetch/main.go
@@ -4,11 +4,12 @@ import (
"context"
"log"
+ "github.com/xlgmokha/mcp/pkg/fetchserver"
"github.com/xlgmokha/mcp/pkg/mcp"
)
func main() {
- server := NewFetchServer()
+ server := fetchserver.New()
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/filesystem/main.go
@@ -5,6 +5,7 @@ import (
"log"
"os"
+ "github.com/xlgmokha/mcp/pkg/fsserver"
"github.com/xlgmokha/mcp/pkg/mcp"
)
@@ -15,7 +16,7 @@ func main() {
}
allowedDirs := os.Args[1:]
- server := NewFilesystemServer(allowedDirs)
+ server := fsserver.New(allowedDirs)
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/git/main.go
@@ -4,11 +4,12 @@ import (
"context"
"log"
+ "github.com/xlgmokha/mcp/pkg/gitserver"
"github.com/xlgmokha/mcp/pkg/mcp"
)
func main() {
- server := NewGitServer()
+ server := gitserver.New()
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/memory/main.go
@@ -7,6 +7,7 @@ import (
"path/filepath"
"github.com/xlgmokha/mcp/pkg/mcp"
+ "github.com/xlgmokha/mcp/pkg/memoryserver"
)
func main() {
@@ -20,7 +21,7 @@ func main() {
memoryFile = filepath.Join(homeDir, ".mcp_memory.json")
}
- server := NewMemoryServer(memoryFile)
+ server := memoryserver.New(memoryFile)
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/sequential-thinking/main.go
@@ -5,10 +5,11 @@ import (
"log"
"github.com/xlgmokha/mcp/pkg/mcp"
+ "github.com/xlgmokha/mcp/pkg/thinkingserver"
)
func main() {
- server := NewSequentialThinkingServer()
+ server := thinkingserver.New()
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/time/main.go
@@ -5,10 +5,11 @@ import (
"log"
"github.com/xlgmokha/mcp/pkg/mcp"
+ "github.com/xlgmokha/mcp/pkg/timeserver"
)
func main() {
- server := NewTimeServer()
+ server := timeserver.New()
// Set up basic initialization
server.SetInitializeHandler(func(req mcp.InitializeRequest) (mcp.InitializeResult, error) {
cmd/fetch/server.go โ pkg/fetchserver/server.go
@@ -1,4 +1,4 @@
-package main
+package fetchserver
import (
"encoding/json"
@@ -14,8 +14,8 @@ import (
"golang.org/x/net/html"
)
-// FetchServer implements the Fetch MCP server
-type FetchServer struct {
+// Server implements the Fetch MCP server
+type Server struct {
*mcp.Server
httpClient *http.Client
userAgent string
@@ -31,11 +31,11 @@ type FetchResult struct {
NextIndex int `json:"next_index,omitempty"`
}
-// NewFetchServer creates a new Fetch MCP server
-func NewFetchServer() *FetchServer {
+// New creates a new Fetch MCP server
+func New() *Server {
server := mcp.NewServer("mcp-fetch", "1.0.0")
- fetchServer := &FetchServer{
+ fetchServer := &Server{
Server: server,
httpClient: &http.Client{
Timeout: 30 * time.Second,
@@ -50,12 +50,12 @@ func NewFetchServer() *FetchServer {
}
// registerTools registers all Fetch tools with the server
-func (fs *FetchServer) registerTools() {
+func (fs *Server) registerTools() {
fs.RegisterTool("fetch", fs.HandleFetch)
}
// ListTools returns all available Fetch tools
-func (fs *FetchServer) ListTools() []mcp.Tool {
+func (fs *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "fetch",
@@ -95,7 +95,7 @@ func (fs *FetchServer) ListTools() []mcp.Tool {
// Tool handlers
-func (fs *FetchServer) HandleFetch(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+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
@@ -162,7 +162,7 @@ func (fs *FetchServer) HandleFetch(req mcp.CallToolRequest) (mcp.CallToolResult,
// Helper methods
-func (fs *FetchServer) fetchContent(urlStr string, maxLength, startIndex int, raw bool) (*FetchResult, error) {
+func (fs *Server) fetchContent(urlStr string, maxLength, startIndex int, raw bool) (*FetchResult, error) {
// Create HTTP request
req, err := http.NewRequest("GET", urlStr, nil)
if err != nil {
@@ -250,7 +250,7 @@ func isHTMLContent(content, contentType string) bool {
return strings.Contains(strings.ToLower(prefix), "<html")
}
-func (fs *FetchServer) htmlToMarkdown(htmlContent string) string {
+func (fs *Server) htmlToMarkdown(htmlContent string) string {
// Parse HTML
doc, err := html.Parse(strings.NewReader(htmlContent))
if err != nil {
@@ -269,7 +269,7 @@ func (fs *FetchServer) htmlToMarkdown(htmlContent string) string {
return content
}
-func (fs *FetchServer) extractMarkdown(node *html.Node, result *strings.Builder, depth int) {
+func (fs *Server) extractMarkdown(node *html.Node, result *strings.Builder, depth int) {
if node.Type == html.TextNode {
text := strings.TrimSpace(node.Data)
if text != "" {
@@ -354,7 +354,7 @@ func (fs *FetchServer) extractMarkdown(node *html.Node, result *strings.Builder,
}
}
-func (fs *FetchServer) stripHTMLTags(content string) string {
+func (fs *Server) stripHTMLTags(content string) string {
// Remove HTML tags using regex
re := regexp.MustCompile(`<[^>]*>`)
text := re.ReplaceAllString(content, " ")
@@ -366,7 +366,7 @@ func (fs *FetchServer) stripHTMLTags(content string) string {
return strings.TrimSpace(text)
}
-func (fs *FetchServer) cleanMarkdown(content string) string {
+func (fs *Server) cleanMarkdown(content string) string {
// Remove excessive newlines
re := regexp.MustCompile(`\n{3,}`)
content = re.ReplaceAllString(content, "\n\n")
cmd/fetch/server_test.go โ pkg/fetchserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package fetchserver
import (
"net/http"
@@ -9,7 +9,7 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-func TestFetchServer_FetchTool(t *testing.T) {
+func TestServer_FetchTool(t *testing.T) {
// Create test server with HTML content
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
@@ -27,7 +27,7 @@ func TestFetchServer_FetchTool(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -65,7 +65,7 @@ func TestFetchServer_FetchTool(t *testing.T) {
}
}
-func TestFetchServer_FetchRawContent(t *testing.T) {
+func TestServer_FetchRawContent(t *testing.T) {
// Create test server with HTML content
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
@@ -74,7 +74,7 @@ func TestFetchServer_FetchRawContent(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -109,7 +109,7 @@ func TestFetchServer_FetchRawContent(t *testing.T) {
}
}
-func TestFetchServer_FetchWithMaxLength(t *testing.T) {
+func TestServer_FetchWithMaxLength(t *testing.T) {
// Create test server with long plain text content to avoid HTML conversion complexity
longContent := strings.Repeat("x", 200) // 200 characters
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -119,7 +119,7 @@ func TestFetchServer_FetchWithMaxLength(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -154,7 +154,7 @@ func TestFetchServer_FetchWithMaxLength(t *testing.T) {
}
}
-func TestFetchServer_FetchWithStartIndex(t *testing.T) {
+func TestServer_FetchWithStartIndex(t *testing.T) {
// Create test server with content
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
@@ -163,7 +163,7 @@ func TestFetchServer_FetchWithStartIndex(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -196,8 +196,8 @@ func TestFetchServer_FetchWithStartIndex(t *testing.T) {
}
}
-func TestFetchServer_FetchInvalidURL(t *testing.T) {
- server := NewFetchServer()
+func TestServer_FetchInvalidURL(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -225,7 +225,7 @@ func TestFetchServer_FetchInvalidURL(t *testing.T) {
}
}
-func TestFetchServer_FetchHTTPError(t *testing.T) {
+func TestServer_FetchHTTPError(t *testing.T) {
// Create test server that returns 404
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
@@ -233,7 +233,7 @@ func TestFetchServer_FetchHTTPError(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -261,7 +261,7 @@ func TestFetchServer_FetchHTTPError(t *testing.T) {
}
}
-func TestFetchServer_FetchPlainText(t *testing.T) {
+func TestServer_FetchPlainText(t *testing.T) {
// Create test server with plain text content
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
@@ -270,7 +270,7 @@ func TestFetchServer_FetchPlainText(t *testing.T) {
}))
defer testServer.Close()
- server := NewFetchServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "fetch",
@@ -300,8 +300,8 @@ func TestFetchServer_FetchPlainText(t *testing.T) {
}
}
-func TestFetchServer_ListTools(t *testing.T) {
- server := NewFetchServer()
+func TestServer_ListTools(t *testing.T) {
+ server := New()
tools := server.ListTools()
expectedTools := []string{
cmd/filesystem/server.go โ pkg/fsserver/server.go
@@ -1,4 +1,4 @@
-package main
+package fsserver
import (
"fmt"
@@ -11,14 +11,14 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-// FilesystemServer implements the Filesystem MCP server
-type FilesystemServer struct {
+// Server implements the Filesystem MCP server
+type Server struct {
*mcp.Server
allowedDirectories []string
}
-// NewFilesystemServer creates a new Filesystem MCP server
-func NewFilesystemServer(allowedDirs []string) *FilesystemServer {
+// New creates a new Filesystem MCP server
+func New(allowedDirs []string) *Server {
server := mcp.NewServer("secure-filesystem-server", "0.2.0")
// Normalize and validate allowed directories
@@ -31,7 +31,7 @@ func NewFilesystemServer(allowedDirs []string) *FilesystemServer {
normalizedDirs[i] = filepath.Clean(absPath)
}
- fsServer := &FilesystemServer{
+ fsServer := &Server{
Server: server,
allowedDirectories: normalizedDirs,
}
@@ -43,7 +43,7 @@ func NewFilesystemServer(allowedDirs []string) *FilesystemServer {
}
// registerTools registers all Filesystem tools with the server
-func (fs *FilesystemServer) registerTools() {
+func (fs *Server) registerTools() {
fs.RegisterTool("read_file", fs.HandleReadFile)
fs.RegisterTool("read_multiple_files", fs.HandleReadMultipleFiles)
fs.RegisterTool("write_file", fs.HandleWriteFile)
@@ -59,7 +59,7 @@ func (fs *FilesystemServer) registerTools() {
}
// ListTools returns all available Filesystem tools
-func (fs *FilesystemServer) ListTools() []mcp.Tool {
+func (fs *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "read_file",
@@ -287,7 +287,7 @@ func (fs *FilesystemServer) ListTools() []mcp.Tool {
// Tool handlers
-func (fs *FilesystemServer) HandleReadFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleReadFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -330,7 +330,7 @@ func (fs *FilesystemServer) HandleReadFile(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(string(content))), nil
}
-func (fs *FilesystemServer) HandleReadMultipleFiles(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleReadMultipleFiles(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathsInterface, ok := req.Arguments["paths"]
if !ok {
return mcp.NewToolError("paths is required"), nil
@@ -361,7 +361,7 @@ func (fs *FilesystemServer) HandleReadMultipleFiles(req mcp.CallToolRequest) (mc
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(results, "\n---\n"))), nil
}
-func (fs *FilesystemServer) HandleWriteFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleWriteFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -385,7 +385,7 @@ func (fs *FilesystemServer) HandleWriteFile(req mcp.CallToolRequest) (mcp.CallTo
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Successfully wrote to %s", pathStr))), nil
}
-func (fs *FilesystemServer) HandleEditFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleEditFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -422,7 +422,7 @@ func (fs *FilesystemServer) HandleEditFile(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(diff)), nil
}
-func (fs *FilesystemServer) HandleCreateDirectory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleCreateDirectory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -441,7 +441,7 @@ func (fs *FilesystemServer) HandleCreateDirectory(req mcp.CallToolRequest) (mcp.
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Successfully created directory %s", pathStr))), nil
}
-func (fs *FilesystemServer) HandleListDirectory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleListDirectory(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -469,7 +469,7 @@ func (fs *FilesystemServer) HandleListDirectory(req mcp.CallToolRequest) (mcp.Ca
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(formatted, "\n"))), nil
}
-func (fs *FilesystemServer) HandleListDirectoryWithSizes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleListDirectoryWithSizes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -551,7 +551,7 @@ func (fs *FilesystemServer) HandleListDirectoryWithSizes(req mcp.CallToolRequest
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(formatted, "\n"))), nil
}
-func (fs *FilesystemServer) HandleDirectoryTree(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleDirectoryTree(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -570,7 +570,7 @@ func (fs *FilesystemServer) HandleDirectoryTree(req mcp.CallToolRequest) (mcp.Ca
return mcp.NewToolResult(mcp.NewTextContent(tree)), nil
}
-func (fs *FilesystemServer) HandleMoveFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleMoveFile(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
sourcePath, ok := req.Arguments["source"].(string)
if !ok {
return mcp.NewToolError("source is required"), nil
@@ -599,7 +599,7 @@ func (fs *FilesystemServer) HandleMoveFile(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Successfully moved %s to %s", sourcePath, destPath))), nil
}
-func (fs *FilesystemServer) HandleSearchFiles(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleSearchFiles(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -634,7 +634,7 @@ func (fs *FilesystemServer) HandleSearchFiles(req mcp.CallToolRequest) (mcp.Call
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(results, "\n"))), nil
}
-func (fs *FilesystemServer) HandleGetFileInfo(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleGetFileInfo(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
pathStr, ok := req.Arguments["path"].(string)
if !ok {
return mcp.NewToolError("path is required"), nil
@@ -661,7 +661,7 @@ func (fs *FilesystemServer) HandleGetFileInfo(req mcp.CallToolRequest) (mcp.Call
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(result, "\n"))), nil
}
-func (fs *FilesystemServer) HandleListAllowedDirectories(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (fs *Server) HandleListAllowedDirectories(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
dirs := []string{"Allowed directories:"}
dirs = append(dirs, fs.allowedDirectories...)
return mcp.NewToolResult(mcp.NewTextContent(strings.Join(dirs, "\n"))), nil
@@ -669,7 +669,7 @@ func (fs *FilesystemServer) HandleListAllowedDirectories(req mcp.CallToolRequest
// Helper methods
-func (fs *FilesystemServer) validatePath(requestedPath string) (string, error) {
+func (fs *Server) validatePath(requestedPath string) (string, error) {
expandedPath := expandHome(requestedPath)
var absolute string
@@ -729,7 +729,7 @@ func expandHome(filePath string) string {
return filePath
}
-func (fs *FilesystemServer) convertToStringSlice(input interface{}) ([]string, error) {
+func (fs *Server) convertToStringSlice(input interface{}) ([]string, error) {
switch v := input.(type) {
case []interface{}:
result := make([]string, len(v))
@@ -748,7 +748,7 @@ func (fs *FilesystemServer) convertToStringSlice(input interface{}) ([]string, e
}
}
-func (fs *FilesystemServer) tailFile(filePath string, numLines int) (string, error) {
+func (fs *Server) tailFile(filePath string, numLines int) (string, error) {
// Simple implementation - read file and return last N lines
content, err := os.ReadFile(filePath)
if err != nil {
@@ -763,7 +763,7 @@ func (fs *FilesystemServer) tailFile(filePath string, numLines int) (string, err
return strings.Join(lines[len(lines)-numLines:], "\n"), nil
}
-func (fs *FilesystemServer) headFile(filePath string, numLines int) (string, error) {
+func (fs *Server) headFile(filePath string, numLines int) (string, error) {
// Simple implementation - read file and return first N lines
content, err := os.ReadFile(filePath)
if err != nil {
@@ -778,7 +778,7 @@ func (fs *FilesystemServer) headFile(filePath string, numLines int) (string, err
return strings.Join(lines[:numLines], "\n"), nil
}
-func (fs *FilesystemServer) parseEdits(editsInterface interface{}) ([]Edit, error) {
+func (fs *Server) parseEdits(editsInterface interface{}) ([]Edit, error) {
editsSlice, ok := editsInterface.([]interface{})
if !ok {
return nil, fmt.Errorf("edits must be an array")
@@ -812,7 +812,7 @@ type Edit struct {
NewText string
}
-func (fs *FilesystemServer) applyFileEdits(filePath string, edits []Edit, dryRun bool) (string, error) {
+func (fs *Server) applyFileEdits(filePath string, edits []Edit, dryRun bool) (string, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return "", err
@@ -842,7 +842,7 @@ func (fs *FilesystemServer) applyFileEdits(filePath string, edits []Edit, dryRun
return diff, nil
}
-func (fs *FilesystemServer) createUnifiedDiff(original, modified, filePath string) string {
+func (fs *Server) createUnifiedDiff(original, modified, filePath string) string {
// Simple diff implementation
if original == modified {
return "No changes made"
@@ -856,7 +856,7 @@ func (fs *FilesystemServer) createUnifiedDiff(original, modified, filePath strin
strings.ReplaceAll(modified, "\n", "\n+"))
}
-func (fs *FilesystemServer) formatSize(bytes int64) string {
+func (fs *Server) formatSize(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
@@ -869,7 +869,7 @@ func (fs *FilesystemServer) formatSize(bytes int64) string {
return fmt.Sprintf("%.2f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
-func (fs *FilesystemServer) buildDirectoryTree(rootPath string) (string, error) {
+func (fs *Server) buildDirectoryTree(rootPath string) (string, error) {
type TreeEntry struct {
Name string `json:"name"`
Type string `json:"type"`
@@ -922,7 +922,7 @@ func (fs *FilesystemServer) buildDirectoryTree(rootPath string) (string, error)
return fmt.Sprintf("%+v", tree), nil
}
-func (fs *FilesystemServer) searchFiles(rootPath, pattern string, excludePatterns []string) ([]string, error) {
+func (fs *Server) searchFiles(rootPath, pattern string, excludePatterns []string) ([]string, error) {
var results []string
pattern = strings.ToLower(pattern)
cmd/filesystem/server_test.go โ pkg/fsserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package fsserver
import (
"os"
@@ -23,7 +23,7 @@ func TestFilesystemServer_ReadFile(t *testing.T) {
t.Fatal(err)
}
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
req := mcp.CallToolRequest{
Name: "read_file",
@@ -59,7 +59,7 @@ func TestFilesystemServer_WriteFile(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
testFile := filepath.Join(tempDir, "new_file.txt")
testContent := "New content"
@@ -99,7 +99,7 @@ func TestFilesystemServer_SecurityValidation(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
// Try to access file outside allowed directory
req := mcp.CallToolRequest{
@@ -147,7 +147,7 @@ func TestFilesystemServer_ListDirectory(t *testing.T) {
t.Fatal(err)
}
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
req := mcp.CallToolRequest{
Name: "list_directory",
@@ -188,7 +188,7 @@ func TestFilesystemServer_CreateDirectory(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
newDir := filepath.Join(tempDir, "new", "nested", "directory")
req := mcp.CallToolRequest{
@@ -214,7 +214,7 @@ func TestFilesystemServer_CreateDirectory(t *testing.T) {
}
func TestFilesystemServer_ListTools(t *testing.T) {
- server := NewFilesystemServer([]string{"/tmp"})
+ server := New([]string{"/tmp"})
tools := server.ListTools()
expectedTools := []string{
@@ -255,7 +255,7 @@ func TestFilesystemServer_EditFile(t *testing.T) {
t.Fatal(err)
}
- server := NewFilesystemServer([]string{tempDir})
+ server := New([]string{tempDir})
req := mcp.CallToolRequest{
Name: "edit_file",
cmd/git/server.go โ pkg/gitserver/server.go
@@ -1,4 +1,4 @@
-package main
+package gitserver
import (
"fmt"
@@ -11,16 +11,16 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-// GitServer implements the Git MCP server
-type GitServer struct {
+// Server implements the Git MCP server
+type Server struct {
*mcp.Server
}
-// NewGitServer creates a new Git MCP server
-func NewGitServer() *GitServer {
+// New creates a new Git MCP server
+func New() *Server {
server := mcp.NewServer("mcp-git", "1.0.0")
- gitServer := &GitServer{
+ gitServer := &Server{
Server: server,
}
@@ -31,7 +31,7 @@ func NewGitServer() *GitServer {
}
// registerTools registers all Git tools with the server
-func (gs *GitServer) registerTools() {
+func (gs *Server) registerTools() {
gs.RegisterTool("git_status", gs.HandleGitStatus)
gs.RegisterTool("git_diff_unstaged", gs.HandleGitDiffUnstaged)
gs.RegisterTool("git_diff_staged", gs.HandleGitDiffStaged)
@@ -47,7 +47,7 @@ func (gs *GitServer) registerTools() {
}
// ListTools returns all available Git tools
-func (gs *GitServer) ListTools() []mcp.Tool {
+func (gs *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "git_status",
@@ -258,7 +258,7 @@ func (gs *GitServer) ListTools() []mcp.Tool {
// Tool handlers
-func (gs *GitServer) HandleGitStatus(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitStatus(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -272,7 +272,7 @@ func (gs *GitServer) HandleGitStatus(req mcp.CallToolRequest) (mcp.CallToolResul
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Repository status:\n%s", output))), nil
}
-func (gs *GitServer) HandleGitDiffUnstaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitDiffUnstaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -286,7 +286,7 @@ func (gs *GitServer) HandleGitDiffUnstaged(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Unstaged changes:\n%s", output))), nil
}
-func (gs *GitServer) HandleGitDiffStaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitDiffStaged(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -300,7 +300,7 @@ func (gs *GitServer) HandleGitDiffStaged(req mcp.CallToolRequest) (mcp.CallToolR
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Staged changes:\n%s", output))), nil
}
-func (gs *GitServer) HandleGitDiff(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitDiff(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -319,7 +319,7 @@ func (gs *GitServer) HandleGitDiff(req mcp.CallToolRequest) (mcp.CallToolResult,
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Diff with %s:\n%s", target, output))), nil
}
-func (gs *GitServer) HandleGitCommit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitCommit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -338,7 +338,7 @@ func (gs *GitServer) HandleGitCommit(req mcp.CallToolRequest) (mcp.CallToolResul
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Changes committed successfully:\n%s", output))), nil
}
-func (gs *GitServer) HandleGitAdd(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitAdd(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -363,7 +363,7 @@ func (gs *GitServer) HandleGitAdd(req mcp.CallToolRequest) (mcp.CallToolResult,
return mcp.NewToolResult(mcp.NewTextContent("Files staged successfully")), nil
}
-func (gs *GitServer) HandleGitReset(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitReset(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -377,7 +377,7 @@ func (gs *GitServer) HandleGitReset(req mcp.CallToolRequest) (mcp.CallToolResult
return mcp.NewToolResult(mcp.NewTextContent("All staged changes reset")), nil
}
-func (gs *GitServer) HandleGitLog(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitLog(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -398,7 +398,7 @@ func (gs *GitServer) HandleGitLog(req mcp.CallToolRequest) (mcp.CallToolResult,
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Commit history:\n%s", output))), nil
}
-func (gs *GitServer) HandleGitCreateBranch(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitCreateBranch(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -426,7 +426,7 @@ func (gs *GitServer) HandleGitCreateBranch(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Created branch '%s'", branchName))), nil
}
-func (gs *GitServer) HandleGitCheckout(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitCheckout(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -445,7 +445,7 @@ func (gs *GitServer) HandleGitCheckout(req mcp.CallToolRequest) (mcp.CallToolRes
return mcp.NewToolResult(mcp.NewTextContent(fmt.Sprintf("Switched to branch '%s'", branchName))), nil
}
-func (gs *GitServer) HandleGitShow(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitShow(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -464,7 +464,7 @@ func (gs *GitServer) HandleGitShow(req mcp.CallToolRequest) (mcp.CallToolResult,
return mcp.NewToolResult(mcp.NewTextContent(output)), nil
}
-func (gs *GitServer) HandleGitInit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (gs *Server) HandleGitInit(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
repoPath, ok := req.Arguments["repo_path"].(string)
if !ok {
return mcp.NewToolError("repo_path is required"), nil
@@ -485,7 +485,7 @@ func (gs *GitServer) HandleGitInit(req mcp.CallToolRequest) (mcp.CallToolResult,
// Helper methods
-func (gs *GitServer) runGitCommand(repoPath string, args ...string) (string, error) {
+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)
@@ -510,7 +510,7 @@ func (gs *GitServer) runGitCommand(repoPath string, args ...string) (string, err
return strings.TrimSpace(string(output)), nil
}
-func (gs *GitServer) convertToStringSlice(input interface{}) ([]string, error) {
+func (gs *Server) convertToStringSlice(input interface{}) ([]string, error) {
switch v := input.(type) {
case []interface{}:
result := make([]string, len(v))
cmd/git/server_test.go โ pkg/gitserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package gitserver
import (
"fmt"
@@ -22,7 +22,7 @@ func TestGitServer_GitStatus(t *testing.T) {
t.Fatal(err)
}
- server := NewGitServer()
+ server := New()
// Test git status
req := mcp.CallToolRequest{
@@ -64,7 +64,7 @@ func TestGitServer_GitInit(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- server := NewGitServer()
+ server := New()
// Test git init
req := mcp.CallToolRequest{
@@ -119,7 +119,7 @@ func TestGitServer_GitAdd(t *testing.T) {
t.Fatal(err)
}
- server := NewGitServer()
+ server := New()
// Test git add
req := mcp.CallToolRequest{
@@ -151,7 +151,7 @@ func TestGitServer_GitAdd(t *testing.T) {
}
func TestGitServer_ListTools(t *testing.T) {
- server := NewGitServer()
+ server := New()
tools := server.ListTools()
expectedTools := []string{
@@ -179,7 +179,7 @@ func TestGitServer_ListTools(t *testing.T) {
// Helper functions
func initGitRepo(dir string) error {
// Use actual git init command for testing
- server := NewGitServer()
+ server := New()
req := mcp.CallToolRequest{
Name: "git_init",
Arguments: map[string]interface{}{
cmd/memory/server.go โ pkg/memoryserver/server.go
@@ -1,4 +1,4 @@
-package main
+package memoryserver
import (
"encoding/json"
@@ -10,8 +10,8 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-// MemoryServer implements the Memory MCP server with knowledge graph functionality
-type MemoryServer struct {
+// Server implements the Memory MCP server with knowledge graph functionality
+type Server struct {
*mcp.Server
memoryFile string
graph *KnowledgeGraph
@@ -38,11 +38,11 @@ type Relation struct {
RelationType string `json:"relationType"`
}
-// NewMemoryServer creates a new Memory MCP server
-func NewMemoryServer(memoryFile string) *MemoryServer {
+// New creates a new Memory MCP server
+func New(memoryFile string) *Server {
server := mcp.NewServer("mcp-memory", "1.0.0")
- memoryServer := &MemoryServer{
+ memoryServer := &Server{
Server: server,
memoryFile: memoryFile,
graph: &KnowledgeGraph{
@@ -61,7 +61,7 @@ func NewMemoryServer(memoryFile string) *MemoryServer {
}
// registerTools registers all Memory tools with the server
-func (ms *MemoryServer) registerTools() {
+func (ms *Server) registerTools() {
ms.RegisterTool("create_entities", ms.HandleCreateEntities)
ms.RegisterTool("create_relations", ms.HandleCreateRelations)
ms.RegisterTool("add_observations", ms.HandleAddObservations)
@@ -74,7 +74,7 @@ func (ms *MemoryServer) registerTools() {
}
// ListTools returns all available Memory tools
-func (ms *MemoryServer) ListTools() []mcp.Tool {
+func (ms *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "create_entities",
@@ -293,7 +293,7 @@ func (ms *MemoryServer) ListTools() []mcp.Tool {
// Tool handlers
-func (ms *MemoryServer) HandleCreateEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleCreateEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -364,7 +364,7 @@ func (ms *MemoryServer) HandleCreateEntities(req mcp.CallToolRequest) (mcp.CallT
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleCreateRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleCreateRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -433,7 +433,7 @@ func (ms *MemoryServer) HandleCreateRelations(req mcp.CallToolRequest) (mcp.Call
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleAddObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleAddObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -498,7 +498,7 @@ func (ms *MemoryServer) HandleAddObservations(req mcp.CallToolRequest) (mcp.Call
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleDeleteEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleDeleteEntities(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -543,7 +543,7 @@ func (ms *MemoryServer) HandleDeleteEntities(req mcp.CallToolRequest) (mcp.CallT
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleDeleteObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleDeleteObservations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -615,7 +615,7 @@ func (ms *MemoryServer) HandleDeleteObservations(req mcp.CallToolRequest) (mcp.C
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleDeleteRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleDeleteRelations(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.Lock()
defer ms.mu.Unlock()
@@ -671,7 +671,7 @@ func (ms *MemoryServer) HandleDeleteRelations(req mcp.CallToolRequest) (mcp.Call
return mcp.NewToolResult(mcp.NewTextContent(result)), nil
}
-func (ms *MemoryServer) HandleReadGraph(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleReadGraph(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
@@ -684,7 +684,7 @@ func (ms *MemoryServer) HandleReadGraph(req mcp.CallToolRequest) (mcp.CallToolRe
return mcp.NewToolResult(mcp.NewTextContent(string(graphJSON))), nil
}
-func (ms *MemoryServer) HandleSearchNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleSearchNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
@@ -733,7 +733,7 @@ func (ms *MemoryServer) HandleSearchNodes(req mcp.CallToolRequest) (mcp.CallTool
return mcp.NewToolResult(mcp.NewTextContent(string(resultJSON))), nil
}
-func (ms *MemoryServer) HandleOpenNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (ms *Server) HandleOpenNodes(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
ms.mu.RLock()
defer ms.mu.RUnlock()
@@ -775,7 +775,7 @@ func (ms *MemoryServer) HandleOpenNodes(req mcp.CallToolRequest) (mcp.CallToolRe
// Helper methods
-func (ms *MemoryServer) loadGraph() error {
+func (ms *Server) loadGraph() error {
if _, err := os.Stat(ms.memoryFile); os.IsNotExist(err) {
// File doesn't exist, start with empty graph
return nil
@@ -794,7 +794,7 @@ func (ms *MemoryServer) loadGraph() error {
return json.Unmarshal(data, ms.graph)
}
-func (ms *MemoryServer) saveGraph() error {
+func (ms *Server) saveGraph() error {
data, err := json.MarshalIndent(ms.graph, "", " ")
if err != nil {
return err
cmd/memory/server_test.go โ pkg/memoryserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package memoryserver
import (
"path/filepath"
@@ -13,7 +13,7 @@ func TestMemoryServer_CreateEntities(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
req := mcp.CallToolRequest{
Name: "create_entities",
@@ -62,7 +62,7 @@ func TestMemoryServer_CreateRelations(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// First create entities
createReq := mcp.CallToolRequest{
@@ -123,7 +123,7 @@ func TestMemoryServer_AddObservations(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// First create entity
createReq := mcp.CallToolRequest{
@@ -178,7 +178,7 @@ func TestMemoryServer_ReadGraph(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// Create some test data
createReq := mcp.CallToolRequest{
@@ -234,7 +234,7 @@ func TestMemoryServer_SearchNodes(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// Create test entities
createReq := mcp.CallToolRequest{
@@ -294,7 +294,7 @@ func TestMemoryServer_OpenNodes(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// Create test entities
createReq := mcp.CallToolRequest{
@@ -354,7 +354,7 @@ func TestMemoryServer_DeleteEntities(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// Create test entity
createReq := mcp.CallToolRequest{
@@ -407,7 +407,7 @@ func TestMemoryServer_DeleteObservations(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
// Create entity with observations
createReq := mcp.CallToolRequest{
@@ -469,7 +469,7 @@ func TestMemoryServer_ListTools(t *testing.T) {
tempDir := t.TempDir()
memoryFile := filepath.Join(tempDir, "test_memory.json")
- server := NewMemoryServer(memoryFile)
+ server := New(memoryFile)
tools := server.ListTools()
expectedTools := []string{
@@ -505,7 +505,7 @@ func TestMemoryServer_Persistence(t *testing.T) {
memoryFile := filepath.Join(tempDir, "test_memory.json")
// Create first server instance and add data
- server1 := NewMemoryServer(memoryFile)
+ server1 := New(memoryFile)
createReq := mcp.CallToolRequest{
Name: "create_entities",
@@ -522,7 +522,7 @@ func TestMemoryServer_Persistence(t *testing.T) {
server1.HandleCreateEntities(createReq)
// Create second server instance (should load from file)
- server2 := NewMemoryServer(memoryFile)
+ server2 := New(memoryFile)
readReq := mcp.CallToolRequest{
Name: "read_graph",
cmd/sequential-thinking/server.go โ pkg/thinkingserver/server.go
@@ -1,4 +1,4 @@
-package main
+package thinkingserver
import (
"encoding/json"
@@ -9,8 +9,8 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-// SequentialThinkingServer implements the Sequential Thinking MCP server
-type SequentialThinkingServer struct {
+// Server implements the Sequential Thinking MCP server
+type Server struct {
*mcp.Server
}
@@ -43,11 +43,11 @@ type ThinkingResponse struct {
Solution string `json:"solution,omitempty"`
}
-// NewSequentialThinkingServer creates a new Sequential Thinking MCP server
-func NewSequentialThinkingServer() *SequentialThinkingServer {
+// New creates a new Sequential Thinking MCP server
+func New() *Server {
server := mcp.NewServer("mcp-sequential-thinking", "1.0.0")
- thinkingServer := &SequentialThinkingServer{
+ thinkingServer := &Server{
Server: server,
}
@@ -58,12 +58,12 @@ func NewSequentialThinkingServer() *SequentialThinkingServer {
}
// registerTools registers all Sequential Thinking tools with the server
-func (sts *SequentialThinkingServer) registerTools() {
+func (sts *Server) registerTools() {
sts.RegisterTool("sequentialthinking", sts.HandleSequentialThinking)
}
// ListTools returns all available Sequential Thinking tools
-func (sts *SequentialThinkingServer) ListTools() []mcp.Tool {
+func (sts *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "sequentialthinking",
@@ -122,7 +122,7 @@ func (sts *SequentialThinkingServer) ListTools() []mcp.Tool {
// Tool handlers
-func (sts *SequentialThinkingServer) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+func (sts *Server) HandleSequentialThinking(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
// Parse input parameters
thought, ok := req.Arguments["thought"].(string)
if !ok {
@@ -265,7 +265,7 @@ func (sts *SequentialThinkingServer) HandleSequentialThinking(req mcp.CallToolRe
// Helper methods
-func (sts *SequentialThinkingServer) extractSolution(finalThought string) string {
+func (sts *Server) extractSolution(finalThought string) string {
// Simple heuristic to extract a solution from the final thought
content := strings.ToLower(finalThought)
@@ -318,7 +318,7 @@ func (sts *SequentialThinkingServer) extractSolution(finalThought string) string
return "Solution extracted from final thought"
}
-func (sts *SequentialThinkingServer) formatThinkingResult(response ThinkingResponse, thought Thought, contextInfo []string) string {
+func (sts *Server) formatThinkingResult(response ThinkingResponse, thought Thought, contextInfo []string) string {
var result strings.Builder
// Header
@@ -368,7 +368,7 @@ func (sts *SequentialThinkingServer) formatThinkingResult(response ThinkingRespo
return result.String()
}
-func (sts *SequentialThinkingServer) createProgressBar(current, total int) string {
+func (sts *Server) createProgressBar(current, total int) string {
if total <= 0 {
return "[โโโโโโโโโโโโโโโโโโโโ] 100%"
}
cmd/sequential-thinking/server_test.go โ pkg/thinkingserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package thinkingserver
import (
"strings"
@@ -7,8 +7,8 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-func TestSequentialThinkingServer_BasicThinking(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_BasicThinking(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -51,8 +51,8 @@ func TestSequentialThinkingServer_BasicThinking(t *testing.T) {
}
}
-func TestSequentialThinkingServer_CompletedThinking(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_CompletedThinking(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -95,8 +95,8 @@ func TestSequentialThinkingServer_CompletedThinking(t *testing.T) {
}
}
-func TestSequentialThinkingServer_RevisionThinking(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_RevisionThinking(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -136,8 +136,8 @@ func TestSequentialThinkingServer_RevisionThinking(t *testing.T) {
}
}
-func TestSequentialThinkingServer_BranchThinking(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_BranchThinking(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -176,8 +176,8 @@ func TestSequentialThinkingServer_BranchThinking(t *testing.T) {
}
}
-func TestSequentialThinkingServer_NeedsMoreThoughts(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_NeedsMoreThoughts(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -216,8 +216,8 @@ func TestSequentialThinkingServer_NeedsMoreThoughts(t *testing.T) {
}
}
-func TestSequentialThinkingServer_MissingRequiredParams(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_MissingRequiredParams(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -246,8 +246,8 @@ func TestSequentialThinkingServer_MissingRequiredParams(t *testing.T) {
}
}
-func TestSequentialThinkingServer_InvalidParams(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_InvalidParams(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "sequentialthinking",
@@ -278,8 +278,8 @@ func TestSequentialThinkingServer_InvalidParams(t *testing.T) {
}
}
-func TestSequentialThinkingServer_SolutionExtraction(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_SolutionExtraction(t *testing.T) {
+ server := New()
// Test with explicit solution keyword
req := mcp.CallToolRequest{
@@ -308,8 +308,8 @@ func TestSequentialThinkingServer_SolutionExtraction(t *testing.T) {
}
}
-func TestSequentialThinkingServer_ListTools(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_ListTools(t *testing.T) {
+ server := New()
tools := server.ListTools()
expectedTools := []string{
@@ -346,8 +346,8 @@ func TestSequentialThinkingServer_ListTools(t *testing.T) {
}
}
-func TestSequentialThinkingServer_ProgressBar(t *testing.T) {
- server := NewSequentialThinkingServer()
+func TestServer_ProgressBar(t *testing.T) {
+ server := New()
// Test progress bar creation
progressBar := server.createProgressBar(3, 10)
cmd/time/server.go โ pkg/timeserver/server.go
@@ -1,4 +1,4 @@
-package main
+package timeserver
import (
"encoding/json"
@@ -10,8 +10,8 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-// TimeServer implements the Time MCP server
-type TimeServer struct {
+// Server implements the Time MCP server
+type Server struct {
*mcp.Server
localTimezone string
}
@@ -30,14 +30,14 @@ type TimeConversionResult struct {
TimeDifference string `json:"time_difference"`
}
-// NewTimeServer creates a new Time MCP server
-func NewTimeServer() *TimeServer {
+// New creates a new Time MCP server
+func New() *Server {
server := mcp.NewServer("mcp-time", "1.0.0")
// Get local timezone
localTZ := getLocalTimezone()
- timeServer := &TimeServer{
+ timeServer := &Server{
Server: server,
localTimezone: localTZ,
}
@@ -49,13 +49,13 @@ func NewTimeServer() *TimeServer {
}
// registerTools registers all Time tools with the server
-func (ts *TimeServer) registerTools() {
+func (ts *Server) registerTools() {
ts.RegisterTool("get_current_time", ts.HandleGetCurrentTime)
ts.RegisterTool("convert_time", ts.HandleConvertTime)
}
// ListTools returns all available Time tools
-func (ts *TimeServer) ListTools() []mcp.Tool {
+func (ts *Server) ListTools() []mcp.Tool {
return []mcp.Tool{
{
Name: "get_current_time",
@@ -98,7 +98,7 @@ func (ts *TimeServer) ListTools() []mcp.Tool {
// Tool handlers
-func (ts *TimeServer) HandleGetCurrentTime(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+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
@@ -117,7 +117,7 @@ func (ts *TimeServer) HandleGetCurrentTime(req mcp.CallToolRequest) (mcp.CallToo
return mcp.NewToolResult(mcp.NewTextContent(string(jsonResult))), nil
}
-func (ts *TimeServer) HandleConvertTime(req mcp.CallToolRequest) (mcp.CallToolResult, error) {
+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
@@ -148,7 +148,7 @@ func (ts *TimeServer) HandleConvertTime(req mcp.CallToolRequest) (mcp.CallToolRe
// Helper methods
-func (ts *TimeServer) getCurrentTime(timezone string) (*TimeResult, error) {
+func (ts *Server) getCurrentTime(timezone string) (*TimeResult, error) {
loc, err := time.LoadLocation(timezone)
if err != nil {
return nil, fmt.Errorf("Invalid timezone: %v", err)
@@ -163,7 +163,7 @@ func (ts *TimeServer) getCurrentTime(timezone string) (*TimeResult, error) {
}, nil
}
-func (ts *TimeServer) convertTime(sourceTimezone, timeStr, targetTimezone string) (*TimeConversionResult, error) {
+func (ts *Server) convertTime(sourceTimezone, timeStr, targetTimezone string) (*TimeConversionResult, error) {
sourceLoc, err := time.LoadLocation(sourceTimezone)
if err != nil {
return nil, fmt.Errorf("Invalid source timezone: %v", err)
cmd/time/server_test.go โ pkg/timeserver/server_test.go
@@ -1,4 +1,4 @@
-package main
+package timeserver
import (
"strings"
@@ -7,8 +7,8 @@ import (
"github.com/xlgmokha/mcp/pkg/mcp"
)
-func TestTimeServer_GetCurrentTime(t *testing.T) {
- server := NewTimeServer()
+func TestServer_GetCurrentTime(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "get_current_time",
@@ -41,8 +41,8 @@ func TestTimeServer_GetCurrentTime(t *testing.T) {
}
}
-func TestTimeServer_ConvertTime(t *testing.T) {
- server := NewTimeServer()
+func TestServer_ConvertTime(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "convert_time",
@@ -81,8 +81,8 @@ func TestTimeServer_ConvertTime(t *testing.T) {
}
}
-func TestTimeServer_InvalidTimezone(t *testing.T) {
- server := NewTimeServer()
+func TestServer_InvalidTimezone(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "get_current_time",
@@ -110,8 +110,8 @@ func TestTimeServer_InvalidTimezone(t *testing.T) {
}
}
-func TestTimeServer_InvalidTimeFormat(t *testing.T) {
- server := NewTimeServer()
+func TestServer_InvalidTimeFormat(t *testing.T) {
+ server := New()
req := mcp.CallToolRequest{
Name: "convert_time",
@@ -141,8 +141,8 @@ func TestTimeServer_InvalidTimeFormat(t *testing.T) {
}
}
-func TestTimeServer_ListTools(t *testing.T) {
- server := NewTimeServer()
+func TestServer_ListTools(t *testing.T) {
+ server := New()
tools := server.ListTools()
expectedTools := []string{
@@ -166,8 +166,8 @@ func TestTimeServer_ListTools(t *testing.T) {
}
}
-func TestTimeServer_ConvertTimeWithDST(t *testing.T) {
- server := NewTimeServer()
+func TestServer_ConvertTimeWithDST(t *testing.T) {
+ server := New()
// Test during daylight saving time period
req := mcp.CallToolRequest{
Makefile
@@ -23,7 +23,7 @@ all: build ## Build all servers
build: $(BINARIES) ## Build all MCP servers
-$(BINDIR)/mcp-%: cmd/%/main.go cmd/%/server.go
+$(BINDIR)/mcp-%: cmd/%/main.go
@mkdir -p $(BINDIR)
$(GOBUILD) $(BUILD_FLAGS) -o $@ ./cmd/$*
README.md
@@ -7,11 +7,11 @@ A pure Go implementation of Model Context Protocol (MCP) servers, providing drop
## Features
-- =๏ฟฝ **Zero Dependencies**: Statically linked binaries with no runtime dependencies
+- =๏ฟฝ **Zero Dependencies**: Statically linked binaries with no runtime dependencies
- =' **Drop-in Replacement**: Compatible with existing Python MCP server configurations
-- >๏ฟฝ **Test-Driven Development**: Comprehensive test coverage for all servers
+- >๏ฟฝ **Test-Driven Development**: Comprehensive test coverage for all servers
- = **Security First**: Built-in access controls and validation
-- ๏ฟฝ **High Performance**: Native Go performance and concurrency
+- ๏ฟฝ **High Performance**: Native Go performance and concurrency
## Available Servers
@@ -231,14 +231,21 @@ go test ./cmd/git/...
## Architecture
-The project follows a clean architecture with:
-
-- **`pkg/mcp/`**: Core MCP protocol implementation
-- **`cmd/*/`**: Individual MCP server implementations
+The project follows a clean, modular architecture with:
+
+- **`pkg/mcp/`**: Core MCP protocol implementation and shared utilities
+- **`pkg/*/`**: Individual MCP server implementations (reusable packages)
+ - `pkg/gitserver/`: Git operations server
+ - `pkg/fsserver/`: Filesystem operations server
+ - `pkg/fetchserver/`: Web content fetching server
+ - `pkg/memoryserver/`: Knowledge graph memory server
+ - `pkg/thinkingserver/`: Sequential thinking server
+ - `pkg/timeserver/`: Time and timezone server
+- **`cmd/*/`**: Minimal CLI entry points (thin wrappers around packages)
- **Standard Go project layout** with clear separation of concerns
- **Test-driven development** ensuring reliability
-Each server is a standalone binary that communicates via JSON-RPC over stdin/stdout, following the MCP specification.
+Each server is a standalone binary that communicates via JSON-RPC over stdin/stdout, following the MCP specification. The modular package structure allows for easy reuse and testing of server implementations.
## Performance