Tlhano speaks MCP (Model Context Protocol) over Streamable HTTP. Point any MCP client at the endpoint below and it gets five tools: encode, decode, parse, suggest and about. No key is required today.
| Endpoint | https://mcp.tlhano.com/mcp |
|---|---|
| Protocol | MCP Streamable HTTP — JSON-RPC 2.0 over HTTP POST |
| Sessions | stateless: every request stands alone, no session id, no SSE stream required |
| Auth | none (open). If keys are ever enabled, send Authorization: Bearer <key> |
| Content | send Accept: application/json, text/event-stream; responses are plain JSON |
In an MCP client's configuration, the server is a remote HTTP entry:
{
"mcpServers": {
"tlhano": { "url": "https://mcp.tlhano.com/mcp" }
}
}
A stateless server still answers initialize. Tell it who you
are; it answers with its capabilities. Then list the tools.
# initialize curl -s https://mcp.tlhano.com/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize", "params":{"protocolVersion":"2025-03-26","capabilities":{}, "clientInfo":{"name":"my-agent","version":"0.1"}}}' # the real response {"jsonrpc":"2.0","id":1,"result":{ "protocolVersion":"2025-03-26", "capabilities":{"tools":{}}, "serverInfo":{"name":"tlhano","version":"0.1.0", "title":"Tlhano — five words, one place"}}} # tools/list (send {"jsonrpc":"2.0","id":2,"method":"tools/list"})
Because the server is stateless you may skip the handshake and call a
tool directly — but sending initialize first keeps generic
MCP clients happy, and it is the polite thing to do.
| Tool | Arguments | Returns |
|---|---|---|
tlhano_encode | lat, lng numbers — or q, any free-form input (decimal, DMS, GPS, Maps URL) | the five-word address, cell token, ordinal, centre |
tlhano_decode | address — five words | latitude/longitude of the cell centre |
tlhano_parse | q — free-form coordinate text | the parsed latitude/longitude and the recognised format |
tlhano_suggest | address, optional limit | ranked valid repairs of a near-miss address |
tlhano_about | — | scheme metadata: constants, vocabulary hash, spec pointer |
Calling a tool — coordinates in, five words out:
# request {"jsonrpc":"2.0","id":3,"method":"tools/call", "params":{"name":"tlhano_encode", "arguments":{"lat":-24.64492,"lng":25.90733}}} # the real response {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":{ "address": "common.circuit.shipped.assist.talking", "center": {"lat": -24.64492931, "lng": 25.90733512}, "cell": {"token": "1ebb5b0458a3", "id": "2214463716007804928", "level": 22, "ordinal": 16895017364561}, "precision": {"avg_area_m2": 4.83} }}],"isError":false}}
Tool results arrive as text content — parse the inner JSON from
content[0].text. isError is the honest signal:
check it before trusting the payload.
A mis-heard or mistyped word is not a crash — it is a structured answer
with a repair path. The decode tool answers isError: true
with a Tlhano error code; feed the address to
tlhano_suggest and you get ranked valid candidates.
# tlhano_decode("common.circuit.shipped.assist.talkin") — last word mis-heard {"result":{"content":[{"type":"text","text":{ "error": {"code": "E_WORD_UNKNOWN", "message": "not in the tlhano vocabulary: talkin", "details": {"unknown": ["talkin"], "vocabulary": "en-4096"}} }}],"isError":true}} # tlhano_suggest on the same input returns the repair: # common.circuit.shipped.assist.talking -24.644929, 25.907335
| Code | Meaning | What an agent should do |
|---|---|---|
E_FORMAT | not five words / wrong shape | if it looked like coordinates, use tlhano_encode with q instead |
E_WORD_UNKNOWN | a word is not in the vocabulary | call tlhano_suggest with the input |
E_CHECKSUM | all words known, check word fails | call tlhano_suggest — a one-word slip is repairable |
E_OUT_OF_RANGE | valid shape, no such cell | the address is forged or from another vocabulary; ask for the source |
E_PARAM | bad arguments | fix the parameters against the tool schema |
E_RATE_LIMITED | HTTP 429 | back off for the Retry-After seconds, then resume |
Every tool has a plain-HTTPS equivalent at
https://api.tlhano.com/v1/ — for scripts, cron jobs and
agents that never leave HTTP:
| Endpoint | Same as |
|---|---|
GET /v1/encode?lat=&lng= · GET /v1/encode?q= | tlhano_encode |
POST /v1/encode (JSON array, ≤ 100 points) | batch encode |
GET /v1/decode?address= | tlhano_decode |
GET /v1/parse?q= | tlhano_parse |
GET /v1/suggest?address= | tlhano_suggest |
GET /v1/about | tlhano_about |
curl -s "https://api.tlhano.com/v1/encode?lat=-24.64492&lng=25.90733"
Full parameter reference, schemas and every response example: doc.tlhano.com.
240 requests per minute per client at the application layer, and a
20 request/second burst ceiling at the edge. Exceeding either returns
HTTP 429 with Retry-After: 60 — honour it rather than
retrying blind. If you are geocoding a fleet of devices, use the batch
endpoint: one POST per 100 points is always kinder than 100 POSTs.
All three services are read-only; there is nothing an agent can break.