# GeoDa: exploratory spatial data analysis with an MCP server attached

> GeoDa is a desktop application for exploratory spatial data analysis on lattice data, built at the GeoDa Center and shipping full space-time support, a new cartogram, 3D visualisation and spatial regression. The repository also carries a built-in MCP server that lets an agent drive the software's spatial analysis commands, and a plugin that installs that server for the client to start.

**GeoDaCenter/geoda** — GeoDa: An introduction to spatial data analysis

- Repository: https://github.com/GeoDaCenter/geoda
- Website: http://geodacenter.github.io
- Stars: 809 · Forks: 161
- Language: C++
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/geodacenter-geoda

## What GeoDa is for and where it came from

GeoDa is an introduction to spatial data analysis, and the README describes it in the academic terms: it is designed to implement techniques for exploratory spatial data analysis on lattice data, points and polygons, with a user friendly graphical interface to methods of descriptive spatial data analysis such as spatial autocorrelation statistics, as well as basic spatial regression functionality.

The lineage matters for how you read the interface. GeoDa is the flagship program of the GeoDa Center, following a long line of software tools developed by Dr. Luc Anselin, and it has been in continuous use since its initial release in February 2003. The README names lab users at Harvard, MIT and Cornell, and it is a tool built by a geographer for geographers rather than a general purpose data platform.

The scope is lattice data, and that is a real constraint. Lattice means data attached to a fixed set of locations, points or polygons, with the spatial relationships between them fixed in advance. Continuous field data, where you sample a surface at arbitrary coordinates, is a different problem and a different set of methods, and GeoDa is not built for it.

The licence field on the repository says GPL-3.0, with a COPYING file at the root, and the primary language is C++.

The recent releases are v1.22.1 from 2026-08-26, v1.22.0.21 from 2025-09-25 and v1.22.0.20 from 2025-07-31, and the last push was on 2026-10-13. There are CI badges for macOS, Ubuntu and Windows builds, so the three desktop platforms are all built continuously.

## The feature set in the current version

The README calls out the newest features explicitly, and they describe a substantial release rather than a patch.

Full space-time data support in all views is the first, and it is the one that changes the character of the tool. Spatial data analysis has a strong static tradition, where you have a shapefile and you look at it, and the space-time work means you can treat a set of observations over time as the primary object rather than as repeated snapshots of a map.

Then there is a new cartogram, which is a map where the geometry is distorted so that area reflects the value of the variable rather than the land, and a refined map movie, which is the animated version of the same idea and is the classic way of showing a spatial pattern changing over time.

A parallel coordinate plot is included, which is how you look at many variables across many observations at once and find the outliers that a table hides.

Three-dimensional visualisation is listed, and it is worth being clear about what that means in a desktop analysis tool. It is a way of seeing a spatial pattern in depth, not a scientific visualisation package.

Conditional plots and maps are included, which is the diagnostic that lets you select a subset of the data interactively, for instance one cluster of points, and see the rest of the variables for just that subset.

And spatial regression is in the list, with the README describing the program as providing basic spatial regression functionality alongside the descriptive methods. That pairing is the point of the tool, since running an ordinary regression on spatial data and then running a spatial one and comparing the coefficients is the standard way of showing that the spatial structure matters.

## The MCP server and its two tools

The most unusual thing in this repository is not the analysis software. It is a built-in MCP server that lets an agent drive GeoDa's spatial analysis commands, and the README describes its design in unusual detail.

The server ships a skill, the spatial data analysis workbook, and serves it to MCP clients itself, so an agent that connects to GeoDa can read it with nothing installed. It exposes two MCP tools. list_command returns the catalog, with each command's id, group and parameters, and execute_command with a name and arguments runs one.

What makes this readable in the README is the explanation of how the same text reaches a client four ways. The `skill/get` command, listed by `skill/list`, takes the uri `skill://spatial-analysis-workbook`, and exists so that a client which does not expose MCP resources can still read the skill. The resource `skill://spatial-analysis-workbook` is served through `resources/read`. The prompt `spatial-analysis-workbook` is served through `prompts/get`, and its `section` argument loads one part: `workflow`, `overview`, `maps`, `weights`, `global`, `local`, `rates`, `multivariate`, `clustering`. And the `instructions` that `initialize` returns name the skill and explain how to read it.

The section list is the vocabulary of the whole method, and it is worth reading as a table of contents for exploratory spatial data analysis: workflow, overview, maps, weights for the spatial weight matrix, global and local statistics, rates, multivariate and clustering.

