#
tokens: 9277/50000 12/12 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── app
│   ├── client
│   │   └── mongo.go
│   ├── configs
│   │   └── config.go
│   ├── mcp.go
│   ├── model
│   │   ├── document.go
│   │   └── index.go
│   └── tools
│       ├── collection.go
│       ├── document.go
│       ├── idgen.go
│       └── index.go
├── config.yml.example
├── Dockerfile
├── go.mod
├── go.sum
├── image
│   ├── img-1.png
│   ├── img-2.png
│   └── img.png
├── README.md
└── server.go
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # configuration file for Go projects
 2 | config.yml
 3 | 
 4 | # Binaries for programs and plugins
 5 | 
 6 | *.exe
 7 | *.exe~
 8 | *.dll
 9 | *.so
10 | *.dylib
11 | 
12 | # Test binary, built with `go test -c`
13 | *.test
14 | 
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 | 
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 | 
21 | # Go workspace file
22 | go.work
23 | go.work.sum
24 | 
25 | # env file
26 | .env
27 | 
28 | # Local configuration files
29 | *.local
30 | 
31 | # IDEs and editors
32 | # JetBrains IDEs
33 | .idea/
34 | # Visual Studio Code
35 | .vscode/
36 | # Visual Studio Code workspace
37 | .code-workspace
38 | 
39 | # MACOS
40 | # macOS Finder directory attributes
41 | .DS_Store
42 | # macOS Finder directory attributes
43 | .AppleDouble
44 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # MongoDB MCP Server
 2 | 
 3 | A Model Context Protocol (MCP) server that enables LLMs to connect MongoDB using [mcp-go](https://github.com/mark3labs/mcp-go). The server acts as a bridge between the LLM and the MongoDB database, allowing you to perform CRUD operations using natural language.
 4 | 
 5 | ## Features
 6 | 
 7 | - **MongoDB action**: Query Collection, Document and Index
 8 | - **SSE Support**: Run MCP Server using Server-Sent Events (SSE)
 9 | 
10 | ## Available Tools
11 | 
12 | ### Query Tools
13 | 
14 | - find: Query documents with filtering and projection
15 | - Count: Count documents in a collection
16 | - listCollections: List available collections
17 | - insertOne: Insert a single document
18 | - updateOne: Update a single document
19 | - deleteOne: Delete a single document
20 | 
21 | ### Index Tools
22 | - createIndex: Create a new index
23 | - dropIndex: Remove an index
24 | - indexes: List indexes for a collection
25 | 
26 | 
27 | ## Configuration
28 | 
29 | > copy the `config.yml.example` file to `config.yml` and modify it according to your needs.
30 | 
31 | The server configuration is managed through the `config.yml` file. Below is an example configuration:
32 | 
33 | ```yaml
34 | mongo:
35 |   host: mongodb
36 |   port: 27017
37 |   user: admin
38 |   password: 123456
39 |   database: db
40 | 
41 | mcp:
42 |   name: mongo-mcp-server
43 |   version: 1.0.0
44 |   base_url: localhost:8081
45 |   address: ":8081"
46 |   sse: true
47 | ```
48 | 
49 | - **MongoDB Configuration**:
50 |     - `host`: MongoDB server host.
51 |     - `port`: MongoDB server port.
52 |     - `user`: MongoDB username.
53 |     - `password`: MongoDB password.
54 |     - `database`: Target MongoDB database.
55 | 
56 | - **MCP Server Configuration**:
57 |     - `name`: Name of the MCP server.
58 |     - `version`: Version of the MCP server.
59 |     - `base_url`: Base URL for the server.
60 |     - `address`: Address and port for the server to listen on.
61 |     - `sse`: Enable or disable SSE support, default is `true`.
62 | 
63 | ## Usage
64 | 
65 | **Start the MCP Server**: Run the server using the following command:
66 | 
67 |  ```bash
68 |  go run main.go
69 |  ```
70 | 
71 | Use in DeepChat
72 | ![img.png](image/img.png)
73 | 
74 | 
75 | ## Example
76 | 
77 | ![find](image/img-1.png)
78 | ![find](image/img-2.png)
79 | 
80 | ## References
81 | 
82 | - [MongoDB Official Documentation](https://www.mongodb.com/zh-cn/docs/languages/go/)
83 | - [mcp-go](https://github.com/mark3labs/mcp-go)
84 | - [mongo-mcp](https://github.com/QuantGeekDev/mongo-mcp)
85 | 
```

--------------------------------------------------------------------------------
/app/model/index.go:
--------------------------------------------------------------------------------

```go
 1 | package model
 2 | 
 3 | type CreateIndexRequest struct {
 4 | 	Collection string                 `mapstructure:"collection" json:"collection"`
 5 | 	IndexSpec  map[string]interface{} `mapstructure:"index_spec" json:"index_spec"`
 6 | }
 7 | type DropIndexRequest struct {
 8 | 	Collection string `mapstructure:"collection" json:"collection"`
 9 | 	IndexName  string `mapstructure:"index_name" json:"index_name"`
10 | }
11 | 
```

--------------------------------------------------------------------------------
/server.go:
--------------------------------------------------------------------------------

```go
 1 | package main
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"github.com/mark3labs/mcp-go/server"
 6 | 	"mcp/app"
 7 | 	"mcp/app/client"
 8 | 	"mcp/app/configs"
 9 | )
10 | 
11 | func main() {
12 | 	// Connect mongo client
13 | 	config := configs.LoadConfig(".", "")
14 | 	client.ConnectMongo(config.Mongo)
15 | 
16 | 	MCPConfig := config.MCP
17 | 
18 | 	// Create a new MCP server
19 | 	s := server.NewMCPServer(
20 | 		MCPConfig.Name,
21 | 		MCPConfig.Version,
22 | 		server.WithResourceCapabilities(true, true),
23 | 		server.WithLogging(),
24 | 		server.WithRecovery(),
25 | 	)
26 | 	// 添加工具到 MCP 服务器中
27 | 	app.AddTools(s)
28 | 	// Start the server
29 | 	if MCPConfig.SSE {
30 | 		// SSE server
31 | 		sse := server.NewSSEServer(s, server.WithBaseURL(MCPConfig.BaseUrl))
32 | 		if err := sse.Start(MCPConfig.Address); err != nil {
33 | 			fmt.Printf("Server error: %v\n", err)
34 | 		}
35 | 	} else {
36 | 		// stdio server
37 | 		if err := server.ServeStdio(s); err != nil {
38 | 			fmt.Printf("Server error: %v\n", err)
39 | 		}
40 | 	}
41 | 
42 | }
43 | 
```

--------------------------------------------------------------------------------
/app/client/mongo.go:
--------------------------------------------------------------------------------

```go
 1 | package client
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"go.mongodb.org/mongo-driver/mongo"
 7 | 	"go.mongodb.org/mongo-driver/mongo/options"
 8 | 	"log"
 9 | 	"mcp/app/configs"
10 | )
11 | 
12 | var (
13 | 	DB          *mongo.Database
14 | 	MongoClient *mongo.Client
15 | )
16 | 
17 | // ConnectMongo connects to a MongoDB database using the provided configuration.
18 | func ConnectMongo(config configs.MongoConfig) {
19 | 	host := config.Host
20 | 	port := config.Port
21 | 	user := config.User
22 | 	password := config.Password
23 | 	database := config.Database
24 | 
25 | 	clientOptions := options.Client().ApplyURI(
26 | 		fmt.Sprintf("mongodb://%s:%s@%s:%d", user, password, host, port),
27 | 	)
28 | 	client, err := mongo.Connect(context.TODO(), clientOptions)
29 | 	if err != nil {
30 | 		log.Fatalf("failed to connect to mongodb: %v", err)
31 | 	}
32 | 
33 | 	// Check the connection
34 | 	err = client.Ping(context.TODO(), nil)
35 | 	if err != nil {
36 | 		log.Fatalf("failed to ping to mongodb: %v", err)
37 | 	}
38 | 	log.Println("Connected to MongoDB!")
39 | 
40 | 	// if the database does not exist, MongoDB create it
41 | 	DB = client.Database(database)
42 | 	MongoClient = client
43 | }
44 | 
```

--------------------------------------------------------------------------------
/app/tools/collection.go:
--------------------------------------------------------------------------------

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"github.com/mark3labs/mcp-go/mcp"
 6 | 	"github.com/mark3labs/mcp-go/server"
 7 | 	"go.mongodb.org/mongo-driver/bson"
 8 | 	"mcp/app/client"
 9 | 	"strings"
10 | )
11 | 
12 | type CollectionTool interface {
13 | 	// ListCollections get collections in mongodb
14 | 	ListCollections() (mcp.Tool, server.ToolHandlerFunc)
15 | }
16 | 
17 | type collectionTool struct{}
18 | 
19 | func NewCollectionTool() CollectionTool {
20 | 	return &collectionTool{}
21 | }
22 | 
23 | // ListCollections List all collections in mongodb
24 | func (c collectionTool) ListCollections() (tool mcp.Tool, handler server.ToolHandlerFunc) {
25 | 
26 | 	// MCP Tool
27 | 	tool = mcp.NewTool(
28 | 		"ListCollections",
29 | 		mcp.WithDescription("List all collections in mongodb"),
30 | 	)
31 | 	// handler
32 | 	// request is empty, this tool will return all collections in mongodb
33 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
34 | 		collections, err := client.DB.ListCollectionNames(ctx, bson.D{})
35 | 
36 | 		if err != nil {
37 | 			return mcp.NewToolResultError(err.Error()), nil
38 | 		}
39 | 		if len(collections) == 0 {
40 | 			return mcp.NewToolResultText("No collections found"), nil
41 | 		}
42 | 		result := mcp.NewToolResultText("Collections: " + strings.Join(collections, ", "))
43 | 		return result, nil
44 | 	}
45 | 	return
46 | }
47 | 
```

--------------------------------------------------------------------------------
/app/mcp.go:
--------------------------------------------------------------------------------

```go
 1 | package app
 2 | 
 3 | import (
 4 | 	"github.com/mark3labs/mcp-go/server"
 5 | 	"mcp/app/tools"
 6 | )
 7 | 
 8 | func AddTools(s *server.MCPServer) {
 9 | 	// Add Collection tools to MCP server
10 | 	collTool := tools.NewCollectionTool()
11 | 	AddCollectionTools(s, collTool)
12 | 
13 | 	// Add Document tools to MCP server
14 | 	docTool := tools.NewDocumentTool()
15 | 	AddDocumentTools(s, docTool)
16 | 
17 | 	// Add Index tools to MCP server
18 | 	indexTool := tools.NewIndexTool()
19 | 	AddIndexTools(s, indexTool)
20 | 
21 | 	idGenerateTool := tools.NewIdGenerateTool()
22 | 	AddIdGenerateTools(s, idGenerateTool)
23 | }
24 | 
25 | // AddCollectionTools adds collection tools to the MCP server
26 | func AddCollectionTools(s *server.MCPServer, collTool tools.CollectionTool) {
27 | 	s.AddTool(collTool.ListCollections())
28 | }
29 | 
30 | // AddDocumentTools adds collection tools to the MCP server
31 | func AddDocumentTools(s *server.MCPServer, docTool tools.DocumentTool) {
32 | 	s.AddTool(docTool.Find())
33 | 	s.AddTool(docTool.Count())
34 | 	s.AddTool(docTool.InsertOne())
35 | 	s.AddTool(docTool.DeleteOne())
36 | 	s.AddTool(docTool.UpdateOne())
37 | }
38 | 
39 | // AddIndexTools adds collection tools to the MCP server
40 | func AddIndexTools(s *server.MCPServer, indexTool tools.IndexTool) {
41 | 	s.AddTool(indexTool.CreateIndex())
42 | 	s.AddTool(indexTool.ListIndexes())
43 | 	s.AddTool(indexTool.DropIndex())
44 | }
45 | 
46 | func AddIdGenerateTools(s *server.MCPServer, idGenerateTool tools.IdGenerateTool) {
47 | 	s.AddTool(idGenerateTool.Generate())
48 | }
49 | 
```

--------------------------------------------------------------------------------
/app/model/document.go:
--------------------------------------------------------------------------------

```go
 1 | package model
 2 | 
 3 | type FindDocumentRequest struct {
 4 | 	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
 5 | 	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
 6 | 	Limit      int64                  `mapstructure:"limit" json:"limit" bson:"limit"`
 7 | 	Projection map[string]interface{} `mapstructure:"projection" json:"projection" bson:"projection"`
 8 | }
 9 | 
10 | type CountDocumentRequest struct {
11 | 	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
12 | 	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
13 | 	Limit      int64                  `mapstructure:"limit" json:"limit" bson:"limit"`
14 | }
15 | 
16 | type InsertDocumentRequest struct {
17 | 	Collection string `mapstructure:"collection" json:"collection" bson:"collection"`
18 | 	Document   string `mapstructure:"document" json:"document" bson:"document"`
19 | }
20 | 
21 | type DeleteDocumentRequest struct {
22 | 	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
23 | 	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
24 | }
25 | 
26 | type UpdateDocumentRequest struct {
27 | 	Collection string                 `mapstructure:"collection" json:"collection"`
28 | 	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
29 | 	Update     map[string]interface{} `mapstructure:"update" json:"update" bson:"update"`
30 | }
31 | 
```

--------------------------------------------------------------------------------
/app/configs/config.go:
--------------------------------------------------------------------------------

```go
 1 | package configs
 2 | 
 3 | import (
 4 | 	"github.com/spf13/viper"
 5 | 	"log"
 6 | )
 7 | 
 8 | type MongoConfig struct {
 9 | 	Host     string `mapstructure:"host" json:"host" yaml:"host"`
10 | 	Port     int    `mapstructure:"port" json:"port" yaml:"port"`
11 | 	User     string `mapstructure:"user" json:"user" yaml:"user"`
12 | 	Password string `mapstructure:"password" json:"password" yaml:"password"`
13 | 	Database string `mapstructure:"database" json:"database" yaml:"database"`
14 | }
15 | 
16 | type MCPClient struct {
17 | 	Name    string `mapstructure:"name" json:"name" yaml:"name"`
18 | 	Version string `mapstructure:"version" json:"version" yaml:"version"`
19 | 	BaseUrl string `mapstructure:"base_url" json:"base_url" yaml:"base_url"`
20 | 	Address string `mapstructure:"address" json:"address" yaml:"address"`
21 | 	SSE     bool   `mapstructure:"sse" json:"sse" yaml:"sse"`
22 | }
23 | 
24 | type Config struct {
25 | 	Mongo MongoConfig `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
26 | 	MCP   MCPClient   `mapstructure:"mcp" json:"mcp" yaml:"mcp"`
27 | }
28 | 
29 | func LoadConfig(path string, env string) Config {
30 | 	var Cfg Config
31 | 	viper.AddConfigPath(path)
32 | 	viper.SetConfigName("config")
33 | 	viper.SetConfigType("yaml")
34 | 	viper.AutomaticEnv()
35 | 
36 | 	if err := viper.ReadInConfig(); err != nil {
37 | 		log.Fatalf("Read config error: %v", err)
38 | 	}
39 | 
40 | 	if err := viper.Unmarshal(&Cfg); err != nil {
41 | 		log.Fatalf("Unmarshal config error: %v", err)
42 | 	}
43 | 
44 | 	if env != "" {
45 | 		viper.SetConfigName("config." + env)
46 | 		if err := viper.MergeInConfig(); err != nil {
47 | 			log.Fatalf("Merge config error: %v", err)
48 | 		}
49 | 		if err := viper.Unmarshal(&Cfg); err != nil {
50 | 			log.Fatalf("Unmarshal config error: %v", err)
51 | 		}
52 | 	}
53 | 
54 | 	log.Println("Config loaded successfully")
55 | 	return Cfg
56 | }
57 | 
```

--------------------------------------------------------------------------------
/app/tools/idgen.go:
--------------------------------------------------------------------------------

```go
 1 | package tools
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"github.com/mark3labs/mcp-go/mcp"
 7 | 	"github.com/mark3labs/mcp-go/server"
 8 | 	"go.mongodb.org/mongo-driver/bson"
 9 | 	"go.mongodb.org/mongo-driver/mongo/options"
10 | 	"log"
11 | 	"mcp/app/client"
12 | )
13 | 
14 | type IdGenerateTool interface {
15 | 	Generate() (mcp.Tool, server.ToolHandlerFunc)
16 | }
17 | 
18 | type idGenerateTool struct {
19 | 	EntityPrefixMap map[string]interface{}
20 | }
21 | 
22 | func NewIdGenerateTool() IdGenerateTool {
23 | 	return &idGenerateTool{
24 | 		EntityPrefixMap: map[string]interface{}{
25 | 			"task":       "TSK",
26 | 			"lesson":     "LSN",
27 | 			"course":     "CRS",
28 | 			"experiment": "EXP",
29 | 		},
30 | 	}
31 | }
32 | 
33 | func (i idGenerateTool) Generate() (tool mcp.Tool, handler server.ToolHandlerFunc) {
34 | 
35 | 	var prefixNameSet []string
36 | 	for key := range i.EntityPrefixMap {
37 | 		prefixNameSet = append(prefixNameSet, key)
38 | 	}
39 | 	tool = mcp.NewTool(
40 | 		"entity_id_generator",
41 | 		mcp.WithDescription("generate id for different type entity"),
42 | 		mcp.WithString("entity_type",
43 | 			mcp.Required(),
44 | 			mcp.Description(fmt.Sprintf("type of entity to generate id, it could be one of %s", prefixNameSet)),
45 | 		),
46 | 	)
47 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
48 | 		entityType := request.Params.Arguments["entity_type"].(string)
49 | 		log.Printf("Generate id for entity: %s", entityType)
50 | 		var entityPrefix string
51 | 		if value, ok := i.EntityPrefixMap[entityType]; ok {
52 | 			entityPrefix = value.(string)
53 | 			//return mcp.NewToolResultText(prefix.(string) + "-" + mcp.GenerateId()), nil
54 | 		} else {
55 | 			return mcp.NewToolResultText(fmt.Sprintf("entity type %s not found, please use one of %s", entityType, prefixNameSet)), nil
56 | 		}
57 | 		counterID, err := i.getNextSequence(ctx, entityPrefix)
58 | 		if err != nil {
59 | 			return mcp.NewToolResultText(fmt.Sprintf("failed to get next sequence: %v", err)), nil
60 | 		}
61 | 		return mcp.NewToolResultText(fmt.Sprintf("%s-%04d", entityPrefix, counterID)), nil
62 | 	}
63 | 	return
64 | }
65 | 
66 | func (i idGenerateTool) getNextSequence(ctx context.Context, counterIDType string) (int, error) {
67 | 	filter := bson.M{"id_type": counterIDType}
68 | 	update := bson.M{"$inc": bson.M{"sequence": 1}}
69 | 	opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)
70 | 
71 | 	var result struct {
72 | 		Sequence int `bson:"sequence"`
73 | 	}
74 | 	err := client.DB.Collection("counters").FindOneAndUpdate(ctx, filter, update, opts).Decode(&result)
75 | 	if err != nil {
76 | 		return 0, err
77 | 	}
78 | 
79 | 	return result.Sequence, nil
80 | }
81 | 
```

--------------------------------------------------------------------------------
/app/tools/index.go:
--------------------------------------------------------------------------------

```go
  1 | package tools
  2 | 
  3 | import (
  4 | 	"context"
  5 | 	"fmt"
  6 | 	"github.com/go-viper/mapstructure/v2"
  7 | 	"github.com/mark3labs/mcp-go/mcp"
  8 | 	"github.com/mark3labs/mcp-go/server"
  9 | 	"go.mongodb.org/mongo-driver/bson"
 10 | 	"go.mongodb.org/mongo-driver/mongo"
 11 | 	"mcp/app/client"
 12 | 	"mcp/app/model"
 13 | )
 14 | 
 15 | type IndexTool interface {
 16 | 	// ListIndexes get indexes in mongodb
 17 | 	ListIndexes() (mcp.Tool, server.ToolHandlerFunc)
 18 | 	// CreateIndex create index in mongodb
 19 | 	CreateIndex() (mcp.Tool, server.ToolHandlerFunc)
 20 | 	// DropIndex drop index in mongodb
 21 | 	DropIndex() (mcp.Tool, server.ToolHandlerFunc)
 22 | }
 23 | 
 24 | type indexTool struct{}
 25 | 
 26 | func NewIndexTool() IndexTool {
 27 | 	return &indexTool{}
 28 | }
 29 | 
 30 | // ListIndexes List all indexes in mongodb
 31 | func (c indexTool) ListIndexes() (tool mcp.Tool, handler server.ToolHandlerFunc) {
 32 | 
 33 | 	// MCP Tool
 34 | 	tool = mcp.NewTool(
 35 | 		"ListIndexes",
 36 | 		mcp.WithDescription("List all indexes in mongodb"),
 37 | 		mcp.WithString("collection",
 38 | 			mcp.Required(),
 39 | 			mcp.Description("Collection name"),
 40 | 		),
 41 | 	)
 42 | 	// handler
 43 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 44 | 		collectionName := request.Params.Arguments["collection"].(string)
 45 | 		cur, err := client.DB.Collection(collectionName).Indexes().List(ctx)
 46 | 		if err != nil {
 47 | 			return mcp.NewToolResultText(err.Error()), err
 48 | 		}
 49 | 		defer cur.Close(ctx)
 50 | 
 51 | 		var indexes []bson.M
 52 | 		if err = cur.All(ctx, &indexes); err != nil {
 53 | 			return mcp.NewToolResultText(err.Error()), err
 54 | 		}
 55 | 		var result string
 56 | 		for _, doc := range indexes {
 57 | 			result += fmt.Sprintf("%v\n", doc)
 58 | 		}
 59 | 		return mcp.NewToolResultText(result), nil
 60 | 
 61 | 	}
 62 | 	return
 63 | }
 64 | 
 65 | // CreateIndex create index in mongodb
 66 | func (c indexTool) CreateIndex() (tool mcp.Tool, handler server.ToolHandlerFunc) {
 67 | 
 68 | 	// MCP Tool
 69 | 	tool = mcp.NewTool(
 70 | 		"CreateIndex",
 71 | 		mcp.WithDescription("create index in mongodb"),
 72 | 		mcp.WithString("collection",
 73 | 			mcp.Required(),
 74 | 			mcp.Description("Collection name"),
 75 | 		),
 76 | 		mcp.WithObject("index_spec",
 77 | 			mcp.Required(),
 78 | 			mcp.Description("Index specification (e.g., { field: 1 } for ascending index)"),
 79 | 		),
 80 | 	)
 81 | 	// handler
 82 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 83 | 		var req model.CreateIndexRequest
 84 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
 85 | 
 86 | 		if err != nil {
 87 | 			return mcp.NewToolResultText(err.Error()), err
 88 | 		}
 89 | 
 90 | 		res, err := client.DB.Collection(req.Collection).Indexes().CreateOne(ctx, mongo.IndexModel{
 91 | 			Keys: req.IndexSpec,
 92 | 		})
 93 | 		if err != nil {
 94 | 			return mcp.NewToolResultText(err.Error()), err
 95 | 		}
 96 | 
 97 | 		return mcp.NewToolResultText(fmt.Sprintf("Index created, Name: %v", res)), nil
 98 | 	}
 99 | 	return
