Skip to main content
Glama
Houston Open Data MCP

Houston Open Data MCP

by Sandysmile
README.md
# Houston Open Data MCP

An MCP server that lets an AI assistant search and read public data from the
[City of Houston Open Data portal](https://data.houstontx.gov), which runs on CKAN.

Built from the [GSA MCP hackathon template](https://github.com/GSA-TTS/mcp-hackathon-template)
as a **Dataset Access Server**. It is read-only, and it needs no key or sign-in.

> Hackathon prototype. Not an official City of Houston service.

## Tools

| Tool | What it does |
|---|---|
| `houston_search_datasets` | Search the catalog by keyword, department, or topic |
| `houston_get_dataset` | Open a dataset and list its resources |
| `houston_describe_table` | List a table's columns and row count |
| `houston_query_records` | Read rows with filters, sorting, and paging |
| `houston_list_organizations` | List departments and their dataset counts |
| `houston_list_groups` | List topic groups and their dataset counts |

The server also offers two prompts (`explore_houston_topic`, `compare_by_geography`)
and two resources (`houston://info/server`, `houston://docs/join-keys`).

## Run it on your computer

Install [uv](https://docs.astral.sh/uv/), then, in PowerShell or any terminal:

```bash
uv sync --group dev
uv run pytest tests/ -v
uv run streamlit run streamlit_app.py
```

The page opens at <http://localhost:8501> and the MCP endpoint is
`http://localhost:8501/api/mcp`. Check the endpoint from a second terminal:

```bash
uv run python scripts/smoke_test.py http://localhost:8501/api/mcp
```

To run it as a local stdio server for Claude Code instead, use `uv run python main.py`.

## Chat agent

The page's **Ask** tab is a chat agent that uses Claude and the same read-only tools.
It needs `ANTHROPIC_API_KEY` and `APP_PASSWORD`, set as Streamlit secrets or locally in
`.streamlit/secrets.toml`, which Git ignores. Copy `.streamlit/secrets.toml.example` to
start. API usage is billed separately from a Claude plan.

## Host it

See **[deploy/streamlit/README.md](deploy/streamlit/README.md)**. One process serves
the Streamlit page at `/` and MCP at `/api/mcp`. The template's IBM, Databricks, and
cloud.gov kits in [deploy/](deploy/README.md) also still work, and serve MCP alone at `/mcp`.

## Repo layout

```
streamlit_app.py            # Streamlit host: page + /api/mcp
Dockerfile.streamlit        # Same host, in a container
main.py                     # Local stdio entry point
src/houston_opendata/
├── app.py                  # Builds FastMCP, picks the transport
├── portal.py               # Read-only CKAN client, shared by the tools and the page
├── page.py                 # Streamlit page
├── config.py, models.py, utils.py, routes.py
├── tools/                  # One file per tool
├── prompts/
└── resources/
scripts/smoke_test.py       # Checks a running server with a real MCP client
tests/                      # Tests that run without network access
eval/EVALUATION.md          # Evaluation write-up for the hackathon submission
deploy/                     # Deployment kits
```

## Add a tool

Create `src/houston_opendata/tools/my_tool.py` with a `register(mcp)` function, then
call it from `tools/__init__.py`. Put any portal call in `portal.py`.

## Security

- Tools use only allow-listed CKAN read actions. There is no SQL endpoint and no write action.
- The portal address comes from server configuration, never from a tool argument.
- Identifiers are validated before any request, and upstream errors are sanitized.
- The endpoint has no authentication, which suits public data. Review your agency's
  requirements before using it beyond the hackathon.

## License

[MIT](LICENSE). See [SECURITY.md](SECURITY.md).