Skip to main content
Glama
README.md
# arcpro-mcp

> Control **ArcGIS Pro** with natural language through the **Model Context Protocol (MCP)**.
> Works with Cursor, Claude, and Codex — bring your own LLM, keep your data local.

[![CI](https://github.com/qiobn/arcpro-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/qiobn/arcpro-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)

`arcpro-mcp` lets an AI agent drive a **live ArcGIS Pro session**: inspect projects,
explore layers and attributes, check coordinate systems, and (soon) run geoprocessing
and build layouts — all from a chat prompt in your favorite MCP client.

Unlike Esri's built-in assistant, this is **open source**, connects to **any LLM** via
your MCP client, and acts on your **actual open session** rather than only generating code.

---

## Architecture

ArcGIS Pro hosts `arcpy`, and `arcpy.mp.ArcGISProject("CURRENT")` only works **inside**
the running app. So the MCP server (a separate process started by your client) talks to a
small **bridge** running in ArcGIS Pro's Python window over a local socket:

```
Cursor / Claude / Codex
        │  stdio (MCP)
        ▼
arcpro-mcp  (this package, separate process)
        │  TCP socket, length-prefixed JSON  (127.0.0.1:18748)
        ▼
arcpro_bridge.py  (runs in ArcGIS Pro's Python window)
        │  arcpy / arcpy.mp
        ▼
ArcGIS Pro  (live session)
```

Design choices vs. existing tools:

- **Socket, not file polling** — lower latency, cleaner framing for big payloads.
- **Layered + tested** — `src/` package, dependency-free bridge, pytest, CI.
- **Safety first** — read-only by default; destructive tools ask for confirmation;
  `execute_python` is **off** unless explicitly enabled; every call is **audit-logged**.
- **Great UX** — structured output, MCP resources, and live **layer-name auto-complete**.

---

## Requirements

- **ArcGIS Pro 3.x** (provides `arcpy`)
- **Python 3.10+** for the MCP server (the `arcgispro-py3` conda env works well)
- An MCP client: **Cursor**, **Claude Desktop**, or **Codex**
- [`uv`](https://docs.astral.sh/uv/) recommended (or plain `pip`)

## Install

```bash
git clone https://github.com/qiobn/arcpro-mcp
cd arcpro-mcp
uv sync          # or: pip install -e .
```

## Usage

### 1. Start the bridge in ArcGIS Pro

Open ArcGIS Pro with a project, open the **Python window**, and run:

```python
exec(open(r"C:/path/to/arcpro-mcp/bridge/arcpro_bridge.py").read())
```

You should see `[ArcPro MCP Bridge] Listening on 127.0.0.1:18748`.

### 2. Configure your MCP client

See [`examples/mcp-config.example.json`](examples/mcp-config.example.json). For Cursor or
Claude Desktop:

```json
{
  "mcpServers": {
    "arcgis-pro": {
      "command": "uv",
      "args": ["--directory", "C:/path/to/arcpro-mcp", "run", "arcpro-mcp"]
    }
  }
}
```

### 3. Talk to it

> "Ping ArcGIS Pro and tell me what's in the project."
> "List the layers, then show me the first 10 rows of the roads layer."
> "What's the coordinate system of C:/data/parcels.shp?"

---

## Tools

**Read-only**

| Tool | Description |
| --- | --- |
| `ping` | Connectivity + project status |
| `get_project_info` | Project path, default GDB, maps |
| `list_directory` | List files (confirm paths before loading) |
| `describe_data` | Data type, geometry, extent, **CRS** |
| `list_feature_classes` | Feature classes in a workspace |
| `list_layers` | Layers on the active map |
| `list_fields` | Fields of a dataset/layer |
| `count_features` | Row count of a layer |
| `get_layer_features` | Preview attribute rows |
| `get_unique_values` | Distinct values of a field |
| `get_workspace` / `list_layouts` | Inspect workspace / layouts |

**Write / map-modifying**

| Tool | Description |
| --- | --- |
| `add_vector_layer` / `add_raster_layer` | Add data to a map |
| `remove_layer` | Remove a layer (asks for confirmation) |
| `set_layer_visibility` / `zoom_to_layer` | Toggle / navigate |
| `create_map` / `save_project` | Map and project management |
| `select_by_attribute` / `clear_selection` | SQL-based selection |
| `set_workspace` | Set default GP workspace |
| `run_geoprocessing` | Run **any** ArcPy tool by dotted name |
| `create_layout` / `export_layout` | Build and export print layouts (PDF/PNG/...) |

`execute_python` (arbitrary `arcpy`) exists but is **disabled** unless you set
`ARCPRO_MCP_ALLOW_EXEC=1` in **both** the client env and the ArcGIS Pro env.

## Configuration

| Variable | Default | Description |
| --- | --- | --- |
| `ARCPRO_MCP_HOST` | `127.0.0.1` | Bridge host |
| `ARCPRO_MCP_PORT` | `18748` | Bridge port |
| `ARCPRO_MCP_TRANSPORT` | `stdio` | `stdio` or `streamable-http` |
| `ARCPRO_MCP_ALLOW_EXEC` | _(off)_ | Enable `execute_python` (`1`/`true`) |
| `ARCPRO_MCP_AUDIT_LOG` | `~/.arcpro_mcp/audit.log` | Audit log path (empty to disable) |
| `ARCPRO_MCP_LOG_LEVEL` | `INFO` | Server log level |

## Safety

- Read-only tools are annotated `readOnlyHint` and are always safe.
- Destructive tools (coming next) require confirmation via MCP elicitation.
- `execute_python` is opt-in and double-gated (client + bridge).
- Every requested operation is appended to an audit log for review/replay.

## Roadmap

- [x] v0.1 — socket bridge, read-only tools, audit log, CI, tests
- [ ] v0.2 — write tools (add/remove layer, selection, geoprocessing) with HITL confirm
- [ ] v0.3 — `execute_python` hardening, **reflection middleware** (CRS/units sanity), layouts & export
- [ ] v0.4 — main-thread dispatch queue / optional **.NET Add-In (QueuedTask)** for rock-solid `arcpy.mp`
- [ ] v1.0 — installer, multi-client docs, compound tool mode to cut tokens

## License

MIT — see [LICENSE](LICENSE).

## Acknowledgements

Architecture informed by the excellent
[nkarasiak/qgis-mcp](https://github.com/nkarasiak/qgis-mcp),
[jjsantos01/qgis_mcp](https://github.com/jjsantos01/qgis_mcp),
[geo2004/MCP-ArcGISPro](https://github.com/geo2004/MCP-ArcGISPro), and the safety patterns in
[gdal-mcp](https://github.com/Wayfinder-Foundry/gdal-mcp).

TDQS

A3.7/5.0

Scored across 25 tools

Disambiguation5/5

Each tool targets a distinct operation or data type. 'list_*' tools operate on different entities (directory, feature classes, fields, layers, layouts), and 'get_*' tools retrieve different information. No overlapping purposes.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., add_raster_layer, list_layers, select_by_attribute). Even 'ping' fits as a common verb. No mixing of conventions.

Tool Count4/5

With 25 tools, the server covers a broad range of ArcGIS Pro functionalities without being excessive. It is slightly on the high side but well-scoped for the domain.

Completeness3/5

The set covers core workflows: data loading, querying, selection, geoprocessing, and layout creation. However, it lacks tools for spatial selection, feature editing, symbology control, and other advanced operations common in GIS.

Maintenance

ActivityInactive
ResponsivenessNo issues