#
tokens: 6783/50000 12/12 files
lines: off (toggle) GitHub
raw markdown copy
# 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:
--------------------------------------------------------------------------------

```
# configuration file for Go projects
config.yml

# Binaries for programs and plugins

*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
go.work.sum

# env file
.env

# Local configuration files
*.local

# IDEs and editors
# JetBrains IDEs
.idea/
# Visual Studio Code
.vscode/
# Visual Studio Code workspace
.code-workspace

# MACOS
# macOS Finder directory attributes
.DS_Store
# macOS Finder directory attributes
.AppleDouble

```

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

```markdown
# MongoDB MCP Server

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.

## Features

- **MongoDB action**: Query Collection, Document and Index
- **SSE Support**: Run MCP Server using Server-Sent Events (SSE)

## Available Tools

### Query Tools

- find: Query documents with filtering and projection
- Count: Count documents in a collection
- listCollections: List available collections
- insertOne: Insert a single document
- updateOne: Update a single document
- deleteOne: Delete a single document

### Index Tools
- createIndex: Create a new index
- dropIndex: Remove an index
- indexes: List indexes for a collection


## Configuration

> copy the `config.yml.example` file to `config.yml` and modify it according to your needs.

The server configuration is managed through the `config.yml` file. Below is an example configuration:

```yaml
mongo:
  host: mongodb
  port: 27017
  user: admin
  password: 123456
  database: db

mcp:
  name: mongo-mcp-server
  version: 1.0.0
  base_url: localhost:8081
  address: ":8081"
  sse: true
```

- **MongoDB Configuration**:
    - `host`: MongoDB server host.
    - `port`: MongoDB server port.
    - `user`: MongoDB username.
    - `password`: MongoDB password.
    - `database`: Target MongoDB database.

- **MCP Server Configuration**:
    - `name`: Name of the MCP server.
    - `version`: Version of the MCP server.
    - `base_url`: Base URL for the server.
    - `address`: Address and port for the server to listen on.
    - `sse`: Enable or disable SSE support, default is `true`.

## Usage

**Start the MCP Server**: Run the server using the following command:

 ```bash
 go run main.go
 ```

Use in DeepChat
![img.png](image/img.png)


## Example

![find](image/img-1.png)
![find](image/img-2.png)

## References

- [MongoDB Official Documentation](https://www.mongodb.com/zh-cn/docs/languages/go/)
- [mcp-go](https://github.com/mark3labs/mcp-go)
- [mongo-mcp](https://github.com/QuantGeekDev/mongo-mcp)

```

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

```go
package model

type CreateIndexRequest struct {
	Collection string                 `mapstructure:"collection" json:"collection"`
	IndexSpec  map[string]interface{} `mapstructure:"index_spec" json:"index_spec"`
}
type DropIndexRequest struct {
	Collection string `mapstructure:"collection" json:"collection"`
	IndexName  string `mapstructure:"index_name" json:"index_name"`
}

```

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

```go
package main

import (
	"fmt"
	"github.com/mark3labs/mcp-go/server"
	"mcp/app"
	"mcp/app/client"
	"mcp/app/configs"
)

func main() {
	// Connect mongo client
	config := configs.LoadConfig(".", "")
	client.ConnectMongo(config.Mongo)

	MCPConfig := config.MCP

	// Create a new MCP server
	s := server.NewMCPServer(
		MCPConfig.Name,
		MCPConfig.Version,
		server.WithResourceCapabilities(true, true),
		server.WithLogging(),
		server.WithRecovery(),
	)
	// 添加工具到 MCP 服务器中
	app.AddTools(s)
	// Start the server
	if MCPConfig.SSE {
		// SSE server
		sse := server.NewSSEServer(s, server.WithBaseURL(MCPConfig.BaseUrl))
		if err := sse.Start(MCPConfig.Address); err != nil {
			fmt.Printf("Server error: %v\n", err)
		}
	} else {
		// stdio server
		if err := server.ServeStdio(s); err != nil {
			fmt.Printf("Server error: %v\n", err)
		}
	}

}

```

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

```go
package client

import (
	"context"
	"fmt"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"mcp/app/configs"
)

var (
	DB          *mongo.Database
	MongoClient *mongo.Client
)

// ConnectMongo connects to a MongoDB database using the provided configuration.
func ConnectMongo(config configs.MongoConfig) {
	host := config.Host
	port := config.Port
	user := config.User
	password := config.Password
	database := config.Database

	clientOptions := options.Client().ApplyURI(
		fmt.Sprintf("mongodb://%s:%s@%s:%d", user, password, host, port),
	)
	client, err := mongo.Connect(context.TODO(), clientOptions)
	if err != nil {
		log.Fatalf("failed to connect to mongodb: %v", err)
	}

	// Check the connection
	err = client.Ping(context.TODO(), nil)
	if err != nil {
		log.Fatalf("failed to ping to mongodb: %v", err)
	}
	log.Println("Connected to MongoDB!")

	// if the database does not exist, MongoDB create it
	DB = client.Database(database)
	MongoClient = client
}

```

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

