# MCP-Gateway

> The platform's machine door: the same tools over MCP and a JSON shell — 52 capabilities from two domains — with a call budget and typed refusals.

## What it does {#was}

The gateway is the platform's machine door: the same 52 capabilities over MCP and over a minimal JSON/HTTP shell, both through one dispatcher. Policy therefore lives in exactly one place — the call budget, the rate limit and the typed refusals happen once, whichever door the caller used. Discovery runs in two stages: «meta.tools» names every tool with a one-line summary, its domain and its price, and carries no input schema at all; «meta.schemas» hands over the schemas of only the tools an agent actually named. Two interfaces to federal infrastructure are mounted behind it, fedlex with 35 tools and LINDAS with 8, and their stage-one lines are the servers' own, verbatim, pinned by a test. What it refuses to be: the JSON shell is explicitly not the production transport — one connection at a time, no keep-alive, no TLS, no sessions — and a refused call costs nothing, because both bounds are checked before either is charged. It serves no public endpoint to this day.


## Run it yourself {#betreiben}

**You need:**

- Rust (stable via rustup) and Git; every command runs from the root of the corpus checkout.

From the root of the corpus checkout, line by line:

```bash
cargo run --locked --manifest-path mcp/gateway/Cargo.toml -- --root . --http 8700 --fedlex-fixtures mcp/servers/fedlex/tests/fixtures --lindas-fixtures mcp/servers/lindas/tests/fixtures
```

Then you should see:

```text
gateway on 127.0.0.1:8700
```

With the fixture flags both interfaces answer from recorded files, without network. Without them the gateway asks the federal public endpoints.


## Test {#testen}

```bash
cargo test --locked --manifest-path mcp/gateway/Cargo.toml
```

- **Recorded fixtures:** `mcp/gateway/tests`
- Runs without network: every answer comes from the repository, the result is the same every run.

## Call {#ansteuern}

- **Public:** *not yet* — No public endpoint: zone, route and deployment are not switched on.
- **Local:** http://127.0.0.1:8700 — GET /tools, POST /tool/<id>, POST /mcp

### Contracts

- **Tool inventory (stage one)** `mcp/gateway/tool-inventory.json`
- **RFC 9728 metadata** `mcp/gateway/oauth-protected-resource.json`

### Call a domain tool through the JSON shell

```bash
curl -s -X POST http://127.0.0.1:8700/tool/lindas.list_cubes -H 'content-type: application/json' -d '{}'
```

Response (excerpt):

```json
{"cubes":[{"cube":"https://politics.ld.admin.ch/fc/cube-chancellor","description":"Bundeskanzler der Schweiz mit Partei, Kanton und Amtszeiten.","family":"fc","name":"Bundeskanzler","observations":15, …}, …]}
```

### Usage and options

```text
usage: oh-mcp-gateway --root <repo root> [--budget <n>] [--rate <n/min>] [--burst <n>] [--trust-forwarded-for] [--upstream-rate <n/s>] [--fedlex-fixtures <dir>] [--lindas-fixtures <dir>] [--http <port>] [--model-key-file <path>] [--model-cap <answers/client/day>]
```

## Contribute {#mitwirken}

Changes go through merge requests and the same gates as the association's own: formatting, Clippy without warnings, tests, seal and drift checks. Security reports, in confidence, to admin@openhelvetia.swiss.

The base tier costs nothing; what the operation lives on is under [About us, Financing](../../../about/financing/index.html).

## Module card {#steckbrief}

State, evidence, download and dependencies are on the infrastructure page: [MCP-Gateway](../../../directory/building-blocks/mcp-gateway/index.html).

---

Source: generated from public/web/modules.json
