# 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 | 
73 |
74 |
75 | ## Example
76 |
77 | 
78 | 
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 |
```