The design decision behind the four routes is redundancy. A client may expose resources, may not, may support prompts, may not, so the same document is offered through whichever mechanism the client understands. The cost is duplication, and the README is candid that the text has to be kept in step across three files.

## The three-file editing contract

The README spends a lot of space on how to edit the skill, and the reason is that the duplication is a maintenance hazard that the project handles head-on.

The text lives in three files and all three have to be edited together. MCP/skills/spatial-analysis-workbook.md is the authoring source and the copy a human reads. MCP/McpResources.cpp, in the WorkbookSkillText() function, holds the whole document as the C string that skill/get and the resource serve. MCP/McpPrompts.cpp, in GuideText() and SectionText(), holds the same guide split into the prompt's sections.

The rules for editing are specific. The FIRST: Always load this skill section is the contract that makes an agent read the workbook before it calls anything, and the instruction is to keep it and keep it first.

Commands and parameters have to be named exactly as they are registered in MCP/McpCommands.cpp, because that document is their documentation. Commands reach a client only through execute_command, with MCP/McpTools.cpp building the two tool schemas and list_command reporting the same registry. So the skill text is where a command's workflow is described, and a mismatch between the skill and the registry is a documentation bug that only an agent will notice.

Adding a section means a new kSectionKeys and kSectionLabels entry, a SectionText() branch, and a matching heading in the markdown file. And if how the skill is delivered changes, the instructions in MCP/McpServer.cpp need updating too.

To see what a client actually sees, with GeoDa running on its default port 8765:

```
curl -s -X POST -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"execute_command","arguments":{"name":"skill/get","arguments":{"uri":"skill://spatial-analysis-workbook"}}}}' \
  http://127.0.0.1:8765/mcp
```

And the test that checks the whole arrangement.

```
GEODA_BIN=/path/to/GeoDa python3 MCP/tests/skill_serving_test.py
```

That test verifies that tools/list returns only list_command and execute_command, that the instructions point at the skill, that skill/get and resources/read return identical text, that the document still opens with the load-me-first section, and that an unknown URI is an error. A test that asserts skill/get and resources/read return identical text is exactly what a duplicated document needs.

## The plugin route and the launcher that must not drift

Alongside the server there is a second way for a client to reach GeoDa, and the README explains the difference in a way that makes the design choice clear.

GeoDa's MCP server can also reach a client as a plugin, which the client installs and starts itself, so the agent sees GeoDa's commands as tools rather than being handed the endpoint URL. The plugin is published from this repository, with .claude-plugin/marketplace.json for Claude Code and .agents/plugins/marketplace.json for Codex at the root, and the plugin itself under plugins/geoda/.

The install path is interesting because of the size of the repository behind it. A marketplace is looked for at the root of the repository it names, and this one is a large source tree, so the install asks for a sparse checkout of the three directories the plugin needs.

```
claude plugin marketplace add GeoDaCenter/geoda --sparse .claude-plugin .agents plugins
claude plugin install -y geoda@geoda
```

GeoDa does the same thing from its own window. Options, then MCP, then Install MCP Plugin gives a button for Claude Code and one for Codex, reports each step, and falls back to registering the HTTP endpoint by URL where a plugin install is not possible.

The fallback is the important design point. The plugin route is the good one, because the client starts the server and the agent never handles a URL. The URL route is the fallback for clients that cannot install a plugin, and it exists so the same capability works everywhere.

That means the launcher exists in three copies, in plugins/geoda/bin/geoda-mcp, in MCP/bin/geoda-mcp, and as the raw string MCP/McpClientSetup.cpp writes out for the direct route. The project knows this is a hazard, and MCP/tests/launcher_test.py fails when the three drift apart.

```
GEODA_BIN=/path/to/GeoDa python3 MCP/tests/launcher_test.py
```

The same pattern as the skill: duplicated for practical reasons, with a test that turns the duplication into a checked invariant.

## Building GeoDa and the internationalization effort

The build instructions are per platform and live in the BuildTools directory, with separate readme files for Windows, Mac OSX and Linux/Ubuntu. The README asks for contributions of build scripts under other platforms and says to follow the structure of the existing build scripts under BuildTools.

