MCP server providing geocoding and residency verification tools for AI workflows.
LLMs can hallucinate address data, giving incorrect coordinates and residency verification. To get reliable results, you need a real geocoding service. This MCP server connects AI agents to a real geocoding service (Census Geocoder) so you can ask questions in natural language while getting accurate data, no API calls or scripts needed.
Current Implementation: Local prototype where each user runs their own instance. Uses the free Census Geocoder, which has limitations (US-only, slower than commercial options, requires well-formatted addresses, no reverse geocoding). This MCP server was specifically tested using VS Code/GitHub Copilot as the Host and supported Client, but you could try using the server with other MCP-compatible applications.
Potential Use Case for Cities: This concept originated from the idea that cities could deploy a hosted MCP server as a centralized geocoding service. Multiple AI agents across applications and departments (licensing, permits, business registration) would connect to one server instance instead of each building their own geocoding integration. This is a quick exploration of that concept.
flowchart TB
User["🖥️ HOST: VS Code + GitHub Copilot LLM"]
Client["📄 MCP CLIENT
Component in Host that talks to Server"]
Server["⚙️ MCP SERVER
server.py
geocode, verify residency, get ward"]
Census["🌐 CENSUS GEOCODER API
Free US address geocoding"]
Boundary["📍 LOCAL BOUNDARY FILES
city_boundary.geojson
wards.geojson"]
User -->|1. Question: Is 1600 Penn Ave a DC address?| Client
Client -->|2. Call tool: geocode_address| Server
Server -->|3. Try abbreviated, then full name| Census
Census -->|4. Return all matches NW and SE| Server
Server -->|5. Check residency and districts| Boundary
Boundary -->|6. Return results| Server
Server -->|7. Send answer| Client
Client -->|8. Found 2 matches: NW Ward 2 and SE Ward 6| User
style User fill:#e3f2fd,stroke:#1976d2,stroke-width:4px
style Client fill:#fff3e0,stroke:#f57c00,stroke-width:4px
style Server fill:#e8f5e9,stroke:#388e3c,stroke-width:4px
style Census fill:#f3e5f5,stroke:#7b1fa2,stroke-width:4px
style Boundary fill:#fce4ec,stroke:#c2185b,stroke-width:4px
- Python 3.10+
- VS Code with GitHub Copilot subscription
- City boundary and district GeoJSON files
cd geocoding-mcp-server
uv venv # Create a virtual environment if needed
source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -r requirements.txtThis server is designed to work with any US city, but this prototype uses DC boundaries:
DC Boundary:
- Visit https://opendata.dc.gov/datasets/7241f6d500b44288ad983f0942b39663_10
- Click "Download" → "GeoJSON"
- Save as
city_boundary.geojsoninboundaries/folder
DC Wards:
- Visit https://opendata.dc.gov/datasets/c5cd8b40fb784548a6680aead5f919ed_53
- Click "Download" → "GeoJSON"
- Save as
wards.geojsoninboundaries/folder
The server will automatically create the boundaries/ and logs/ folders if they don't exist.
Configuring for Cities other than DC
- Edit the configuration section at the top of
server.py:
# Change these settings to adapt for your city
CITY_NAME = "Washington DC"
CITY_KEYWORDS = ['washington', 'dc', 'district of columbia']
USE_QUADRANTS = True # Set to False for cities without quadrant system
QUADRANTS = ['NW', 'NE', 'SE', 'SW'] # Customize or leave emptycp .vscode/mcp.json.example .vscode/mcp.jsonEdit .vscode/mcp.json with the absolute path to server.py:
{
"servers": {
"geocoding-server": {
"command": "python",
"args": ["/Users/yourname/Dev/geocoding-mcp-server/server.py"]
}
}
}- Reload VS Code:
Cmd/Ctrl + Shift + P→ "Reload Window" - Open Copilot Chat and switch to Agent mode
- Click tools icon to verify
geocoding-serveris connected - You should see:
geocode_address,check_residency,get_district
Convert a street address to coordinates. Automatically handles:
- Abbreviated street names (Penn Ave → Pennsylvania Avenue)
- Multiple matches in different quadrants
- Ambiguous addresses
Example:
geocode the address "1600 Penn Ave"
Returns both 1600 Pennsylvania Ave NW and SE with coordinates.
Verify if an address is within the city boundary. Returns is_resident: true/false with all matching addresses.
Example:
is "1600 Penn Ave" a DC address?
Returns both matches with residency status for each.
Return the ward/district for an address. Only checks districts for addresses confirmed within city boundaries.
Example:
what ward is "1600 Penn Ave" in?
Returns ward information for all matching addresses in DC.
The server uses a modular design:
geocode_address: Handles all geocoding logic, searches quadrant variationscheck_residency: Calls geocode, then checks city boundaryget_district: Calls geocode and residency check, then identifies ward
All tool interactions are logged to logs/interactions.jsonl for audit trails.