Skip to main content
Glama
jonfreeland

MongoDB MCP Server

by jonfreeland

query

Execute read-only queries on MongoDB collections using standard query syntax to retrieve and export data in JSON or CSV formats.

Instructions

Execute a read-only query on a collection using MongoDB query syntax.

Supports both JSON and CSV output formats:

  • Use outputFormat="json" for standard JSON (default)

  • Use outputFormat="csv" for comma-separated values export

Best Practices:

  • Use projections to fetch only needed fields

  • Add limits for large collections

  • Use sort for consistent ordering

Example - Standard Query: use_mcp_tool with server_name: "mongodb", tool_name: "query", arguments: { "collection": "users", "filter": { "age": { "$gte": 21 } }, "projection": { "name": 1, "email": 1 }, "sort": { "name": 1 }, "limit": 100 }

Example - CSV Export: use_mcp_tool with server_name: "mongodb", tool_name: "query", arguments: { "collection": "users", "filter": { "active": true }, "outputFormat": "csv", "formatOptions": { "includeHeaders": true, "delimiter": "," } }

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
databaseNoDatabase name (optional if default database is configured)
collectionYesCollection name
filterYesMongoDB query filter using standard MongoDB operators ($eq, $gt, $in, etc.)
projectionNoMongoDB projection to specify fields to return (optional)
sortNoMongoDB sort specification (optional)
limitNoMaximum number of documents to return (optional)
outputFormatNoOutput format for results (json or csv)
formatOptionsNoFormat-specific options

