SvenST89/osint_mcp_experiment
If you are the rightful owner of osint_mcp_experiment and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
The Overpass MCP Tool is a Python-based solution for querying OpenStreetMap data via the Overpass API, providing both MCP and REST interfaces.
Overpass MCP Tool
This project provides a Python-based tool to query OpenStreetMap data via the Overpass API and expose it through both MCP (Model Context Protocol) and a lightweight REST endpoint for testing or integration. It allows asynchronous querying of OSM nodes, ways, and optionally relations, with tag-based filtering and bounding box or area-based queries. Geometries are parsed into GeoPandas objects and returned as fully JSON-serializable Pydantic models.
Program Structure
-
OverpassQuery: Builds and executes Overpass API queries. Supports filtering by tags, bounding boxes, or area names, with JSON or CSV output. Can parse geometries into Shapely objects and handles retries and Overpass server availability. -
AsyncOverpassClient: Asynchronous execution of multiple Overpass queries usingaiohttpwith concurrency control. -
OverpassStructuredTool: Wraps the Overpass client and provides aquery_regionmethod returning structuredOverpassFeaturePydantic objects. Can be used both as an MCP tool and in a REST endpoint. -
MCP Server: Uses
FastMCPto expose the tool via MCP. Thequery_regionmethod is registered with@mcp.tool(). Supportsstateless_httptransport for streamable agent calls. -
REST Endpoint: A Starlette-based endpoint (
/query_region) provides a lightweight HTTP interface for testing or integration. Includes full JSON sanitization of geometries and tags.
Runnable Server Example
# Instantiate MCP server
mcp = FastMCP(
name="Overpass MCP Server",
description="Overpass OSM Query Tool with Structured Output",
stateless_http=True,
host="127.0.0.1",
port=8008
)
# Instantiate tool logic
client = AsyncOverpassClient(max_concurrent=3)
overpass_tool = OverpassStructuredTool(client)
# MCP tool registration
@mcp.tool()
async def query_region(params: OverpassQueryParams, ctx: Context):
return await overpass_tool.query_region(params, ctx)
# REST endpoint setup
async def rest_query_region(request: Request):
payload = await request.json()
params = OverpassQueryParams(**payload)
result = await overpass_tool.query_region(params, ctx=None)
safe_result = sanitize_obj(result.model_dump()) # fully JSON-serializable
return JSONResponse(safe_result, status_code=200)
rest_app = Starlette(routes=[Route("/query_region", rest_query_region, methods=["POST"])])
# Run both MCP and REST servers concurrently
async def main():
from uvicorn import Config, Server
mcp_task = asyncio.create_task(mcp.run_streamable_http_async())
rest_server = Server(Config(app=rest_app, host="127.0.0.1", port=8010, log_level="info"))
rest_task = asyncio.create_task(rest_server.serve())
await asyncio.gather(mcp_task, rest_task)
if __name__ == "__main__":
print("🚀 Overpass MCP running on 127.0.0.1:8008")
print("🌍 REST API available on 127.0.0.1:8010/query_region")
asyncio.run(main())
Lessons Learned (so far...)
JSON Serialization and Shapely Geometries
Shapely objects cannot be returned directly in JSON. All geometries must be converted to GeoJSON dictionaries using mapping(geom).
Coordinate Validation
OSM data may contain invalid coordinates (NaN, Infinity) or extremely large floats. A recursive validation is necessary for nested geometries (Polygons, MultiPolygons, LineStrings).
Tag and Metadata Sanitization
Tags and other numeric fields may contain NaN, Inf, or NumPy numeric types (numpy.float64, numpy.int64) which are not JSON-compliant. All numbers should be converted to native Python types, with invalid values replaced by None.
NumPy Scalars Are Problematic
Even finite NumPy floats or integers cannot be serialized directly by json.dumps(), which is used internally in JSONResponse() or shapely.to_geojson() (was used initially in the code for feature creation). Conversion to Python float or int is required.
MCP Context Handling
When called via REST, ctx: Context may be None. Logging or other context-dependent operations should be guarded or use a dummy context to avoid runtime errors.
Safe Recursive Serialization
Using a recursive sanitization function ensures that geometries, tags, and all nested structures are fully JSON-safe. This guarantees compatibility for MCP endpoints, REST APIs, Postman, and browser testing.
Concurrent Server Setup
Running MCP and REST servers concurrently in the same Python process is feasible using asyncio.create_task and asyncio.gather, enabling both agent workflows and HTTP testing simultaneously.
Open Issues (upcoming...)
- OpenAI + Anthropic API chat endpoint setup
- Overpass Tool connection to OpenAI LLM
- Further Abstraction / Base Classes for LLM
- Further Abstraction / Base Classes MCP + Tool Usage
- Unit Tests
- MVP frontend with Dash/plotly + map for demonstration purposes