# Ask a question through the MCP server

> Connect your AI assistant to the MCP server with a sandbox key, ask it a question, and see the calls it makes.

After this recipe your AI assistant can answer questions from the sandbox through the MCP server, and you will have made the same calls it makes by hand.

**Uses:** the MCP server at `https://data.heytownhall.com/mcp`. The handshake and the tool list are free; each tool call is one request on its tool's meter.

## 1. Connect your assistant

Most AI assistants that accept a remote MCP server take a settings block like this one. Put in your sandbox key:

```json
{
  "mcpServers": {
    "hey-town-hall-data": {
      "url": "https://data.heytownhall.com/mcp",
      "headers": { "Authorization": "Bearer htd_test_..." }
    }
  }
}
```

An assistant that asks for the settings in another form needs the same two things: the address and the `Authorization` header. A desktop assistant usually reads this block from its settings file; an assistant you build passes the address and header to its MCP library.

## 2. Ask it a question

Ask about a sandbox town, and ask for sources:

> Which tenders are open in Port Ellery, and when do they close? Link each one.

The assistant finds `list_bids` in the tool list and calls it with `jurisdiction` set to `port-ellery`. The answer carries each bid's `closes_at`, `source_url` and `read_at`, and the server tells the assistant to cite them. Its reply should name the two sandbox tenders, the Eastside water main replacement and snow clearing, each with a link under `bids.example`.

If the assistant says it has no such tool, check the connection: [Connect the MCP server](https://data.heytownhall.com/docs/mcp) has a `curl` that sends the first message a client sends.

## 3. Make the same calls yourself

An assistant speaks to the server in JSON-RPC over HTTP. This script sends the three messages it sends for that question: the handshake, the tool list and the tool call. The server answers each as a server-sent event, one `data:` line of JSON.

```python
import json
import os

import requests

MCP = "https://data.heytownhall.com/mcp"
HEADERS = {
    "Authorization": f"Bearer {os.environ['HTD_KEY']}",
    "Accept": "application/json, text/event-stream",
}

def rpc(id, method, params):
    res = requests.post(MCP, json={"jsonrpc": "2.0", "id": id, "method": method, "params": params}, headers=HEADERS, timeout=30)
    res.raise_for_status()
    if res.headers["Content-Type"].startswith("text/event-stream"):
        data = [line[len("data: "):] for line in res.text.splitlines() if line.startswith("data: ")]
        return json.loads(data[-1])
    return res.json()

hello = rpc(1, "initialize", {"protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": {"name": "recipe", "version": "1.0.0"}})
print("Server:", hello["result"]["serverInfo"]["name"])

tools = rpc(2, "tools/list", {})["result"]["tools"]
print("Tools:", len(tools))

call = rpc(3, "tools/call", {"name": "list_bids", "arguments": {"jurisdiction": "port-ellery"}})["result"]
if call.get("isError"):
    raise RuntimeError(call["content"][0]["text"])
page = json.loads(call["content"][0]["text"])
for bid in page["results"]:
    print(bid["closes_at"], bid["title"], bid["source_url"])
```

## What the sandbox prints

```text
Server: hey-town-hall-data
Tools: 28
2026-11-21T22:00:00.000Z ITT 2026-06: Snow clearing services 2026-2028 https://bids.example/port-ellery/100009
2026-11-20T22:00:00.000Z RFP 2026-00: Eastside water main replacement https://bids.example/port-ellery/100006
```

## Going further

- **Search first.** For an open question ("has any town talked about battery storage?"), the assistant starts with `search_records`. The server tells it to begin there or with `find_jurisdictions`.
- **Keep the sandbox key** while you test prompts. Calls on it are free, and the answers are in the live shapes.
- **Every tool,** what it does and what it takes, is in [Connect the MCP server](https://data.heytownhall.com/docs/mcp).