```go
package tools

import (
	"context"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"go.mongodb.org/mongo-driver/bson"
	"mcp/app/client"
	"strings"
)

type CollectionTool interface {
	// ListCollections get collections in mongodb
	ListCollections() (mcp.Tool, server.ToolHandlerFunc)
}

type collectionTool struct{}

func NewCollectionTool() CollectionTool {
	return &collectionTool{}
}

// ListCollections List all collections in mongodb
func (c collectionTool) ListCollections() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"ListCollections",
		mcp.WithDescription("List all collections in mongodb"),
	)
	// handler
	// request is empty, this tool will return all collections in mongodb
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		collections, err := client.DB.ListCollectionNames(ctx, bson.D{})

		if err != nil {
			return mcp.NewToolResultError(err.Error()), nil
		}
		if len(collections) == 0 {
			return mcp.NewToolResultText("No collections found"), nil
		}
		result := mcp.NewToolResultText("Collections: " + strings.Join(collections, ", "))
		return result, nil
	}
	return
}

```

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

```go
package app

import (
	"github.com/mark3labs/mcp-go/server"
	"mcp/app/tools"
)

func AddTools(s *server.MCPServer) {
	// Add Collection tools to MCP server
	collTool := tools.NewCollectionTool()
	AddCollectionTools(s, collTool)

	// Add Document tools to MCP server
	docTool := tools.NewDocumentTool()
	AddDocumentTools(s, docTool)

	// Add Index tools to MCP server
	indexTool := tools.NewIndexTool()
	AddIndexTools(s, indexTool)

	idGenerateTool := tools.NewIdGenerateTool()
	AddIdGenerateTools(s, idGenerateTool)
}

// AddCollectionTools adds collection tools to the MCP server
func AddCollectionTools(s *server.MCPServer, collTool tools.CollectionTool) {
	s.AddTool(collTool.ListCollections())
}

// AddDocumentTools adds collection tools to the MCP server
func AddDocumentTools(s *server.MCPServer, docTool tools.DocumentTool) {
	s.AddTool(docTool.Find())
	s.AddTool(docTool.Count())
	s.AddTool(docTool.InsertOne())
	s.AddTool(docTool.DeleteOne())
	s.AddTool(docTool.UpdateOne())
}

// AddIndexTools adds collection tools to the MCP server
func AddIndexTools(s *server.MCPServer, indexTool tools.IndexTool) {
	s.AddTool(indexTool.CreateIndex())
	s.AddTool(indexTool.ListIndexes())
	s.AddTool(indexTool.DropIndex())
}

func AddIdGenerateTools(s *server.MCPServer, idGenerateTool tools.IdGenerateTool) {
	s.AddTool(idGenerateTool.Generate())
}

```

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

```go
package model

type FindDocumentRequest struct {
	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
	Limit      int64                  `mapstructure:"limit" json:"limit" bson:"limit"`
	Projection map[string]interface{} `mapstructure:"projection" json:"projection" bson:"projection"`
}

type CountDocumentRequest struct {
	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
	Limit      int64                  `mapstructure:"limit" json:"limit" bson:"limit"`
}

type InsertDocumentRequest struct {
	Collection string `mapstructure:"collection" json:"collection" bson:"collection"`
	Document   string `mapstructure:"document" json:"document" bson:"document"`
}

type DeleteDocumentRequest struct {
	Collection string                 `mapstructure:"collection" json:"collection" bson:"collection"`
	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
}

type UpdateDocumentRequest struct {
	Collection string                 `mapstructure:"collection" json:"collection"`
	Filter     map[string]interface{} `mapstructure:"filter" json:"filter" bson:"filter"`
	Update     map[string]interface{} `mapstructure:"update" json:"update" bson:"update"`
}

```

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

