TXLookup · Use as agent · MCP server

Sourced civic data, wherever your agent lives.

One MCP server. Eight tools. 6,061 Texas datasets indexed across 6 portals — Austin, Dallas, San Antonio, Houston, TX state. 9 deeply curated; the rest answered on demand. Install in 30 seconds. Verify in 60.

Why TXLookup, not a wrapper

Six reasons your agent should use this instead of writing its own SoQL.

Citation-enforced

The tool loop structurally cannot return without `cite_dataset`. ChatGPT-style hallucination is a class of bug we don't have.

Multi-agent reasoning, visible

Orchestrator + 3 specialists + critic + dataset scout. Every step tagged with the responsible agent. Watch them collaborate at /q.

Doom-loop guard

Pattern-based detection (3+ identical OR [A,B,A,B]) catches stuck agents and triggers replan with diagnosis. Patentable; tests in tests/test_doom_loop.py.

Cache-first SoQL with cross-dataset JOINs

SQLite cache mirrors curated columns. Cross-dataset SQL joins Socrata's SoQL can't express. Source pill (cache | live | cache-fallback) on every tool envelope.

Always-on dataset scout

Multi-city cron scans Austin / Dallas / SA / Houston / state portals every 6h, files GitHub issues for new datasets. The corpus grows by itself.

Replayable run archive

Every accepted answer is fingerprinted + saved. /admin/replay/{hash} re-streams the full SSE flow. Demo insurance + audit trail.

Install

Pick your runtime. Copy. Paste. Done.

TXLookup ships as a stdio MCP server. Any client that speaks MCP can install it — Claude Code, Codex CLI, Cursor, your own Python orchestrator. Smithery-listed via smithery.yaml at the repo root. Requires Python 3.11+ and an OpenAI API key.

Claude Code

claude-code

Install

claude mcp add txlookup -- python -m mcp.server

Verify

claude --message "use txlookup to list food truck permits in 78702 last 6 months"

Codex CLI

codex

Install

codex mcp add txlookup --command python --args -m --args mcp.server

Verify

codex "use txlookup ask_data: which Austin zips have the most code violations this year"

Cursor

cursor

Install

Settings → MCP → Add: { "txlookup": { "command": "python", "args": ["-m", "mcp.server"] } }

Verify

In chat: "@txlookup ask: 311 response times across the 10 council districts"

Custom MCP client

custom

Install

import the server: python -m mcp.server  # speaks MCP stdio

Verify

POST { "method": "tools/call", "params": { "name": "ask_data", "arguments": { "query": "..." } } }
~/txlookup · pre-install
$ git clone https://github.com/ATX-TXLookup/TXLookup
$ cd TXLookup && pip install -r requirements.txt
$ export OPENAI_API_KEY=sk-…
$ python -m mcp.server  # speaks MCP stdio

Prove it works

Sixty seconds to a sourced answer.

Option 1 · Hosted, no install

Hit the live agent at /q. Watch the DAG light up in the right column. Every node carries an agent name + source pill (cache / live).

Try a marquee query →

Option 2 · One-shot smoke from your shell

After install, run this from anywhere. Returns a JSON envelope with answer + citation.

~/anywhere · smoke test
$ echo '{"query":"food truck permits 78702 last 6mo"}' \
  | python -c '
import asyncio, json, sys
from mcp.server import ask_data
print(asyncio.run(ask_data(json.load(sys.stdin)["query"])))'

What you get

Eight tools, all bounded, all cited.

Full machine-readable catalog at mcp/manifest.json. Skill doc with safety rules at skills/txlookup/SKILL.md. Reference docs at /docs.

  • ask_data

    End-to-end loop. Plain-English question → plan → tool dispatch (with replan on failure + doom-loop guard + critic-driven revision) → cited answer.

    { "query": "Where do permits and code violations both spike together this year by zip?" }
  • discover_datasets

    Find a TX civic dataset for a topic. Returns up to 5 candidates from the curated catalog.

    { "query": "311 service requests", "city": "Austin" }
  • get_dataset_schema

    Inspect a dataset's columns, types, and field-name aliases before SoQL. Run BEFORE fetch_data on a fresh dataset.

    { "dataset_id": "3syk-w9eu" }
  • fetch_data

    Bounded SODA fetch (≤100 rows). Cache-first; live fallback. Returns _source: cache | live | cache-fallback so callers can audit provenance.

    { "dataset_id": "3syk-w9eu", "where": "original_zip='78702' AND issue_date >= '2026-01-01'" }
  • get_task_status

    Poll status of a long-running ask_data task started in async mode.

    { "task_id": "task_01HZ…" }
  • create_miro_board

    Create a Miro board for visualizing agent results. Returns board id + URL.

    { "name": "Austin permit hotspots Q2 2026", "description": "Built by ask_data" }
  • add_to_miro

    Post a structured payload (frame + sticky grid + chart card) to an existing Miro board.

    { "board_id": "uXjVM…", "items": ["frame", "sticky_grid", "chart_card"] }
  • list_known_tools

    Self-introspection: returns this tool catalog. Useful for agents that load the server dynamically.

    {}