opendata-atlas
Agent-friendly access to public Socrata open-data portals, as an MCP server. It is read-only: it reads public datasets through each portal's SODA API and writes nothing.
Status: preview. Nothing is published yet; until the first release, run the server from a checkout (Try it locally). The server holds a registry of public Socrata portals; atlas_find_portals lists them. Three portals are curated: Seattle (seattle), Chicago (chicago) and City of Everett (everett).
Tools
| Tool | Purpose |
|---|---|
atlas_find_portals |
Find portals by place name, alias, portal name or host |
atlas_search_datasets |
Find a portal's datasets by topic |
atlas_describe_dataset |
Columns, row count, time coverage, place fields, geo columns, knowledge level |
atlas_query_dataset |
Bounded reads and aggregates (SoQL clauses or raw SoQL) |
atlas_get_reference |
Capability summary, SoQL help, portals, guides, error catalog |
Choosing a portal
Every data tool takes a required portal: a portal id (its hostname, such as data.seattle.gov) or an alias (such as seattle). Without the id, call atlas_find_portals with a place name. It never picks for you: a city and its county are both candidates, told apart by jurisdiction.level, and the server's rules tell the agent to ask the user which one they mean unless the request names the level.
Knowledge levels
Portals are tiered (generic, profiled, curated), but the tier never vouches for a dataset. atlas_describe_dataset reports a knowledge level for the dataset: none (nothing recorded), profiled (the profiler recorded observations that nobody reviewed) or reviewed (a contributor reviewed its unit of observation, place fields and primary time column). atlas_query_dataset adds a knowledge_notice when the dataset is not reviewed, or when your query uses a place or time column with no reviewed claim. Each knowledge also reports validation, what the claims' checks found when the drift run (uv run pytest --run-integration -m integration) last ran them: passed, contradicted or inconclusive, unchecked for a claim with no check, and stale when the checks last ran over 180 days ago by the server's clock. The server reads the recorded outcomes and runs no check itself. A stale claim stops vouching for the data: for example, a place field it reviewed as ok reports unknown, and coverage_warnings fire on it.
Install
These paths work after the first release, which has not happened yet; until then, use Try it locally. The server runs over stdio. The uvx commands below need uv.
Claude Desktop: download opendata-atlas-<version>.mcpb from the latest release and open it with Claude Desktop.
Claude Code:
claude mcp add opendata-atlas -- uvx opendata-atlas
Codex:
codex mcp add opendata-atlas -- uvx opendata-atlas
Any other MCP client: run uvx opendata-atlas as a stdio server:
{
"mcpServers": {
"opendata-atlas": { "command": "uvx", "args": ["opendata-atlas"] }
}
}
Try it locally
Three ways to run the server before it is published, each from a checkout and each over stdio. Each needs uv; path (c) also needs the mcpb CLI (npm install -g @anthropic-ai/mcpb). Replace /path/to/opendata-atlas with the absolute path of your checkout.
By default (--scope local), claude mcp add makes the server available only to you, in the current project. To use it in every project, add --scope user. For Claude Desktop, merge the snippet's opendata-atlas entry into mcpServers in claude_desktop_config.json (on macOS, ~/Library/Application Support/Claude/claude_desktop_config.json), then restart Claude Desktop. If Claude Desktop cannot find uv or uvx, set command to the absolute path that which uv or which uvx prints.
(a) From the checkout. The server runs from your working tree, so edits take effect on the next start.
claude mcp add opendata-atlas -- uv run --directory /path/to/opendata-atlas --frozen opendata-atlas
{
"mcpServers": {
"opendata-atlas": {
"command": "uv",
"args": ["run", "--directory", "/path/to/opendata-atlas", "--frozen", "opendata-atlas"]
}
}
}
(b) From a built wheel. Run uv build in the checkout; it writes the wheel and sdist to dist/. Replace /path/to/dist with the absolute path of that dist/ directory.
claude mcp add opendata-atlas -- uvx --from /path/to/dist/opendata_atlas-0.1.0-py3-none-any.whl opendata-atlas
{
"mcpServers": {
"opendata-atlas": {
"command": "uvx",
"args": ["--from", "/path/to/dist/opendata_atlas-0.1.0-py3-none-any.whl", "opendata-atlas"]
}
}
}
(c) From the bundle (Claude Desktop only). Run make mcpb in the checkout. Open dist/opendata-atlas-0.1.0.mcpb with Claude Desktop and follow its install prompt. The app token setting is optional: leave it blank to run without one.
To check a path without a client, run scripts/smoke_test.py from the checkout. It starts the server the same way and checks offline that it answers: uv run python scripts/smoke_test.py --checkout . for (a); after (b)'s uv build, --uvx dist/opendata_atlas-0.1.0-py3-none-any.whl; after (c)'s make mcpb, --bundle dist/opendata-atlas-0.1.0.mcpb. Add --live for one free live call to Seattle's portal.
Configuration
SOCRATA_APP_TOKEN(optional): a Socrata application token, for exampleclaude mcp add opendata-atlas -e SOCRATA_APP_TOKEN=... -- uvx opendata-atlas. The bundle asks for it in Claude Desktop's settings. A rejected token is reported asapp_token_rejected, never silently dropped. Whether one token is accepted by every portal is unprobed.OPENDATA_ATLAS_PORTALS(optional): a comma-separated list of portal ids or aliases. Set, it limits the server to those portals; any other fails withportal_not_enabled. Unset or blank, every registered portal is served.
Adding a missing portal
If a Socrata portal is not in the registry:
- Add an entry for it to
src/opendata_atlas/portals/registry_overrides.toml. The comments in the file anddocs/design.md(Registry) describe the fields. - Open a pull request.
scripts/build_registry.pyrebuildsregistry.jsonfrom the entries and fails unless the portal is eligible and its identity holds.
Issues
Report bugs and gaps at github.com/briandconnelly/opendata-atlas/issues.
Develop
From a checkout:
uv sync
uv run opendata-atlas # run the server over stdio
uv run pytest
uv run ruff check && uv run ruff format --check && uv run ty check
UPDATE_SNAPSHOTS=1 uv run pytest tests/test_contract.py # after an intended tool-surface change
uv run pytest --run-integration -m integration # live tests against Socrata portals
uv run python evals/run.py [--host claude|codex] <out_dir> [task_id ...]
uv run python evals/report.py <out_dir> --answers
To build the MCPB bundle locally: make mcpb (needs the mcpb CLI; see Try it locally, path (c)).
Release
Tag vX.Y.Z after bumping the version: the release workflow builds and smoke-tests the wheel, sdist, and .mcpb, publishes to PyPI after maintainer approval, and attaches all three to a GitHub Release. See docs/releasing.md for the steps. Before the first release, work through docs/release-checklist.md: the one-time setup, the TestPyPI rehearsal and the maintainer's open decisions.
The documentation is this README and the files in docs/, as they stand in the repository; there is no hosted docs site.
License
MIT
Metadata
Release files for opendata-atlas 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| opendata_atlas-0.1.0.tar.gz | 155.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| opendata_atlas-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 345.0 kB
Release files / opendata_atlas-0.1.0.tar.gz
| Download URL | opendata_atlas-0.1.0.tar.gz |
|---|---|
| Size | 155.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
025d69e0349a281ab7052498dfc7f9ebaa64da5f199e5047d959373d9b4f5ca0
|
|
BLAKE2b-256 checksum How to use checksums |
8145258a8e304cac8b4e032aa165a642971fd9844b2a05f1e62dbaad403a12a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / opendata_atlas-0.1.0-py3-none-any.whl
| Download URL | opendata_atlas-0.1.0-py3-none-any.whl |
|---|---|
| Size | 189.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d4dc1feb1cd684a5888e489eec850216051bf630d45defa6950708f1c299ad23
|
|
BLAKE2b-256 checksum How to use checksums |
a717b01d67c189fa271ac27d0e799a7b7c098177005d59eb36341c6370d79400
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for opendata-atlas 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for opendata_atlas-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.