100 | }
101 | 
102 | // DropIndex drop index in mongodb
103 | func (c indexTool) DropIndex() (tool mcp.Tool, handler server.ToolHandlerFunc) {
104 | 
105 | 	// MCP Tool
106 | 	tool = mcp.NewTool(
107 | 		"DropIndex",
108 | 		mcp.WithDescription("drop index in mongodb"),
109 | 		mcp.WithString("collection",
110 | 			mcp.Required(),
111 | 			mcp.Description("Collection name"),
112 | 		),
113 | 		mcp.WithObject("index_name",
114 | 			mcp.Required(),
115 | 			mcp.Description("Name of the index to drop"),
116 | 		),
117 | 	)
118 | 	// handler
119 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
120 | 		var req model.DropIndexRequest
121 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
122 | 
123 | 		if err != nil {
124 | 			return mcp.NewToolResultText(err.Error()), err
125 | 		}
126 | 
127 | 		res, err := client.DB.Collection(req.Collection).Indexes().DropOne(ctx, req.IndexName)
128 | 		if err != nil {
129 | 			return mcp.NewToolResultText(err.Error()), err
130 | 		}
131 | 		return mcp.NewToolResultText(fmt.Sprintf("Index dropped Successfully, result: %v", res)), nil
132 | 	}
133 | 	return
134 | }
135 | 
```

--------------------------------------------------------------------------------
/app/tools/document.go:
--------------------------------------------------------------------------------

```go
  1 | package tools
  2 | 
  3 | import (
  4 | 	"context"
  5 | 	"fmt"
  6 | 	"github.com/go-viper/mapstructure/v2"
  7 | 	"github.com/mark3labs/mcp-go/mcp"
  8 | 	"github.com/mark3labs/mcp-go/server"
  9 | 	"go.mongodb.org/mongo-driver/bson"
 10 | 	"go.mongodb.org/mongo-driver/mongo/options"
 11 | 	"log"
 12 | 	"mcp/app/client"
 13 | 	"mcp/app/model"
 14 | )
 15 | 
 16 | type DocumentTool interface {
 17 | 	// Find get document in collection
 18 | 	Find() (mcp.Tool, server.ToolHandlerFunc)
 19 | 	// Count get documents count in collection
 20 | 	Count() (mcp.Tool, server.ToolHandlerFunc)
 21 | 	// InsertOne insert one document in collection
 22 | 	InsertOne() (mcp.Tool, server.ToolHandlerFunc)
 23 | 	// DeleteOne insert one document in collection
 24 | 	DeleteOne() (mcp.Tool, server.ToolHandlerFunc)
 25 | 	// UpdateOne insert one document in collection
 26 | 	UpdateOne() (mcp.Tool, server.ToolHandlerFunc)
 27 | }
 28 | 
 29 | type documentTool struct{}
 30 | 
 31 | func NewDocumentTool() DocumentTool {
 32 | 	return &documentTool{}
 33 | }
 34 | 
 35 | // Find get document in collection
 36 | func (c documentTool) Find() (tool mcp.Tool, handler server.ToolHandlerFunc) {
 37 | 
 38 | 	// MCP Tool
 39 | 	tool = mcp.NewTool(
 40 | 		"Find",
 41 | 		mcp.WithDescription("Query documents in a collection using MongoDB query syntax"),
 42 | 		mcp.WithString("collection",
 43 | 			mcp.Required(),
 44 | 			mcp.Description("Collection name to query"),
 45 | 		),
 46 | 		mcp.WithObject("filter",
 47 | 			mcp.Description("MongoDB query filter"),
 48 | 			mcp.DefaultString("{}"),
 49 | 		),
 50 | 		mcp.WithNumber("limit",
 51 | 			mcp.Description("Limit the number of documents to return"),
 52 | 			mcp.DefaultNumber(0),
 53 | 			mcp.Min(0),
 54 | 			mcp.Max(1000),
 55 | 		),
 56 | 		mcp.WithObject("projection",
 57 | 			mcp.Description("MongoDB projection filter"),
 58 | 			mcp.DefaultString("{}"),
 59 | 		),
 60 | 	)
 61 | 	// handler
 62 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
 63 | 		var req model.FindDocumentRequest
 64 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
 65 | 		if err != nil {
 66 | 			return mcp.NewToolResultText("Parse request failed"), err
 67 | 		}
 68 | 
 69 | 		log.Printf(fmt.Sprintf("Find document in collection: %s, filter: %s, limit: %d", req.Collection, req.Filter, req.Limit))
 70 | 
 71 | 		cur, err := client.DB.Collection(req.Collection).Find(ctx, req.Filter, &options.FindOptions{
 72 | 			Limit:      &req.Limit,
 73 | 			Projection: req.Projection,
 74 | 		})
 75 | 		defer cur.Close(ctx)
 76 | 
 77 | 		if err != nil {
 78 | 			return mcp.NewToolResultText(err.Error()), err
 79 | 		}
 80 | 
 81 | 		var documents []bson.M
 82 | 		if err = cur.All(ctx, &documents); err != nil {
 83 | 			return mcp.NewToolResultText(err.Error()), err
 84 | 		}
 85 | 		if len(documents) == 0 {
 86 | 			log.Println("No documents found")
 87 | 			return mcp.NewToolResultText("No documents found"), nil
 88 | 		}
 89 | 		var result string
 90 | 		for _, doc := range documents {
 91 | 			result += fmt.Sprintf("%v\n", doc)
 92 | 		}
 93 | 		log.Println(result)
 94 | 		return mcp.NewToolResultText(result), nil
 95 | 	}
 96 | 	return
 97 | }
 98 | 
 99 | // Count get documents count in collection