The build system is the classic make layout for a long-lived C++ project. The GNUmakefile at the root is the entry point, and there is a family of platform option files beside it, GeoDamake.opt and GeoDamake.ubuntu.opt, GeoDamake.focal.opt, GeoDamake.jammy.opt, GeoDamake.xenial.opt, GeoDamake.centos.opt, GeoDamake.bionic.opt, GeoDamake.macosx.opt and GeoDamake.silicon.opt. The names are distribution and release names, so the pattern is that each supported platform and distribution has its own option file, and adding a new one is a contribution the project explicitly wants.

The Dockerfile is minimal and mostly delegates. It starts from ubuntu:18.04, installs git and build-essential, copies the tree into /tmp/geoda, and then runs the Ubuntu install script with a specific OS, version and package manager set on the command line.

```
CMD OS="focal" VER="1.18.2" APT="sudo apt-get" WORK_DIR="/tmp/geoda/geoda/BuildTools/ubuntu" /tmp/geoda/geoda/BuildTools/ubuntu/install.sh
```

The internationalization project is a different kind of effort and worth knowing about if you are not an English speaker. GeoDa Internationalization and Localization aims to provide an online tool that users could help to translate the GeoDa interface into different languages, and for crowdsourcing it uses a public Google Spreadsheet that anyone can access and edit.

That is a pragmatic choice. A C++ wxWidgets application with a large string catalogue is not an easy translation target, and a shared spreadsheet that non-programmers can edit removes the barrier that a pull request would create.

## Where GeoDa is the wrong tool

The first limitation is that it is a desktop application and not a library. The topic tags name spatial-data-analysis and spatial-regression, and the primary language is C++, but there is no Python package to import. A data engineer who wants spatial statistics inside a pipeline will find the analysis available as something you drive through a graphical interface or now through the MCP server, and a script that shells out to the application is not the same thing as a library call. That is a real constraint for reproducibility, because a result produced by clicking through a GUI has to be re-created by whoever wants to check it.

The second is the lattice data constraint, already mentioned but worth repeating. Points and polygons with fixed spatial structure are the target. If your data is a continuous field, or if your polygons change between time steps in ways the space-time support does not handle, you are outside the design.

The third is the version of the statistical machinery. The README describes the spatial regression functionality as basic. That is the researcher's own word, and for a course, a tutorial, or an exploratory pass over a dataset it is entirely adequate, and for a publication where the estimator choice matters you would want to check the implementation against what you need.

The fourth is the MCP integration's surface area. The server exposes two tools and one document, and the document is triplicated in the source tree. That is a well-handled duplication, with tests, but it is duplication, and an agent that reads the skill and then calls a command whose parameters have drifted will get an error that reads as a tool failure rather than a documentation failure.

The fifth is that the MCP server is new relative to the application. The application's history goes back to 2003 and the tooling on top of it does not, so the two halves of this repository have very different maturity and it is worth being clear about which one you are relying on.

## GeoDa compared with Python spatial stacks and with a full GIS

The comparison with the Python spatial stack, with GeoPandas, Shapely, PySAL and the scikit-learn-adjacent spatial estimators, is the one most readers will want. The difference in approach is interactive exploration against programmatic analysis. A Python stack is what you use when you already know which statistic you want and you want it in a pipeline, with the data flowing through code that is versioned and tested. GeoDa is what you use when you do not yet know what the data is doing, and its value is the linked views where selecting a cluster in one view updates the map, the histogram and the table at once.

The most defensible way to use both is together. Explore in GeoDa, find which spatial weights and which local statistic answer the question, then reproduce that analysis in code for the pipeline. The MCP server makes that loop a little shorter, because an agent can call the analysis commands rather than a human clicking through dialogs.

The second comparison is with a full GIS such as QGIS, and the difference is scope. QGIS is a general purpose geospatial platform for handling projections, rasters, vector formats, geocoding and cartographic production. GeoDa is a statistical analysis workbench for a specific family of methods, and it is not a map production tool, a data management system or a format converter. They overlap on the map, and the overlap is a small part of what each does.

The third comparison is with R packages such as spdep or sf, which is the closest of the three. spdep carries much of the same statistics, Moran's I and LISA and the spatial weight matrix construction, in a language that fits an analysis pipeline, and it has a much larger extension ecosystem. GeoDa's advantage there is the interactive visualisation and the space-time and cartogram work, and the MCP server is the new way to reach that advantage from a tool that speaks to agents.

The fourth is a general point about exploratory analysis. Everything above assumes the exploratory part is where the value is, and if you already know your statistic and your specification, the R or Python route is faster and more reproducible.