```go
package configs

import (
	"github.com/spf13/viper"
	"log"
)

type MongoConfig struct {
	Host     string `mapstructure:"host" json:"host" yaml:"host"`
	Port     int    `mapstructure:"port" json:"port" yaml:"port"`
	User     string `mapstructure:"user" json:"user" yaml:"user"`
	Password string `mapstructure:"password" json:"password" yaml:"password"`
	Database string `mapstructure:"database" json:"database" yaml:"database"`
}

type MCPClient struct {
	Name    string `mapstructure:"name" json:"name" yaml:"name"`
	Version string `mapstructure:"version" json:"version" yaml:"version"`
	BaseUrl string `mapstructure:"base_url" json:"base_url" yaml:"base_url"`
	Address string `mapstructure:"address" json:"address" yaml:"address"`
	SSE     bool   `mapstructure:"sse" json:"sse" yaml:"sse"`
}

type Config struct {
	Mongo MongoConfig `mapstructure:"mongo" json:"mongo" yaml:"mongo"`
	MCP   MCPClient   `mapstructure:"mcp" json:"mcp" yaml:"mcp"`
}

func LoadConfig(path string, env string) Config {
	var Cfg Config
	viper.AddConfigPath(path)
	viper.SetConfigName("config")
	viper.SetConfigType("yaml")
	viper.AutomaticEnv()

	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("Read config error: %v", err)
	}

	if err := viper.Unmarshal(&Cfg); err != nil {
		log.Fatalf("Unmarshal config error: %v", err)
	}

	if env != "" {
		viper.SetConfigName("config." + env)
		if err := viper.MergeInConfig(); err != nil {
			log.Fatalf("Merge config error: %v", err)
		}
		if err := viper.Unmarshal(&Cfg); err != nil {
			log.Fatalf("Unmarshal config error: %v", err)
		}
	}

	log.Println("Config loaded successfully")
	return Cfg
}

```

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

```go
package tools

import (
	"context"
	"fmt"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"mcp/app/client"
)

type IdGenerateTool interface {
	Generate() (mcp.Tool, server.ToolHandlerFunc)
}

type idGenerateTool struct {
	EntityPrefixMap map[string]interface{}
}

func NewIdGenerateTool() IdGenerateTool {
	return &idGenerateTool{
		EntityPrefixMap: map[string]interface{}{
			"task":       "TSK",
			"lesson":     "LSN",
			"course":     "CRS",
			"experiment": "EXP",
		},
	}
}

func (i idGenerateTool) Generate() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	var prefixNameSet []string
	for key := range i.EntityPrefixMap {
		prefixNameSet = append(prefixNameSet, key)
	}
	tool = mcp.NewTool(
		"entity_id_generator",
		mcp.WithDescription("generate id for different type entity"),
		mcp.WithString("entity_type",
			mcp.Required(),
			mcp.Description(fmt.Sprintf("type of entity to generate id, it could be one of %s", prefixNameSet)),
		),
	)
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		entityType := request.Params.Arguments["entity_type"].(string)
		log.Printf("Generate id for entity: %s", entityType)
		var entityPrefix string
		if value, ok := i.EntityPrefixMap[entityType]; ok {
			entityPrefix = value.(string)
			//return mcp.NewToolResultText(prefix.(string) + "-" + mcp.GenerateId()), nil
		} else {
			return mcp.NewToolResultText(fmt.Sprintf("entity type %s not found, please use one of %s", entityType, prefixNameSet)), nil
		}
		counterID, err := i.getNextSequence(ctx, entityPrefix)
		if err != nil {
			return mcp.NewToolResultText(fmt.Sprintf("failed to get next sequence: %v", err)), nil
		}
		return mcp.NewToolResultText(fmt.Sprintf("%s-%04d", entityPrefix, counterID)), nil
	}
	return
}

func (i idGenerateTool) getNextSequence(ctx context.Context, counterIDType string) (int, error) {
	filter := bson.M{"id_type": counterIDType}
	update := bson.M{"$inc": bson.M{"sequence": 1}}
	opts := options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After)

	var result struct {
		Sequence int `bson:"sequence"`
	}
	err := client.DB.Collection("counters").FindOneAndUpdate(ctx, filter, update, opts).Decode(&result)
	if err != nil {
		return 0, err
	}

	return result.Sequence, nil
}

```

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