100 | func (c documentTool) Count() (tool mcp.Tool, handler server.ToolHandlerFunc) {
101 | 
102 | 	// MCP Tool
103 | 	tool = mcp.NewTool(
104 | 		"Count",
105 | 		mcp.WithDescription("Count documents in a collection using MongoDB query syntax"),
106 | 		mcp.WithString("collection",
107 | 			mcp.Required(),
108 | 			mcp.Description("Collection name to query"),
109 | 		),
110 | 		mcp.WithObject("filter",
111 | 			mcp.Description("MongoDB query filter"),
112 | 			mcp.DefaultString("{}"),
113 | 		),
114 | 		mcp.WithObject("projection",
115 | 			mcp.Description("MongoDB projection filter"),
116 | 			mcp.DefaultString("{}"),
117 | 		),
118 | 	)
119 | 	// handler
120 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
121 | 		var req model.CountDocumentRequest
122 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
123 | 		if err != nil {
124 | 			return mcp.NewToolResultText("Parse request failed"), err
125 | 		}
126 | 
127 | 		log.Printf(fmt.Sprintf("Count document in collection: %s, filter: %s", req.Collection, req.Filter))
128 | 
129 | 		count, err := client.DB.Collection(req.Collection).CountDocuments(ctx, req.Filter)
130 | 		if err != nil {
131 | 			return mcp.NewToolResultText(err.Error()), err
132 | 		}
133 | 		log.Printf(fmt.Sprintf("Count documents success, count: %d", count))
134 | 		return mcp.NewToolResultText(fmt.Sprintf("Count documents success, count: %d", count)), nil
135 | 	}
136 | 	return
137 | }
138 | 
139 | // InsertOne insert one document in collection
140 | func (c documentTool) InsertOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
141 | 	// MCP Tool
142 | 	tool = mcp.NewTool(
143 | 		"InertOne",
144 | 		mcp.WithDescription("Insert a single document into a collection"),
145 | 		mcp.WithString("collection",
146 | 			mcp.Required(),
147 | 			mcp.Description("Collection name to insert"),
148 | 		),
149 | 		mcp.WithString("document",
150 | 			mcp.Required(),
151 | 			mcp.Description("document to insert"),
152 | 			mcp.DefaultString("{}"),
153 | 		),
154 | 	)
155 | 	// handler
156 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
157 | 		var req model.InsertDocumentRequest
158 | 
159 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
160 | 		if err != nil {
161 | 			return mcp.NewToolResultText("Parse request failed"), err
162 | 		}
163 | 
164 | 		log.Printf(fmt.Sprintf("Insert document in collection: %s, document: %s", req.Collection, req.Document))
165 | 
166 | 		// Convert the document string to a BSON document
167 | 		var document bson.M
168 | 		err = bson.UnmarshalExtJSON([]byte(req.Document), true, &document)
169 | 		if err != nil {
170 | 			return mcp.NewToolResultText("Parse document failed"), err
171 | 		}
172 | 		res, err := client.DB.Collection(req.Collection).InsertOne(ctx, document)
173 | 		if err != nil {
174 | 			return mcp.NewToolResultText(err.Error()), err
175 | 		}
176 | 
177 | 		if res.InsertedID == nil {
178 | 			return mcp.NewToolResultText("Insert document failed"), nil
179 | 		}
180 | 		return mcp.NewToolResultText(fmt.Sprintf("Insert document success, id: %v", res.InsertedID)), nil
181 | 	}
182 | 	return
183 | }
184 | 
185 | // DeleteOne insert one document in collection
186 | func (c documentTool) DeleteOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
187 | 	// MCP Tool
188 | 	tool = mcp.NewTool(
189 | 		"DeleteOne",
190 | 		mcp.WithDescription("Delete a single document into a collection"),
191 | 		mcp.WithString("collection",
192 | 			mcp.Required(),
193 | 			mcp.Description("Collection name to delete"),
194 | 		),
195 | 		mcp.WithObject("filter",
196 | 			mcp.Required(),
197 | 			mcp.Description("Filter to identify document"),
198 | 		),
199 | 	)
200 | 	// handler
201 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
202 | 		var req model.DeleteDocumentRequest
203 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
204 | 		if err != nil {
205 | 			return mcp.NewToolResultText("Parse request failed"), err
206 | 		}
207 | 
208 | 		log.Printf(fmt.Sprintf("Delete document in collection: %s, filter: %s", req.Collection, req.Filter))
209 | 
210 | 		res, err := client.DB.Collection(req.Collection).DeleteOne(ctx, req.Filter)
211 | 		if err != nil {
212 | 			return mcp.NewToolResultText(err.Error()), err
213 | 		}
214 | 		if res.DeletedCount == 0 {
215 | 			return mcp.NewToolResultText("No documents deleted"), nil
216 | 		}
217 | 		return mcp.NewToolResultText(fmt.Sprintf("Delete document success, deleted count: %d", res.DeletedCount)), nil
218 | 	}
219 | 	return
220 | }
221 | 
222 | // UpdateOne insert one document in collection
223 | func (c documentTool) UpdateOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
224 | 	// MCP Tool
225 | 	tool = mcp.NewTool(
226 | 		"UpdateOne",
227 | 		mcp.WithDescription("update a single document into a collection"),
228 | 		mcp.WithString("collection",
229 | 			mcp.Required(),
230 | 			mcp.Description("Collection name to update"),
231 | 		),
232 | 		mcp.WithObject("filter",
233 | 			mcp.Required(),
234 | 			mcp.Description("Filter to identify document"),
235 | 		),
236 | 		mcp.WithObject("update",
237 | 			mcp.Required(),
238 | 			mcp.Description("Update operations to apply"),
239 | 		),
240 | 	)
241 | 	// handler
242 | 	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
243 | 		var req model.UpdateDocumentRequest
244 | 		err := mapstructure.Decode(request.Params.Arguments, &req)
245 | 		if err != nil {
246 | 			return mcp.NewToolResultText("Parse request failed"), err
247 | 		}
248 | 		fmt.Println(req)
249 | 
250 | 		log.Printf(fmt.Sprintf("Update document in collection: %s, filter: %s", req.Collection, req.Filter))
251 | 
252 | 		res, err := client.DB.Collection(req.Collection).UpdateOne(ctx, req.Filter, req.Update)
253 | 		if err != nil {
254 | 			return mcp.NewToolResultText(err.Error()), err
255 | 		}
256 | 		if res.MatchedCount == 0 {
257 | 			return mcp.NewToolResultText("No documents matched"), nil
258 | 		}
259 | 		if res.ModifiedCount == 0 {
260 | 			return mcp.NewToolResultText("No documents updated"), nil
261 | 		}
262 | 		return mcp.NewToolResultText(
263 | 			fmt.Sprintf("Update document success, matched count: %d, modified count: %d, upsertedId %d",
264 | 				res.MatchedCount, res.ModifiedCount, res.UpsertedID,
265 | 			),
266 | 		), nil
267 | 	}
268 | 	return
269 | }
270 | 
```