## Licence, project history and what to verify first

The licence field on the repository says GPL-3.0, with the COPYING file at the root, and the README carries a Contributor Covenant code of conduct and a CONTRIBUTING.md. A copyleft licence is the right choice for a tool that ships a graphical interface, since anyone distributing a modified build has to publish the source, which keeps derived versions honest.

The project is not archived and the last push was on 2026-10-13, so it is being worked on. The version numbers, v1.22.1 and the two v1.22.0.x builds, show a mature release cadence for a project that has been running for over two decades, and the release history going back to the 2003 initial release is itself part of the case for the software's maturity.

The build badges for macOS, Ubuntu and Windows are the practical signal that this is a tool you can install on the platform you already use, and the per-distribution GeoDamake option files show that the build is maintained against current distributions rather than frozen against one.

Four things to check before you commit to it.

That the MCP server is what you actually want to use, since it is a new layer on a mature application, and that the two tools it exposes are the two you need. If you plan to edit the skill, read the three-file contract first, because the first instruction is that the load-me-first section must stay first, and run MCP/tests/skill_serving_test.py afterwards to confirm the four delivery routes still return identical text.

That your data is lattice data in the sense the software means, points or polygons with fixed spatial relationships.

That the statistics you need are implemented in the way you need, since the README calls the spatial regression functionality basic, and the documentation and the discussion around the GeoDa Center are the place to check that.

And if you are building the project rather than using it, that the platform you need has a build script, or that you are willing to contribute one following the structure of the existing ones under BuildTools.

## Conclusion

GeoDa suits a spatial analyst who wants local indicators of spatial association, a spatial regression and a spatial weight matrix in one graphical tool, and who now wants to script or automate part of that workflow through an agent. It is the wrong tool for a data engineer who wants a library, since it is a desktop application rather than a Python package, and the wrong choice for anyone who needs results that are reproducible from a script alone without the interface in the loop. Before wiring the MCP server to an agent, read the three-file editing contract in the README, because the skill text, the C string and the prompt sections have to change together, and run MCP/tests/skill_serving_test.py after any edit.

## FAQ

### What is GeoDa?

It is a graphical application for exploratory spatial data analysis on lattice data, points and polygons, from the GeoDa Center. It provides descriptive spatial data analysis methods such as spatial autocorrelation statistics along with basic spatial regression functionality, and the current version adds full space-time support, a new cartogram, a refined map movie, a parallel coordinate plot, 3D visualisation, conditional plots and spatial regression.

### What does the GeoDa MCP server expose?

It exposes two MCP tools, list_command which returns the catalog of commands with their id, group and parameters, and execute_command which runs one by name. It also ships a spatial analysis workbook skill that it serves to clients itself, so an agent can read it with nothing installed.

### How is the GeoDa MCP skill edited?

The text lives in three files that must all be edited together: the markdown authoring source, the C string in MCP/McpResources.cpp, and the split sections in MCP/McpPrompts.cpp. The README asks that the load-me-first section stays first, that command names match MCP/McpCommands.cpp exactly, and that MCP/tests/skill_serving_test.py is run afterwards.

### How do I install the GeoDa MCP plugin?

Run `claude plugin marketplace add GeoDaCenter/geoda --sparse .claude-plugin .agents plugins` and then `claude plugin install -y geoda@geoda`. The sparse checkout matters because the marketplace is looked for at the root of a large source tree. GeoDa can also do this from its own window under Options, MCP, Install MCP Plugin.

### How do I build GeoDa from source?

The per-platform instructions are in the BuildTools directory, with separate readme files for Windows, Mac OSX and Linux/Ubuntu, and the GNUmakefile at the root drives the build using per-platform option files such as GeoDamake.ubuntu.opt. The repository also ships a Dockerfile that runs the Ubuntu install script.

### What licence is GeoDa released under?

GPL-3.0, with the COPYING file at the root of the repository, along with a CONTRIBUTING.md and a code of conduct.

## Sources

- [GeoDaCenter/geoda on GitHub](https://github.com/GeoDaCenter/geoda)
- [License: GPL-3.0](https://github.com/GeoDaCenter/geoda/blob/master/LICENSE)
- [Project website](http://geodacenter.github.io)
- [README](https://github.com/GeoDaCenter/geoda/blob/master/README.md)
- [Releases](https://github.com/GeoDaCenter/geoda/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/geodacenter-geoda