```go
package tools

import (
	"context"
	"fmt"
	"github.com/go-viper/mapstructure/v2"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"mcp/app/client"
	"mcp/app/model"
)

type IndexTool interface {
	// ListIndexes get indexes in mongodb
	ListIndexes() (mcp.Tool, server.ToolHandlerFunc)
	// CreateIndex create index in mongodb
	CreateIndex() (mcp.Tool, server.ToolHandlerFunc)
	// DropIndex drop index in mongodb
	DropIndex() (mcp.Tool, server.ToolHandlerFunc)
}

type indexTool struct{}

func NewIndexTool() IndexTool {
	return &indexTool{}
}

// ListIndexes List all indexes in mongodb
func (c indexTool) ListIndexes() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"ListIndexes",
		mcp.WithDescription("List all indexes in mongodb"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		collectionName := request.Params.Arguments["collection"].(string)
		cur, err := client.DB.Collection(collectionName).Indexes().List(ctx)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		defer cur.Close(ctx)

		var indexes []bson.M
		if err = cur.All(ctx, &indexes); err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		var result string
		for _, doc := range indexes {
			result += fmt.Sprintf("%v\n", doc)
		}
		return mcp.NewToolResultText(result), nil

	}
	return
}

// CreateIndex create index in mongodb
func (c indexTool) CreateIndex() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"CreateIndex",
		mcp.WithDescription("create index in mongodb"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name"),
		),
		mcp.WithObject("index_spec",
			mcp.Required(),
			mcp.Description("Index specification (e.g., { field: 1 } for ascending index)"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.CreateIndexRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)

		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}

		res, err := client.DB.Collection(req.Collection).Indexes().CreateOne(ctx, mongo.IndexModel{
			Keys: req.IndexSpec,
		})
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}

		return mcp.NewToolResultText(fmt.Sprintf("Index created, Name: %v", res)), nil
	}
	return
}

// DropIndex drop index in mongodb
func (c indexTool) DropIndex() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"DropIndex",
		mcp.WithDescription("drop index in mongodb"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name"),
		),
		mcp.WithObject("index_name",
			mcp.Required(),
			mcp.Description("Name of the index to drop"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.DropIndexRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)

		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}

		res, err := client.DB.Collection(req.Collection).Indexes().DropOne(ctx, req.IndexName)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		return mcp.NewToolResultText(fmt.Sprintf("Index dropped Successfully, result: %v", res)), nil
	}
	return
}

```

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