Implementation Reference

  • The main handler for the 'query' tool. Executes MongoDB find operation with filter, optional projection, sort, and limit. Supports JSON (default) and CSV output formats. Includes visualization hints for JSON results.
    case 'query': {
      const { 
        database, 
        collection, 
        filter, 
        projection, 
        sort, 
        limit,
        outputFormat = 'json',
        formatOptions = {} 
      } = request.params.arguments as {
        database?: string;
        collection: string;
        filter: object;
        projection?: object;
        sort?: Sort;
        limit?: number;
        outputFormat?: 'json' | 'csv';
        formatOptions?: any;
      };
      const dbName = database || this.defaultDatabase;
      if (!dbName) {
        throw new McpError(
          ErrorCode.InvalidRequest,
          'Database name is required when no default database is configured'
        );
      }
    
      const db = client.db(dbName);
      let query = db.collection(collection).find(filter);
    
      if (projection) {
        query = query.project(projection);
      }
      if (sort) {
        query = query.sort(sort);
      }
      if (limit) {
        query = query.limit(limit);
      }
    
      const results = await query.toArray();
      
      // Handle different output formats
      if (outputFormat.toLowerCase() === 'csv') {
        return {
          content: [
            {
              type: 'text',
              text: this.documentsToCsv(results, formatOptions),
            },
          ],
        };
      } else {
        // Default JSON format
        const vizHint = this.generateVisualizationHint(results);
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(results, null, 2) + (vizHint ? `\n\nVisualization Hint:\n${vizHint}` : ''),
            },
          ],
        };
      }
    }
  • Input schema definition for the 'query' tool, specifying parameters like database, collection, filter (required), projection, sort, limit, outputFormat, and formatOptions with types and constraints.
    inputSchema: {
      type: 'object',
      properties: {
        database: {
          type: 'string',
          description: 'Database name (optional if default database is configured)',
        },
        collection: {
          type: 'string',
          description: 'Collection name',
        },
        filter: {
          type: 'object',
          description: 'MongoDB query filter using standard MongoDB operators ($eq, $gt, $in, etc.)',
        },
        projection: {
          type: 'object',
          description: 'MongoDB projection to specify fields to return (optional)',
        },
        sort: {
          type: 'object',
          description: 'MongoDB sort specification (optional)',
        },
        limit: {
          type: 'number',
          description: 'Maximum number of documents to return (optional)',
          minimum: 1,
          maximum: 1000,
        },
        outputFormat: {
          type: 'string',
          description: 'Output format for results (json or csv)',
          enum: ['json', 'csv'],
        },
        formatOptions: {
          type: 'object',
          description: 'Format-specific options',
          properties: {
            delimiter: {
              type: 'string',
              description: 'CSV delimiter character (default: comma)',
            },
            includeHeaders: {
              type: 'boolean',
              description: 'Whether to include header row in CSV (default: true)',
            },
          },
        },
      },
      required: ['collection', 'filter'],
    },
  • src/index.ts:371-458 (registration)
    Registration of the 'query' tool in the list_tools handler, including name, detailed description with usage examples, and complete input schema.
              name: 'query',
              description: `Execute a read-only query on a collection using MongoDB query syntax.
    
    Supports both JSON and CSV output formats:
    - Use outputFormat="json" for standard JSON (default)
    - Use outputFormat="csv" for comma-separated values export
    
    Best Practices:
    - Use projections to fetch only needed fields
    - Add limits for large collections
    - Use sort for consistent ordering
    
    Example - Standard Query:
    use_mcp_tool with
      server_name: "mongodb",
      tool_name: "query",
      arguments: {
        "collection": "users",
        "filter": { "age": { "$gte": 21 } },
        "projection": { "name": 1, "email": 1 },
        "sort": { "name": 1 },
        "limit": 100
      }
    
    Example - CSV Export:
    use_mcp_tool with
      server_name: "mongodb",
      tool_name: "query",
      arguments: {
        "collection": "users",
        "filter": { "active": true },
        "outputFormat": "csv",
        "formatOptions": {
          "includeHeaders": true,
          "delimiter": ","
        }
      }`,
              inputSchema: {
                type: 'object',
                properties: {
                  database: {
                    type: 'string',
                    description: 'Database name (optional if default database is configured)',
                  },
                  collection: {
                    type: 'string',
                    description: 'Collection name',
                  },
                  filter: {
                    type: 'object',
                    description: 'MongoDB query filter using standard MongoDB operators ($eq, $gt, $in, etc.)',
                  },
                  projection: {
                    type: 'object',
                    description: 'MongoDB projection to specify fields to return (optional)',
                  },
                  sort: {
                    type: 'object',
                    description: 'MongoDB sort specification (optional)',
                  },
                  limit: {
                    type: 'number',
                    description: 'Maximum number of documents to return (optional)',
                    minimum: 1,
                    maximum: 1000,
                  },
                  outputFormat: {
                    type: 'string',
                    description: 'Output format for results (json or csv)',
                    enum: ['json', 'csv'],
                  },
                  formatOptions: {
                    type: 'object',
                    description: 'Format-specific options',
                    properties: {
                      delimiter: {
                        type: 'string',
                        description: 'CSV delimiter character (default: comma)',
                      },
                      includeHeaders: {
                        type: 'boolean',
                        description: 'Whether to include header row in CSV (default: true)',
                      },
                    },
                  },
                },
                required: ['collection', 'filter'],
              },
  • Helper function that analyzes query results and generates tailored visualization recommendations (e.g., time series, scatter plots, maps), appended to JSON query responses.
    private generateVisualizationHint(data: any[]): string {
      if (!Array.isArray(data) || data.length === 0) return '';
    
      // Check if the data looks like time series
      const hasDateFields = Object.keys(data[0]).some(key => 
        data[0][key] instanceof Date || 
        (typeof data[0][key] === 'string' && !isNaN(Date.parse(data[0][key])))
      );
    
      // Check if the data has numeric fields
      const numericFields = Object.keys(data[0]).filter(key => 
        typeof data[0][key] === 'number'
      );
    
      // Check if the data has categorical fields
      const categoricalFields = Object.keys(data[0]).filter(key => 
        typeof data[0][key] === 'string' && 
        data.every(item => typeof item[key] === 'string')
      );
    
      // Check if the data has geospatial fields
      const hasGeoData = Object.keys(data[0]).some(key => {
        const value = data[0][key];
        return value && typeof value === 'object' && 
          (('type' in value && value.type === 'Point' && 'coordinates' in value) ||
           (Array.isArray(value) && value.length === 2 && 
            typeof value[0] === 'number' && typeof value[1] === 'number'));
      });
    
      let hints = [];
    
      if (hasDateFields && numericFields.length > 0) {
        hints.push('Time Series Visualization:\n- Consider line charts for temporal trends\n- Time-based heat maps for density patterns\n- Area charts for cumulative values over time');
      }
    
      if (categoricalFields.length > 0 && numericFields.length > 0) {
        hints.push('Categorical Analysis:\n- Bar charts for comparing categories\n- Box plots for distribution analysis\n- Heat maps for category correlations\n- Treemaps for hierarchical data');
      }
    
      if (numericFields.length >= 2) {
        hints.push('Numerical Analysis:\n- Scatter plots for correlation analysis\n- Bubble charts if three numeric dimensions\n- Correlation matrices for multiple variables\n- Histograms for distribution analysis');
      }
    
      if (hasGeoData) {
        hints.push('Geospatial Visualization:\n- Map overlays for location data\n- Choropleth maps for regional analysis\n- Heat maps for density visualization\n- Cluster maps for point concentration');
      }
    
      if (data.length > 1000) {
        hints.push('Large Dataset Considerations:\n- Consider sampling for initial visualization\n- Use aggregation for summary views\n- Implement pagination or infinite scroll\n- Consider server-side rendering');
      }
    
      return hints.join('\n\n');
    }
  • Helper function to convert MongoDB documents to CSV format, handling varying schemas, proper escaping, and configurable options like headers and delimiter. Used for CSV output in query tool.
    private documentsToCsv(docs: any[], options: {
      includeHeaders?: boolean;
      delimiter?: string;
    } = {}): string {
      if (!Array.isArray(docs) || docs.length === 0) return '';
      
      const delimiter = options.delimiter || ',';
      const includeHeaders = options.includeHeaders !== false;
      
      // Extract all possible field names from all documents (handles varying schemas)
      const fieldsSet = new Set<string>();
      docs.forEach(doc => {
        Object.keys(doc).forEach(key => fieldsSet.add(key));
      });
      
      const fields = Array.from(fieldsSet);
      let result = '';
      
      // Add headers
      if (includeHeaders) {
        result += fields.map(field => this.escapeCsvField(field, delimiter)).join(delimiter) + '\n';
      }
      
      // Add data rows
      docs.forEach(doc => {
        const row = fields.map(field => {
          const value = doc[field];
          if (value === undefined || value === null) return '';
          if (typeof value === 'object') return this.escapeCsvField(JSON.stringify(value), delimiter);
          return this.escapeCsvField(String(value), delimiter);
        });
        result += row.join(delimiter) + '\n';
      });
      
      return result;
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explicitly states 'read-only' which is crucial safety information. It also mentions output formats (JSON/CSV) and best practices like adding limits. However, it doesn't cover important behavioral aspects like pagination, error handling, timeout behavior, or authentication requirements that would be helpful for an agent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections: purpose statement, output format explanation, best practices, and examples. However, the two detailed examples are quite lengthy and could potentially be summarized more concisely. The front-loaded purpose statement is excellent, but the overall length might be slightly excessive for what needs to be communicated.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex query tool with 8 parameters, no annotations, and no output schema, the description provides good basic coverage but has gaps. It explains the core functionality and output formats well, but doesn't describe what the return value looks like (structure, pagination, error formats). Given the complexity and lack of output schema, more information about response format would be beneficial.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, so the schema already documents all 8 parameters thoroughly. The description adds some value by explaining outputFormat options and providing examples, but doesn't add significant semantic meaning beyond what's in the schema. The examples show parameter usage but don't explain semantics that aren't already in the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Execute a read-only query on a collection using MongoDB query syntax.' It specifies the verb ('execute'), resource ('collection'), and technology ('MongoDB query syntax'), distinguishing it from siblings like 'aggregate', 'count_documents', or 'text_search' which serve different query purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: for read-only queries with MongoDB syntax. It mentions best practices like using projections and limits, which implicitly guides usage. However, it doesn't explicitly state when to choose this over alternatives like 'aggregate' for complex aggregations or 'find_by_ids' for ID-based lookups.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jonfreeland/mongodb-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server