Skip to main content
Glama
jonfreeland

MongoDB MCP Server

by jonfreeland

geo_query

Perform geospatial queries on MongoDB collections to find points near a location, within shapes, or calculate distances. Supports GeoJSON, legacy formats, and requires a geospatial index.

Instructions

Execute geospatial queries on a MongoDB collection.

Supports:

  • Finding points near a location

  • Finding documents within a polygon, circle, or box

  • Calculating distances between points

  • GeoJSON and legacy coordinate pair formats

Requirements:

  • Collection must have a geospatial index (2dsphere recommended)

  • Coordinates should follow MongoDB conventions (longitude first, then latitude)

Examples:

  1. Find locations near a point (2 miles radius): use_mcp_tool with server_name: "mongodb", tool_name: "geo_query", arguments: { "collection": "restaurants", "operation": "near", "point": [-73.9667, 40.78], "maxDistance": 3218.69, // 2 miles in meters "distanceField": "distance" }

  2. Find locations within a polygon: use_mcp_tool with server_name: "mongodb", tool_name: "geo_query", arguments: { "collection": "properties", "operation": "geoWithin", "geometry": { "type": "Polygon", "coordinates": [ [[-73.958, 40.8], [-73.94, 40.79], [-73.95, 40.76], [-73.97, 40.76], [-73.958, 40.8]] ] } }

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
additionalFilterNoAdditional MongoDB query criteria to combine with geospatial query
collectionYesCollection name
databaseNoDatabase name (optional if default database is configured)
distanceFieldNoField to store calculated distances (for near/nearSphere queries)
geometryNoGeoJSON geometry for geoWithin/geoIntersects queries
limitNoMaximum number of results to return
locationFieldNoField containing geospatial data (default: "location")
maxDistanceNoMaximum distance in meters for near/nearSphere queries
minDistanceNoMinimum distance in meters for near/nearSphere queries
operationYesGeospatial operation to perform
pointNoPoint coordinates [longitude, latitude] for near/nearSphere queries
sphericalNoCalculate distances on a sphere (Earth) rather than flat plane

Implementation Reference

  • Main execution handler for the geo_query tool. Handles geospatial operations including near/nearSphere using $geoNear aggregation, and geoWithin/geoIntersects using find queries. Includes input validation, coordinate checks, error handling for missing indexes, and visualization hints.
    case 'geo_query': { const { database, collection, operation, locationField = 'location', point, maxDistance, minDistance, geometry, distanceField, spherical = true, limit = 100, additionalFilter = {} } = request.params.arguments as { database?: string; collection: string; operation: 'near' | 'geoWithin' | 'geoIntersects' | 'nearSphere'; locationField?: string; point?: number[]; maxDistance?: number; minDistance?: number; geometry?: any; distanceField?: string; spherical?: boolean; limit?: number; additionalFilter?: object; }; 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); switch (operation) { case 'near': case 'nearSphere': { if (!Array.isArray(point) || point.length !== 2) { throw new McpError( ErrorCode.InvalidRequest, 'Point coordinates [longitude, latitude] are required for near/nearSphere queries' ); } // Validate coordinates const [longitude, latitude] = point; if (longitude < -180 || longitude > 180) { throw new McpError( ErrorCode.InvalidRequest, 'Invalid longitude: must be between -180 and 180' ); } if (latitude < -90 || latitude > 90) { throw new McpError( ErrorCode.InvalidRequest, 'Invalid latitude: must be between -90 and 90' ); } const geoNearOptions: any = { near: { type: 'Point', coordinates: point }, distanceField: distanceField || 'distance', spherical: operation === 'nearSphere' || spherical, query: additionalFilter }; if (maxDistance !== undefined) geoNearOptions.maxDistance = maxDistance; if (minDistance !== undefined) geoNearOptions.minDistance = minDistance; if (limit) geoNearOptions.limit = limit; try { // Use aggregation for geoNear const results = await db.collection(collection).aggregate([ { $geoNear: geoNearOptions } ]).toArray(); const vizHint = this.generateVisualizationHint(results); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2) + (vizHint ? `\n\nVisualization Hint:\n${vizHint}` : ''), }, ], }; } catch (error) { // Check if error is due to missing geospatial index if (error instanceof Error && (error.message.includes('2dsphere') || error.message.includes('geo'))) { throw new McpError( ErrorCode.InvalidRequest, `Geospatial index required. Create one using: db.${collection}.createIndex({ "${locationField}": "2dsphere" })` ); } throw error; } } case 'geoWithin': case 'geoIntersects': { if (!geometry || !geometry.type || !geometry.coordinates) { throw new McpError( ErrorCode.InvalidRequest, 'Valid GeoJSON geometry is required for geoWithin/geoIntersects queries' ); } const operator = operation === 'geoWithin' ? '$geoWithin' : '$geoIntersects'; const geoQuery = { [locationField]: { [operator]: { $geometry: geometry } }, ...additionalFilter }; try { const results = await db.collection(collection) .find(geoQuery) .limit(limit) .toArray(); const vizHint = this.generateVisualizationHint(results); return { content: [ { type: 'text', text: JSON.stringify(results, null, 2) + (vizHint ? `\n\nVisualization Hint:\n${vizHint}` : ''), }, ], }; } catch (error) { // Check if error is due to missing geospatial index if (error instanceof Error && (error.message.includes('2dsphere') || error.message.includes('geo'))) { throw new McpError( ErrorCode.InvalidRequest, `Geospatial index required. Create one using: db.${collection}.createIndex({ "${locationField}": "2dsphere" })` ); } throw error; } } default: throw new McpError( ErrorCode.InvalidRequest, `Unsupported geospatial operation: ${operation}` ); } }
  • Input schema defining parameters for geo_query tool, including operation type, coordinates, distances, geometry, and filters.
    inputSchema: { type: 'object', properties: { database: { type: 'string', description: 'Database name (optional if default database is configured)', }, collection: { type: 'string', description: 'Collection name', }, operation: { type: 'string', description: 'Geospatial operation to perform', enum: ['near', 'geoWithin', 'geoIntersects', 'nearSphere'], }, locationField: { type: 'string', description: 'Field containing geospatial data (default: "location")', }, point: { type: 'array', description: 'Point coordinates [longitude, latitude] for near/nearSphere queries', items: { type: 'number', }, }, maxDistance: { type: 'number', description: 'Maximum distance in meters for near/nearSphere queries', }, minDistance: { type: 'number', description: 'Minimum distance in meters for near/nearSphere queries', }, geometry: { type: 'object', description: 'GeoJSON geometry for geoWithin/geoIntersects queries', }, distanceField: { type: 'string', description: 'Field to store calculated distances (for near/nearSphere queries)', }, spherical: { type: 'boolean', description: 'Calculate distances on a sphere (Earth) rather than flat plane', }, limit: { type: 'number', description: 'Maximum number of results to return', minimum: 1, maximum: 1000, }, additionalFilter: { type: 'object', description: 'Additional MongoDB query criteria to combine with geospatial query', }, }, required: ['collection', 'operation'], },
  • src/index.ts:843-944 (registration)
    Tool registration in the ListTools response, defining name, description, and referencing the input schema for geo_query.
    { name: 'geo_query', description: `Execute geospatial queries on a MongoDB collection. Supports: - Finding points near a location - Finding documents within a polygon, circle, or box - Calculating distances between points - GeoJSON and legacy coordinate pair formats Requirements: - Collection must have a geospatial index (2dsphere recommended) - Coordinates should follow MongoDB conventions (longitude first, then latitude) Examples: 1. Find locations near a point (2 miles radius): use_mcp_tool with server_name: "mongodb", tool_name: "geo_query", arguments: { "collection": "restaurants", "operation": "near", "point": [-73.9667, 40.78], "maxDistance": 3218.69, // 2 miles in meters "distanceField": "distance" } 2. Find locations within a polygon: use_mcp_tool with server_name: "mongodb", tool_name: "geo_query", arguments: { "collection": "properties", "operation": "geoWithin", "geometry": { "type": "Polygon", "coordinates": [ [[-73.958, 40.8], [-73.94, 40.79], [-73.95, 40.76], [-73.97, 40.76], [-73.958, 40.8]] ] } }`, inputSchema: { type: 'object', properties: { database: { type: 'string', description: 'Database name (optional if default database is configured)', }, collection: { type: 'string', description: 'Collection name', }, operation: { type: 'string', description: 'Geospatial operation to perform', enum: ['near', 'geoWithin', 'geoIntersects', 'nearSphere'], }, locationField: { type: 'string', description: 'Field containing geospatial data (default: "location")', }, point: { type: 'array', description: 'Point coordinates [longitude, latitude] for near/nearSphere queries', items: { type: 'number', }, }, maxDistance: { type: 'number', description: 'Maximum distance in meters for near/nearSphere queries', }, minDistance: { type: 'number', description: 'Minimum distance in meters for near/nearSphere queries', }, geometry: { type: 'object', description: 'GeoJSON geometry for geoWithin/geoIntersects queries', }, distanceField: { type: 'string', description: 'Field to store calculated distances (for near/nearSphere queries)', }, spherical: { type: 'boolean', description: 'Calculate distances on a sphere (Earth) rather than flat plane', }, limit: { type: 'number', description: 'Maximum number of results to return', minimum: 1, maximum: 1000, }, additionalFilter: { type: 'object', description: 'Additional MongoDB query criteria to combine with geospatial query', }, }, required: ['collection', 'operation'], }, },
  • Helper function generateVisualizationHint includes specific logic to detect geospatial data and suggest map-based visualizations, used by geo_query handler.
    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'); }

Other Tools

Related 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