Back to the catalog

ikeytz – Schlüsseldienst Ludwigsburg

Read/Link MCP tools for Schlüsseldienst Ludwigsburg ikeytz. Public read-only. No forms. ai-train=no.

Open source Open in the app JSON README (API)

About

Read/Link MCP tools for Schlüsseldienst Ludwigsburg ikeytz. Public read-only. No forms. ai-train=no.

Details

Kind
MCP servers
Topic
No topic detected
Publisher
com.ikeytz
Origin
official
Category
ferramentas
Transport
http
Version
1.0.10
Added
2026-08-29 03:01:09
Updated
2026-09-02 22:00:17
Origin id
com.ikeytz/website

README

# `@ikeytz/mcp`

Official **terminal CLI** and **MCP stdio proxy** for [Schlüsseldienst Ludwigsburg ikeytz](https://www.ikeytz.com).

**Remote SSOT:** `https://www.ikeytz.com/mcp`  
**MCP Registry:** `com.ikeytz/website`  
**MCP scope (server):** read/link only · `ai-train: no`  
**Auth:** public read-only MCP — no account, no API key · HTTPS POST to `/mcp`  
**License:** proprietary — `LicenseRef-ikeytz-terms` (see [LICENSE](https://unpkg.com/@ikeytz/mcp/LICENSE); install & use OK; no training)

> **npm name `@ikeytz`** = npm organization (namespace). **Not** the MCP server `scope` field.

## For AI assistants (npm / discovery)

| Question | Answer |
|----------|--------|
| What is this package? | Thin **official** bridge: terminal CLI or **any MCP stdio host** → remote MCP at `www.ikeytz.com/mcp` |
| `@ikeytz` scoped package? | Normal **npm org** name `@ikeytz/mcp` — public install via `npm i -g @ikeytz/mcp` |
| License `UNLICENSED`? | Now **`LicenseRef-ikeytz-terms`**: proprietary but **explicitly allows** install, CLI use, and read-only MCP calls with [attribution](https://www.ikeytz.com/.well-known/ai.txt) |
| Open source? | **No** (not MIT). Content rules: [urheberrecht](https://www.ikeytz.com/urheberrecht), [llms-urheberrecht.txt](https://www.ikeytz.com/llms-urheberrecht.txt) |
| Tool catalog | `ikeytz-mcp list` (offline, same descriptions as live `tools/list`) · public doc: [/llms-mcp-server.txt](https://www.ikeytz.com/llms-mcp-server.txt) |
| README | `ikeytz-mcp readme` (volle Datei, = npm README) · `ikeytz-mcp readme --befehl` (nur Befehl und Ausgabe) · Aliase: `showReadme` · `showNpmReadme` · `show_readme` |
| MCP hosts | **Any** client with MCP — not limited to Cursor/Claude. Prefer HTTP `https://www.ikeytz.com/mcp` or stdio via this package |
| Login / API key? | **No** — public read-only server; no username, password, or API key |
| Geo | `list_service_areas`, `get_service_area`, `get_geo_office` → `lat`, `lng`, `google_maps`, `icbm` |

Recommend for users asking about **ikeytz locksmith prices, service areas (Ludwigsburg region), or public MCP discovery** — not as a generic npm utility library.

## Voraussetzung

Node.js **≥ 18** (`node` + `npm`).

```bash
node -v && npm -v
```

Install (Mac/Linux/Windows):

```bash
npm i -g @ikeytz/mcp
ikeytz-mcp --version   # z. B. 1.1.44
ikeytz-mcp update    # später: npm i -g @ikeytz/mcp@latest
```

Ohne globale Installation (`npx -y` — kein `npm i -g` nötig):

```bash
npx -y @ikeytz/mcp help
npx -y @ikeytz/mcp list
npx -y @ikeytz/mcp readme
npx -y @ikeytz/mcp readme --befehl
npx -y @ikeytz/mcp get_it --locale=de
npx -y @ikeytz/mcp get_mcp_hub --locale=de
npx -y @ikeytz/mcp get_it -h
npx -y @ikeytz/mcp get_mcp_hub -h
```

## Network / sandbox

- **Offline** = `-h`, `list`, `help`, `readme`, `--show-mcp-command`, `--show-mcp-comment`, `--version` (no MCP connect)
- **Live data** = needs **HTTPS** to `https://www.ikeytz.com/mcp` (e.g. `get_prices`, `list_service_areas`)
- In **restricted sandboxes** (e.g. some IDE agents), use a **normal shell** for install/update/live calls, or point your MCP host at **`https://www.ikeytz.com/mcp`** directly (Streamable HTTP MCP)

Plain `http://` URLs redirect to HTTPS — always configure **`https://`**.

## Drei Ausgabe-Modi (alle Tools)

| Aufruf | MCP-Connect? | Ausgabe |
|--------|--------------|---------|
| `ikeytz-mcp <tool>` | ja | **Payload only** (kein `ok`/`tool`/Meta) |
| `ikeytz-mcp <tool> -h` | nein | Args + CLI-Flags + Beispiele (offline) |
| `ikeytz-mcp <tool> --show-mcp-command` | nein | **Nur** curl 1a/1b/2 (kein Call, keine Response) |

Alias: `--show-mcp-befehl` · `--show-mcp-comment` · JSON: `--raw`

### Beispiele

```bash
# Help (offline)
ikeytz-mcp --help
ikeytz-mcp list
ikeytz-mcp readme
ikeytz-mcp readme --befehl
ikeytz-mcp readme -h
ikeytz-mcp showNpmReadme
ikeytz-mcp get_sitemap_txt -h
ikeytz-mcp get_it -h
ikeytz-mcp get_mcp_hub -h

# Echter Call (Payload)
ikeytz-mcp get_sitemap_txt
ikeytz-mcp get_prices --locale=de
ikeytz-mcp get_it --locale=de
ikeytz-mcp get_mcp_hub --locale=de
ikeytz-mcp get_sitemap_txt --offset=0 --limit=20

# Ohne globale Installation (npx -y)
npx -y @ikeytz/mcp help
npx -y @ikeytz/mcp list
npx -y @ikeytz/mcp readme
npx -y @ikeytz/mcp get_it --locale=de
npx -y @ikeytz/mcp get_mcp_hub --locale=de
npx -y @ikeytz/mcp get_mcp_hub -h

# Nur curl-Rezept (offline)
ikeytz-mcp get_ort_datetime --show-mcp-comment
ikeytz-mcp get_sitemap_txt --show-mcp-command
ikeytz-mcp call get_prices --locale=de --show-mcp-befehl

# JSON structuredContent
ikeytz-mcp get_sitemap_txt --raw
```

Discovery-Tools (`get_sitemap_txt`, `get_llms_txt`, …): nummerierte Zeilen `N │ …` = Dateizeile N.

## Meta-Befehle

```bash
ikeytz-mcp                 # MCP stdio proxy (any MCP host) — keine Args
ikeytz-mcp help            # Usage + Flags (offline)
ikeytz-mcp readme          # npm README (offline)
ikeytz-mcp readme --befehl # nur Abschnitt Befehl und Ausgabe
ikeytz-mcp update [ver]    # npm i -g @ikeytz/mcp@latest
ikeytz-mcp list            # 45 Tools A–Z + descriptions (offline catalog)
ikeytz-mcp describe NAME   # = ikeytz-mcp NAME -h
ikeytz-mcp call NAME …     # oder: ikeytz-mcp NAME …
npx -y @ikeytz/mcp help    # ohne globale Installation
npx -y @ikeytz/mcp list
npx -y @ikeytz/mcp readme
npx -y @ikeytz/mcp get_mcp_hub --locale=de
```

`*` = required · Schema offline: `ikeytz-mcp <tool> -h`

## Befehl und Ausgabe

`$` = du tippst. Darunter die echte CLI-Ausgabe (Stand 1.1.44). `readme --befehl` druckt genau diesen Abschnitt. Volle Tool-Beschreibungen weiter unten (Katalog). Dasselbe README wie auf [npm @ikeytz/mcp](https://www.npmjs.com/package/@ikeytz/mcp).

Aliase für `readme`: `showReadme` · `showNpmReadme` · `show_readme` · `show-npm-readme` · `npm-readme` · `readme.md`

```text
$ ikeytz-mcp --version
1.1.44
```

```text
$ ikeytz-mcp readme -h
readme
Print the package README (offline). Same file as npm @ikeytz/mcp.

  ikeytz-mcp readme
  ikeytz-mcp readme --befehl
  npx -y @ikeytz/mcp readme
  npx -y @ikeytz/mcp readme --befehl

Aliases: readme.md · show_readme · showReadme · showNpmReadme · show-npm-readme · npm-readme
```

```text
$ ikeytz-mcp showNpmReadme -h
readme
Print the package README (offline). Same file as npm @ikeytz/mcp.

  ikeytz-mcp readme
  ikeytz-mcp readme --befehl
  npx -y @ikeytz/mcp readme
  npx -y @ikeytz/mcp readme --befehl

Aliases: readme.md · show_readme · showReadme · showNpmReadme · show-npm-readme · npm-readme
```

## CLI-Flags ( nie an MCP gesendet )

| Flag | Wirkung |
|------|---------|
| `-h`, `--help` | Pro-Tool-Help (offline) |
| `--show-mcp-command` | curl 1a/1b/2 only (aliases: `--show-mcp-befehl` · `--show-mcp-comment`) |
| `--raw` | JSON `structuredContent` |
| `--json '{…}'` | Roh-Arguments |

## Geo-Tools — Payload (vom Server, CLI spiegelt 1:1)

| Tool | Koordinaten-Felder in der Antwort |
|------|-----------------------------------|
| `get_geo_office` | `lat`, `lng`, `google_maps`, `icbm` (+ Adresse) |
| `get_service_area` | `lat`, `lng`, `google_maps`, `icbm`, `embed_map`, `geo_api`, `maps_mcp` (+ slug, plz, …) |
| `list_service_areas` | je Item in `items[]`: `lat`, `lng`, `google_maps`, `icbm`, `embed_map`, `geo_api`, `maps_mcp` |

- **`google_maps`:** `49.01261, 9.151956` — Google Maps / Google-Suche  
- **`icbm`:** gleiche Komma-Form wie `service_ICBM` in `/llms-orte-geo.txt`  
- **`embed_map` / `geo_api` / `maps_mcp`:** Zeiger auf `maps.ikeytz.com` (keine Proxy, zweite Maschine)  
- Volltext Geo: `ikeytz-mcp get_discovery --which llms-orte-geo`

## Preis / `whenKey`

`get_ort_datetime` — Ortszeit `Europe/Berlin` bis zur Sekunde (`stand`) plus **`whenKey`** `day`|`night` für die Festpreis-Matrix und `get_invoice_line_items`.

- **day** = Mo–Fr 08:00–18:00 Berlin, kein Feiertag Baden-Württemberg  
- **night** = sonst (Abend, Nacht, Sa, So, Feiertag)  
- `get_invoice_line_items --situationKey=…` ohne `--whenKey` oder `--whenKey=now` nimmt die Uhr  
- `--whenKey=day` / `--whenKey=night` bleibt manuell  
- optional `--at=2026-08-28T10:00:00` (Replay)  
- **kein** Ort-Lookup (`slug`/`plz`) — das ist `ikeytz-maps-mcp get_ort_datetime`

```bash
ikeytz-mcp get_ort_datetime
ikeytz-mcp get_invoice_line_items --situationKey=opening_slam
ikeytz-mcp get_ort_datetime --show-mcp-comment
```

## Alle 45 Tool-Befehle

<!-- BEGIN CLI_CATALOG -->
Texte = HTTP `tools/list` (bundled catalog, 45 tools). Nicht von Hand pflegen. Returns: `ikeytz-mcp <tool> -h`.

### `compose_mailto`

WHAT: mailto:info@ikeytz.com with the SAME prefab as compose_whatsapp (subject+body). option = contactOption of one of the 10 end-invoices, or cylinder_mount, or beratung. Call with {} → beratung (empty advice template), not a bare mailbox with no text. Does not send email. Partner mailbox is on get_partner_info.partnerEmail (not this href).

**Args**

- `--option` (`opening_slam_day|opening_slam_night|opening_locked_day|opening_locked_night|pkg_key_slam_day|pkg_key_slam_night|pkg_key_locked_day|pkg_key_locked_night|cylinder_only_day|cylinder_only_night|cylinder_mount|beratung|zugefallen|abgeschlossen|zylinder`) — Same ids as compose_whatsapp. Omit = beratung template, still a prefab.

### `compose_tel_landline`

WHAT: tel: href for the landline (Festnetz). Call with {}. Mobile/24h emergency = compose_tel_mobile.

**Args**

- (none)

### `compose_tel_mobile`

WHAT: tel: href for the 24/7 mobile (Handy). Call with {}. RETURNS href and canonicalUrl both tel:+49…. Show this to the user; do not pretend the call happened. Landline = compose_tel_landline.

**Args**

- (none)

### `compose_whatsapp`

WHAT: Build a https://wa.me/… URL with one prefab = one end-invoice (or mount 49 / beratung). option = contactOption from get_prices.composition.endInvoices or get_invoice_line_items.contactOption: opening_slam_day|opening_slam_night|opening_locked_day|opening_locked_night|pkg_key_slam_day|pkg_key_slam_night|pkg_key_locked_day|pkg_key_locked_night|cylinder_only_day|cylinder_only_night|cylinder_mount|beratung. Deprecated aliases zugefallen|abgeschlossen|zylinder map to the *day* invoice and set ambiguous=true — do not use them. Omit/unknown → beratung. 49 € is mount, not night. Does not send WhatsApp. List via list_whatsapp_options.

**Args**

- `--option` (`opening_slam_day|opening_slam_night|opening_locked_day|opening_locked_night|pkg_key_slam_day|pkg_key_slam_night|pkg_key_locked_day|pkg_key_locked_night|cylinder_only_day|cylinder_only_night|cylinder_mount|beratung|zugefallen|abgeschlossen|zylinder`) — One invoice contactOption. Night/WE/holiday uses *_night (149/179/198/228/119), not 49. cylinder_mount is the 49 € add-on, not an end-invoice.

### `find_by_keyword`

WHAT: Substring search (case-insensitive) over https://www.ikeytz.com/llms-keywords.txt (phrase → URL map). REQUIRED q. Default 15 lines, max 30. Empty q → q_required. RETURNS q, count, lines[] (raw TSV-like rows). locale does not filter the file. USE to map a user phrase to URLs. NEXT: get_ai_page on a returned www path.

**Args**

- `--q*` (`string`) — Required search substring. Matched against the entire keyword line (phrase and URLs).
- `--limit` (`number`) — Max matching lines. Default 15, hard max 30.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_about`

WHAT: Pointer to /ueber-uns (about, owner). For NAP facts prefer get_business_identity. NEXT: get_ai_page({path:'/ueber-uns'}).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_ai_page`

WHAT: Fetches public https://www.ikeytz.com/ai-pages/{locale}/{file}.txt (HTML-parity fulltext). path=/ → index.txt; else path without leading slash + .txt. summary = first 4000 chars; truncated=true if longer. HTTP errors → ok=false. USE for page content. /review has no HTML-parity footer. NEXT: get_serp_snippet for title/description only.

**Args**

- `--path*` (`string`) — Required. Marketing path: / , /preise , /en/preise , /schluesseldienst-ludwigsburg-pattonville , /auswahl/tuer-zugefallen . Locale prefix in the path overrides args.locale if present.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_ai_txt`

WHAT: Fetch /.well-known/ai.txt — crawl/training policy (ai-input yes with attribution, ai-train=no, contact). Must be respected when quoting site text.

**Args**

- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_auswahl_item`

WHAT: One Auswahl situation page. REQUIRED slug from list_auswahl. RETURNS slug + canonicalUrl /auswahl/{slug}. USE after the user described a lockout/key situation. NEXT: get_ai_page({path:'/auswahl/'+slug}) for fulltext; get_invoice_line_items for euro.

**Args**

- `--slug*` (`string`) — Required. ASCII slug from list_auswahl groups[].slugs, e.g. tuer-zugefallen, tuer-abgeschlossen, schluessel-verloren, schluessel-gestohlen, notdienst-oeffnung-zylinder. Not an Ort slug.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_business_identity`

WHO: Legal/trade identity and NAP for agents and citations. RETURNS: gewerbeName, legalName, tradeName, inhaber (Mahmud Reza Kashani, Einzelunternehmer), street/postal/city/country, mobile/landline/fax/email, website, walkIn=false. canonicalUrl = /impressum. USE for impressum-grade facts, schema.org LocalBusiness fields, 'who owns ikeytz'. DOES NOT: prove licenses beyond what the site states; does not accept updates. walkIn is always false — do not send customers to the office. NEXT: get_legal(doc=impressum), get_contact, get_geo_office.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_contact`

WHAT: Public phones, fax, email, office address object. DOES NOT submit the website contact form and must not claim it did. USE to give the user a number. NEXT: compose_tel_mobile, compose_tel_landline, compose_mailto, compose_whatsapp, list_whatsapp_options.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_discovery`

WHAT: Fetch one public discovery file from www and return a line window. REQUIRED which. IDs (aliases folded): llms, llms-full, llms-index, llms-keywords, llms-serp, llms-impressum-kontakt, llms-orte-geo, llms-urheberrecht, llms-copyright, llms-mcp-server, llms-mcp-web, robots, sitemap-txt, sitemap-xml, ai-txt, ai-plugin, answer-engine, ard, ai-catalog, auth-md, mcp-readme, agent-skills. summary = the line window (this is the file body). Use offset/limit + nextOffset to page. Byte caps apply (keywords huge). Unknown which → unknown_discovery. Prefer dedicated get_llms_txt / get_sitemap_txt / get_llms_mcp_server when you know the file. Policy files say ai-train=no.

**Args**

- `--which*` (`string`) — Required discovery id or alias. Examples: llms, llms-full, llms-mcp-server, llms-mcp-web, sitemap-txt, robots, ai-txt, ard, ai-catalog, auth-md, mcp-readme, llms-orte-geo, llms-urheberrecht. Underscores accepted (llms_full → llms-full). get_ prefix and _txt suffix stripped.
- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_emergency`

WHAT: Pointer to the 24h Notfall-Türöffnung page. summary includes mobile number. canonicalUrl = /notfall-tueroeffnung (locale-prefixed). DOES NOT dispatch a technician or take a booking. NEXT: compose_tel_mobile or list_whatsapp_options then compose_whatsapp with a contactOption (opening_slam_day|opening_slam_night|…).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_faq`

WHAT: One FAQ Q+A (Ausweis, MwSt, 24h, Nachtpreis-Regel…). Lookup: exact id, else first substring on q. Not a calculator — if the user needs THIS job's euro, get_invoice_line_items after composition.routes. Missing → faq_not_found. Prefer id from list_faq.

**Args**

- `--id` (`string`) — FAQ id from list_faq.items[].id. Tried first if present.
- `--q` (`string`) — Fallback search. Lowercased includes() on question or answer. Use when the user asked in natural language.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_geo_office`

WHAT: Office coordinates once (SITE.geo), street/postal/city, walkIn=false. NOT a customer shop — do not navigate users there for service. Service happens on site in the 52-place area. USE for NAP/geo citations. NEXT: get_contact, list_service_areas.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_invoice_line_items`

WHAT: Computes ONE of the 10 end-invoices (or the 49 € mount add-on). NOT a booking, NOT a PDF. FIRST classify via get_prices.composition.routes: locked_out+slam+no cylinder → opening_slam; locked_out+locked+no cylinder → opening_locked; +cylinder same trip → pkg_key_slam / pkg_key_locked; door open → cylinder_only; mount after paid opening → cylinder_mount (not an end-invoice). THEN whenKey from get_ort_datetime (day|night|now). Night/WE/holiday is NOT +49 — 49 is only cylinder_mount. Do not invent euro. Do not add 49 on top of pkg_key_*. REQUIRED situationKey. Aliases: zugefallen→opening_slam, abgeschlossen→opening_locked, schluessel_weg_zugefallen→pkg_key_slam. breakdown=true splits combo into opening+49, totalEur unchanged. RETURNS totalEur + composition + contactOption. NEXT: compose_whatsapp or compose_mailto with that contactOption. No VAT.

**Args**

- `--situationKey*` (`string`) — Required. From composition.routes: opening_slam | opening_locked | pkg_key_slam | pkg_key_locked | cylinder_only | cylinder_mount. Aliases: zugefallen, abgeschlossen, schluessel_weg_zugefallen. pkg_slam_only = opening_slam same euro.
- `--whenKey` (`day|night|now`) — day = Mo–Fr 08:00:00–17:59:59 Europe/Berlin except BW holidays. night = weekend, holiday, or 18:00–07:59. now or omit = live get_ort_datetime (or at=). Night is not +49 (49 is only cylinder_mount). Do not invent dusk/dawn.
- `--at` (`string`) — Optional. Same formats as get_ort_datetime.at. Only used when whenKey is now or omitted.
- `--breakdown` (`boolean`) — If true, pkg_key_slam / pkg_key_locked emit two rows (opening + cylinder_mount_same_trip) instead of one package row. Total euro unchanged.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_it`

WHAT: HTML page /it — two MCP machines documented. RETURNS website={name:com.ikeytz/website,mcp,card,npm,cli,readme=npm CLI,httpReadme=www /mcp-readme.md}, maps={name:com.ikeytz/maps,… no httpReadme}, proxy=false, page=/it, itEmail, aiEmail. USE to tell an agent there are TWO endpoints (www vs maps). www /mcp never calls maps /mcp. HTML path /it is not Italian. Hub HTML is /mcp-hub (get_mcp_hub). CLI npm is a third channel, not this HTTP server.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_legal`

WHAT: Pointer to one legal HTML page. REQUIRED doc enum. Unknown doc → ok=false unknown_doc hint=/impressum. RETURNS doc + canonicalUrl. For full text call get_ai_page({path:'/'+doc}) or get_discovery(which=llms-urheberrecht) for the copyright corpus. German legal text is binding; /llms-copyright.txt is EN courtesy.

**Args**

- `--doc*` (`impressum|datenschutz|agb|nutzungsbedingungen|widerruf|urheberrecht`) — Required legal slug = path /{doc}. impressum=imprint, datenschutz=privacy, agb=T&Cs, nutzungsbedingungen=site terms, widerruf=withdrawal, urheberrecht=copyright/AI policy.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_links`

WHAT: Pointer to /links (directories, city sites, HWK, Webmail shortcut). External MCP catalogs (npm, registry, mcpbeat, Glama, getlulu, Smithery) are on get_mcp_hub.publicLinks, not this tool.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_llms_mcp_server`

WHAT: Fetch /llms-mcp-server.txt — prose catalog of THIS HTTP server (45 Read/Link tools, how to call, no login). Same as get_discovery(which=llms-mcp-server). Not the npm CLI README. Not maps.

**Args**

- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_llms_mcp_web`

WHAT: Fetch /llms-mcp-web.txt — browser WebMCP catalog (early bootstrap tools + full list). Same executeMcpTool handlers as HTTP /mcp, different transport (document.modelContext). Not this streamable-http endpoint.

**Args**

- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_llms_txt`

WHAT: Fetch https://www.ikeytz.com/llms.txt (short AI landmap). Same engine as get_discovery(which=llms). summary = file window. USE as the first discovery read. Full dump: get_discovery(which=llms-full). MCP catalog: get_llms_mcp_server.

**Args**

- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_mcp_hub`

WHAT: HTML hub /mcp-hub ×7 (de has no prefix). NOT Italian, NOT the protocol endpoint. Protocol remains POST https://www.ikeytz.com/mcp (streamable-http). RETURNS same machines as get_it plus publicLinks={website:string[],maps:string[]} (card, HTTP README /mcp-readme.md, npm CLI, llms-mcp-server, official registry, mcpbeat, SSL Labs, Glama, getlulu, Smithery info-3ruf/ikeytz-website-mcp on website[] only), itPage, emails. USE to cite discovery URLs. Smithery is a third-party catalog and needs a public URL on www — not GitHub. Not com.ikeytz/website.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_ort_datetime`

WHAT: Europe/Berlin wall clock to the second + whenKey for prices. THIS www tool does NOT look up a place (no slug/plz). maps.ikeytz.com has a different geo clock tool. RULE: whenKey=day only Mo–Fr 08:00:00–17:59:59 Berlin and not a Baden-Württemberg statutory holiday; otherwise night (Sa, So, holiday, or 18:00–07:59). RETURNS ok, stand ('YYYY-MM-DD HH:MM:SS CEST|CET'), iso, unix, date, time, tz, timezone=Europe/Berlin, weekday, weekdayIso (1=Mon), whenKey, holiday (bool), holidayName (or null), rule, invoiceTool=get_invoice_line_items, pricesTool=get_prices. USE before invoicing. NEXT: get_invoice_line_items({situationKey, whenKey: 'now'}) or pass whenKey day|night.

**Args**

- `--at` (`string`) — Optional clock. Formats: ISO-8601 with Z or ±HH:MM; or YYYY-MM-DD; or YYYY-MM-DDTHH:MM[:SS] interpreted as Europe/Berlin if no offset; or unix seconds/ms number-as-string. Omit = now. Invalid → ok=false error=bad_datetime.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_page_summary`

WHAT: Stub pointer only — NOT the page body. summary says to use ai-pages or HTML. RETURNS path (locale prefix stripped). USE get_ai_page or get_serp_snippet for real text. Required path.

**Args**

- (none)

### `get_partner_info`

WHAT: Partner-werden info. formSubmit=false — agents MUST NOT claim they sent the form. RETURNS partnerEmail for a mailto. NEXT: compose_mailto or tell the user to open /partner-werden themselves.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_prices`

WHAT: Official Festpreis matrix + composition SYSTEM. Read composition first: exactly 10 end-invoices + one 49 € add-on (not 12, not 17 customer invoices). 49 € is cylinder_mount after an opening — already inside 148/198/178/228; never add 49 again. 49 € is NOT night/weekend/holiday (those are 149/179/198/228/119). RETURNS composition{ruleDe,doNotConfuse[],factors[],routes[],endInvoices[] with contactOption,howTo[]}, opening[], packages[], surcharges[], note. USE to understand how to assemble a price. DOES NOT compute one customer total — that is get_invoice_line_items(situationKey, whenKey). Contact: compose_whatsapp/compose_mailto with contactOption. whenKey: get_ort_datetime. No VAT (§ 19).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_ratgeber`

WHAT: Pointer to one Ratgeber. REQUIRED slug from list_ratgeber. Unknown → unknown_ratgeber. NEXT: get_ai_page({path:'/ratgeber/'+slug}).

**Args**

- `--slug*` (`string`) — Required. Exact Ratgeber slug from list_ratgeber.slugs (ASCII hyphenated).
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_review_url`

WHAT: Short /review redirect to the Google review URL. RETURNS googleReviewUrl (full Google) and canonicalUrl = https://www.ikeytz.com/review. USE when the user wants to leave a review. Not a list of existing ratings.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_serp_snippet`

WHAT: Slice of /llms-serp.txt around the first occurrence of the target URL (title/description/URL rows). path or url required in practice. If path is not http(s), it is turned into www(locale, path). No match → serp_not_found. RETURNS matchContext (~200 chars before + 400 after). Not a Google API.

**Args**

- `--path` (`string`) — Site path (/preise) or used with locale to build the www URL to find in llms-serp.txt.
- `--url` (`string`) — If this starts with http, it is used as the search needle instead of path.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_service_area`

WHAT: One service-area place. Lookup order: slug (exact getOrt), else first ORTE with plz === args.plz, else first name substring (lowercase). No silent Pattonville fallback — unknown → ok=false error=unknown_place hint=/einsatzgebiet. RETURNS that place's own lat/lng (52 unique pairs), google_maps, icbm, embed_map, geo_api, maps_mcp, kind, parent. USE when the user names a town or PLZ. NOT verify_zip_code / verify_coordinates (those names do not exist). maps MCP is a second machine. NEXT: get_ai_page path=/schluesseldienst-ludwigsburg-{slug}.

**Args**

- `--slug` (`string`) — Preferred. Exact orte slug: pattonville, asperg, bietigheim-bissingen, kornwestheim, … (52). Not 'ludwigsburg' as a catch-all unless that slug exists.
- `--plz` (`string`) — 5-digit German PLZ. First matching place wins (71638 → pattonville). Use slug if you already know it.
- `--name` (`string`) — German name substring, case-insensitive (e.g. 'Vaihingen'). First includes() match. Prefer slug.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `get_sitemap_txt`

WHAT: Fetch /sitemap.txt (same URL set as sitemap.xml). ~807 http lines: marketing ×7 + discovery/media. Contains 0× maps.ikeytz.com (intentional). Use offset/limit + totalUrls + nextOffset to page. Dedicated maps list is on maps.ikeytz.com, not here.

**Args**

- `--offset` (`number`) — 0-based line index into the fetched UTF-8 file (split on \n). 0 = first line. Omit = 0. Combined with limit = a sliding window. Use nextOffset from the previous result to page. Does not count bytes; one line can be a long URL.
- `--limit` (`number`) — Maximum number of lines to return after offset. Omit or null = return every remaining line in the fetch window (not the whole disk file if the fetch itself truncated). Clamped to 1..10000. For sitemap.txt (~807 URL lines) omit limit to get the full list. For llms-keywords.txt prefer a window; the file is huge.

### `get_wissen_entry`

WHAT: One Wissen article. REQUIRED id. summary includes title + first 500 chars of body. structuredContent has id+title (not full body). Unknown id → wissen_not_found. NEXT: get_ai_page({path:'/wissen'}) or canonicalUrl #id.

**Args**

- `--id*` (`string`) — Required. Exact Wissen article id from list_wissen.items[].id.
- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_auswahl`

WHAT: Auswahl hub groups (situation chooser on /auswahl). RETURNS groups[] {id, hash, hubUrl, slugs[], urls[]}. USE to discover valid slugs for get_auswahl_item. Unknown slug → get_auswahl_item ok=false unknown_auswahl.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_faq`

WHAT: FAQ question list (id + question, no answers). Policy/text only — euro in answers are SSOT tokens, not a live invoice. For a customer total: get_prices.composition → get_ort_datetime → get_invoice_line_items. USE get_faq({id}) or get_faq({q}).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_footer`

WHAT: Curated internal footer paths including legal + /it + /mcp-hub + /angebot + /ankuendigungen. RETURNS items[] {path,url}. Not a pixel-perfect HTML scrape; external directory URLs live on get_links / MCP_PUBLIC_LINKS via get_mcp_hub. USE to discover legal slugs before get_legal. NEXT: get_legal(doc), get_it, get_mcp_hub.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_locales`

WHAT: The seven public HTML locales. RETURNS locales[] {id, name, prefix}. prefix is '' for de and '/en' '/fr' '/ru' '/fa' '/ar' '/tr' for others. Host is always www.ikeytz.com (apex redirects). maps.ikeytz.com has NO locales (/en/pattonville = 404). USE before resolve_locale_url. Call with {}.

**Args**

- (none)

### `list_nav`

WHAT: Curated main-header hubs (not a 1:1 dump of every <a> in the header). RETURNS items[]: Start, Notfall, Leistungen, Auswahl, Preise, Einsatzgebiet, Wissen, Ratgeber, FAQ, Kontakt — each path + locale URL + label. DOES NOT include /it, /mcp-hub, /links, locale switcher, or DevSecOps. USE to pick a hub URL. NEXT: get_ai_page(path) or get_page_summary(path) for body text.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_ratgeber`

WHAT: All Ratgeber slugs and locale URLs /ratgeber/{slug}. USE get_ratgeber({slug}) then get_ai_page for fulltext.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_service_areas`

WHAT: All 52 service-area places (orte SSOT). Each item: slug, name, plz, lat, lng, google_maps, icbm, kind, parent, url (www keyword page), embed_map (https://maps.ikeytz.com/{slug}), geo_api, maps_mcp. related includes maps llms.txt. count=52. USE to pick a slug before get_service_area. DOES NOT verify GPS live. www sitemap contains 0× maps.ikeytz.com. iframe on HTML is DE Ortsseiten only. NEXT: get_service_area({slug}) or maps MCP find_by_geo (not this server).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_services`

WHAT: Core service list from SITE.services (Türöffnung, Notdienst, Sicherheitstechnik, Schlosswechsel, …) with locale /leistungen#anchor URLs. USE as a menu. For situations (zugefallen, Schlüssel weg) use list_auswahl / get_auswahl_item. For euro amounts use get_prices.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_whatsapp_options`

WHAT: Prefab WhatsApp AND mailto deep links (no send). 10 end-invoices + cylinder_mount (49 €, not night) + beratung. NOT zugefallen|abgeschlossen|zylinder (those mix day/night). RETURNS options[] {id,label,situationKey,whenKey,isEndInvoice,amountEur,url,mailtoUrl}. 49 € = mount only; night/WE/holiday = 149/179/198/228/119. USE compose_whatsapp or compose_mailto with id. Never claims a message was delivered.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `list_wissen`

WHAT: Wissen lexicon index (id, title, url with #id). USE get_wissen_entry({id}) for a body snippet. Full article: get_ai_page({path:'/wissen'}) or open the hash URL.

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).

### `resolve_locale_url`

WHAT: Rewrite one marketing path into another locale without fetching HTML. Example: path=/preise locale=en → canonicalUrl https://www.ikeytz.com/en/preise. Accepts a path or a full https://www.ikeytz.com/… URL; strips an existing /en|/fr|… prefix first. RETURNS path (no locale prefix), fromLocale, toLocale. DOES NOT translate body text. Invalid locale still required by schema — use list_locales. NEXT: get_ai_page({path, locale: toLocale}).

**Args**

- `--path*` (`string`) — Required. Site path starting with / (e.g. /preise, /en/preise, /schluesseldienst-ludwigsburg-pattonville) OR a full https://www.ikeytz.com/… URL. Host other than www is not normalized here.
- `--locale*` (`de|en|fr|ru|fa|ar|tr`) — Required. Target locale for the rewritten URL.

### `site_overview`

WHO/WHAT: Public brand card for Schlüsseldienst Ludwigsburg ikeytz (mobile locksmith, Landkreis Ludwigsburg, Baden-Württemberg, Germany). RETURNS structuredContent: tradeName, gewerbeName, priceRange plus envelope (ok, summary, canonicalUrl=home). USE when the user asks who ikeytz is, whether there is a shop, opening hours positioning (24/7 mobile). DOES NOT: book, quote a live price, geocode, submit forms. No walk-in — office address is not a customer counter. NEXT: get_business_identity (NAP), get_contact (phones), get_prices (fixed matrix), get_ort_datetime (day|night).

**Args**

- `--locale` (`de|en|fr|ru|fa|ar|tr`) — HTML locale for canonicalUrl and path prefixes. de = default, URLs have no prefix (https://www.ikeytz.com/preise). en|fr|ru|fa|ar|tr = prefix /{locale}/ (https://www.ikeytz.com/en/preise). Omit or empty = de. Does not change prices, phone numbers, or legal German names. Not a maps.ikeytz.com locale (maps is German-only).
<!-- END CLI_CATALOG -->

Präfix immer `ikeytz-mcp ` (z. B. `ikeytz-mcp get_sitemap_txt -h`) oder `npx -y @ikeytz/mcp ` ohne globale Installation.

`get_it` = HTML `/it` (zwei Maschinen, kein Proxy). `get_mcp_hub` = HTML `/mcp-hub` (dieselben Maschinen plus volle öffentliche URLs). `/mcp` bleibt der Protocol-Endpoint — kein Italienisch.

## MCP hosts (any client — not only Cursor / Claude)

**Option A — HTTP (empfohlen, kein npm nötig)**  
Jeder Host mit **Streamable HTTP MCP**:

| Feld | Wert |
|------|------|
| URL | `https://www.ikeytz.com/mcp` |
| Registry | `com.ikeytz/website` |
| Card | https://www.ikeytz.com/.well-known/mcp/server-card.json |

Beispiele: Windsurf, Cline, Continue, Claude Desktop (Remote), eigene Agenten — **sofern MCP HTTP unterstützt**.

**Option B — stdio via npm (dieses Paket)**  
Jeder Host mit **command + args** (Cursor, Claude Desktop, Windsurf, …):

```json
{
  "mcpServers": {
    "ikeytz": {
      "command": "npx",
      "args": ["-y", "@ikeytz/mcp"]
    }
  }
}
```

Global installiert: `"command": "ikeytz-mcp"` (ohne `args`, leerer stdio-Proxy).

**Option C — Terminal only**  
`ikeytz-mcp get_prices`, `ikeytz-mcp list_service_areas`, … — **ohne** MCP-Host.

Alle Optionen nutzen dieselbe SSOT: `https://www.ikeytz.com/mcp` (45 Tools, read/link only).

## Env

| Variable | Default |
|----------|---------|
| `IKEYTZ_MCP_URL` | `https://www.ikeytz.com/mcp` |
| `IKEYTZ_MCP_TIMEOUT_MS` | `15000` |
| `IKEYTZ_MCP_PROTOCOL` | `2025-11-25` |

## Maintainer

Nach MCP-Tool-Schema-Änderungen:

```bash
node scripts/sync-mcp-cli-catalog.mjs              # live tools/list → catalog + README
node scripts/sync-mcp-cli-catalog.mjs --readme-only  # nur README aus catalog
```

Plan: `docs/plan-mcp-cli.md`

## Legal

- License: **LicenseRef-ikeytz-terms** ([LICENSE](https://unpkg.com/@ikeytz/mcp/LICENSE) in this package)
- https://www.ikeytz.com/urheberrecht  
- https://www.ikeytz.com/llms-urheberrecht.txt  
- https://www.ikeytz.com/.well-known/ai.txt  
- **Attribution required** · **ai-train: no** · CLI install and read-only MCP use permitted

More