```go
package tools

import (
	"context"
	"fmt"
	"github.com/go-viper/mapstructure/v2"
	"github.com/mark3labs/mcp-go/mcp"
	"github.com/mark3labs/mcp-go/server"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"mcp/app/client"
	"mcp/app/model"
)

type DocumentTool interface {
	// Find get document in collection
	Find() (mcp.Tool, server.ToolHandlerFunc)
	// Count get documents count in collection
	Count() (mcp.Tool, server.ToolHandlerFunc)
	// InsertOne insert one document in collection
	InsertOne() (mcp.Tool, server.ToolHandlerFunc)
	// DeleteOne insert one document in collection
	DeleteOne() (mcp.Tool, server.ToolHandlerFunc)
	// UpdateOne insert one document in collection
	UpdateOne() (mcp.Tool, server.ToolHandlerFunc)
}

type documentTool struct{}

func NewDocumentTool() DocumentTool {
	return &documentTool{}
}

// Find get document in collection
func (c documentTool) Find() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"Find",
		mcp.WithDescription("Query documents in a collection using MongoDB query syntax"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name to query"),
		),
		mcp.WithObject("filter",
			mcp.Description("MongoDB query filter"),
			mcp.DefaultString("{}"),
		),
		mcp.WithNumber("limit",
			mcp.Description("Limit the number of documents to return"),
			mcp.DefaultNumber(0),
			mcp.Min(0),
			mcp.Max(1000),
		),
		mcp.WithObject("projection",
			mcp.Description("MongoDB projection filter"),
			mcp.DefaultString("{}"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.FindDocumentRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)
		if err != nil {
			return mcp.NewToolResultText("Parse request failed"), err
		}

		log.Printf(fmt.Sprintf("Find document in collection: %s, filter: %s, limit: %d", req.Collection, req.Filter, req.Limit))

		cur, err := client.DB.Collection(req.Collection).Find(ctx, req.Filter, &options.FindOptions{
			Limit:      &req.Limit,
			Projection: req.Projection,
		})
		defer cur.Close(ctx)

		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}

		var documents []bson.M
		if err = cur.All(ctx, &documents); err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		if len(documents) == 0 {
			log.Println("No documents found")
			return mcp.NewToolResultText("No documents found"), nil
		}
		var result string
		for _, doc := range documents {
			result += fmt.Sprintf("%v\n", doc)
		}
		log.Println(result)
		return mcp.NewToolResultText(result), nil
	}
	return
}

// Count get documents count in collection
func (c documentTool) Count() (tool mcp.Tool, handler server.ToolHandlerFunc) {

	// MCP Tool
	tool = mcp.NewTool(
		"Count",
		mcp.WithDescription("Count documents in a collection using MongoDB query syntax"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name to query"),
		),
		mcp.WithObject("filter",
			mcp.Description("MongoDB query filter"),
			mcp.DefaultString("{}"),
		),
		mcp.WithObject("projection",
			mcp.Description("MongoDB projection filter"),
			mcp.DefaultString("{}"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.CountDocumentRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)
		if err != nil {
			return mcp.NewToolResultText("Parse request failed"), err
		}

		log.Printf(fmt.Sprintf("Count document in collection: %s, filter: %s", req.Collection, req.Filter))

		count, err := client.DB.Collection(req.Collection).CountDocuments(ctx, req.Filter)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		log.Printf(fmt.Sprintf("Count documents success, count: %d", count))
		return mcp.NewToolResultText(fmt.Sprintf("Count documents success, count: %d", count)), nil
	}
	return
}

// InsertOne insert one document in collection
func (c documentTool) InsertOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
	// MCP Tool
	tool = mcp.NewTool(
		"InertOne",
		mcp.WithDescription("Insert a single document into a collection"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name to insert"),
		),
		mcp.WithString("document",
			mcp.Required(),
			mcp.Description("document to insert"),
			mcp.DefaultString("{}"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.InsertDocumentRequest

		err := mapstructure.Decode(request.Params.Arguments, &req)
		if err != nil {
			return mcp.NewToolResultText("Parse request failed"), err
		}

		log.Printf(fmt.Sprintf("Insert document in collection: %s, document: %s", req.Collection, req.Document))

		// Convert the document string to a BSON document
		var document bson.M
		err = bson.UnmarshalExtJSON([]byte(req.Document), true, &document)
		if err != nil {
			return mcp.NewToolResultText("Parse document failed"), err
		}
		res, err := client.DB.Collection(req.Collection).InsertOne(ctx, document)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}

		if res.InsertedID == nil {
			return mcp.NewToolResultText("Insert document failed"), nil
		}
		return mcp.NewToolResultText(fmt.Sprintf("Insert document success, id: %v", res.InsertedID)), nil
	}
	return
}

// DeleteOne insert one document in collection
func (c documentTool) DeleteOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
	// MCP Tool
	tool = mcp.NewTool(
		"DeleteOne",
		mcp.WithDescription("Delete a single document into a collection"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name to delete"),
		),
		mcp.WithObject("filter",
			mcp.Required(),
			mcp.Description("Filter to identify document"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.DeleteDocumentRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)
		if err != nil {
			return mcp.NewToolResultText("Parse request failed"), err
		}

		log.Printf(fmt.Sprintf("Delete document in collection: %s, filter: %s", req.Collection, req.Filter))

		res, err := client.DB.Collection(req.Collection).DeleteOne(ctx, req.Filter)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		if res.DeletedCount == 0 {
			return mcp.NewToolResultText("No documents deleted"), nil
		}
		return mcp.NewToolResultText(fmt.Sprintf("Delete document success, deleted count: %d", res.DeletedCount)), nil
	}
	return
}

// UpdateOne insert one document in collection
func (c documentTool) UpdateOne() (tool mcp.Tool, handler server.ToolHandlerFunc) {
	// MCP Tool
	tool = mcp.NewTool(
		"UpdateOne",
		mcp.WithDescription("update a single document into a collection"),
		mcp.WithString("collection",
			mcp.Required(),
			mcp.Description("Collection name to update"),
		),
		mcp.WithObject("filter",
			mcp.Required(),
			mcp.Description("Filter to identify document"),
		),
		mcp.WithObject("update",
			mcp.Required(),
			mcp.Description("Update operations to apply"),
		),
	)
	// handler
	handler = func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
		var req model.UpdateDocumentRequest
		err := mapstructure.Decode(request.Params.Arguments, &req)
		if err != nil {
			return mcp.NewToolResultText("Parse request failed"), err
		}
		fmt.Println(req)

		log.Printf(fmt.Sprintf("Update document in collection: %s, filter: %s", req.Collection, req.Filter))

		res, err := client.DB.Collection(req.Collection).UpdateOne(ctx, req.Filter, req.Update)
		if err != nil {
			return mcp.NewToolResultText(err.Error()), err
		}
		if res.MatchedCount == 0 {
			return mcp.NewToolResultText("No documents matched"), nil
		}
		if res.ModifiedCount == 0 {
			return mcp.NewToolResultText("No documents updated"), nil
		}
		return mcp.NewToolResultText(
			fmt.Sprintf("Update document success, matched count: %d, modified count: %d, upsertedId %d",
				res.MatchedCount, res.ModifiedCount, res.UpsertedID,
			),
		), nil
	}
	return
}

```