# Call the gateway

> Two-stage discovery, one call, and what a refusal means — locally today, publicly once the endpoint is served.


One gateway, two functions: policy (rate, session budget, typed refusals) and aggregation (flat names, deterministic tool list, two-stage discovery). Behind it two interfaces to federal infrastructure: fedlex over the public Fedlex SPARQL endpoint, lindas over the 44 political data cubes of the Federal Chancellery.

**State:** `mcp.openhelvetia.swiss/mcp` is prepared and not served. Everything here describes the built state as the tests prove it. It runs locally today; how is in [Run, test and call the MCP gateway](../infrastructure/module-mcp-gateway.md).

## The three doors {#tueren}

| Door | For whom | Note |
|---|---|---|
| MCP over stdio | local hosts and tests | the machine door; the process is the session |
| MCP streamable HTTP `/mcp` | agents and hosts over the network | the intended public door (revision 2026-07-28) |
| JSON shell `GET /tools`, `POST /tool/<id>` | simple clients, this website's chat | local; not a production transport; same tools, same refusals |
| Relay `/relay/infomaniak/<product>/…` | this website's chat, for a provider whose API refuses browser calls | forwards `chat/completions` and `models` with the visitor's own key to Infomaniak and nowhere else; stores and logs nothing of it; open only where the operator sets `--relay` (E16, revision 05.09.2026) |

## Two-stage discovery {#entdeckung}

1. **meta.tools.** Every tool with id, domain, one-liner and weight, without input schemas. Costs 1.
2. **meta.schemas.** The full input schemas only of the named ids, typically three to five.
3. **Call.** Both stages and `tools/list` read the same router; the schemas are byte-identical.

One row from stage one, verbatim from the tool inventory:

```json
{
  "id": "fedlex.resolve_sr",
  "domain": "fedlex",
  "summary": "Resolve an SR number (e.g. 832.10) to the act's ELI, titles and in-force status: use when a question names an SR; predecessors stay visible. norm.",
  "weight": 2
}
```

## A call through the JSON shell {#aufruf}

```bash
curl -s http://127.0.0.1:8700/tools
curl -s -X POST http://127.0.0.1:8700/tool/meta.schemas -H 'content-type: application/json' -d '{"names": ["fedlex.resolve_sr", "fedlex.read_article"]}'
curl -s -X POST http://127.0.0.1:8700/tool/lindas.list_cubes -H 'content-type: application/json' -d '{}'
```

## The first message over MCP streamable HTTP {#discover}

```text
POST https://mcp.openhelvetia.swiss/mcp
Accept: application/json, text/event-stream
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
MCP-Method: server/discover

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "server/discover",
  "params": {
    "protocolVersion": "2026-07-28",
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
```

Both Accept types, version and method headers, `params._meta` with both keys: if one is missing, a conforming server refuses the request before any MCP logic runs.

## Limits {#grenzen}

Session budget: a weighted hard limit (register read 1, domain call 2), it does not recover. Rate: default 60 weight units per minute, burst 20, per client. A refusal costs nothing. The six refusals are in the [reference](../reference/refusals.md).

---

Source: docs/en/how-to/call-the-gateway.md
