{
  "spec_version": "0.3.0",
  "name": "navigator.berlin",
  "description": "Cross-layer address inspector for Berlin: combines noise, air quality, green coverage, mobility, residential quality and Kiez-Score data with full source citations.",
  "homepage": "https://navigator.berlin",
  "license": "CC BY 4.0",
  "attribution": "Tool outputs from navigator.berlin. Underlying datasets carry their own licenses (dl-de/by-2-0, dl-de/zero-2-0, ODbL, CC BY 4.0). Always cite the source URL and license per tool output.",
  "tools": [
    {
      "name": "address_lookup",
      "description": "Search Berlin addresses, streets, and POIs. Returns up to N candidates with coordinates and administrative context (Bezirk, Kiez, postcode). Backed by OSM Nominatim, biased to Berlin.",
      "input_schema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": [
          "query"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "display_name": {
              "type": "string"
            },
            "lat": {
              "type": "number"
            },
            "lng": {
              "type": "number"
            },
            "bezirk": {
              "type": "string"
            },
            "kiez": {
              "type": "string"
            },
            "postcode": {
              "type": "string"
            }
          },
          "required": [
            "display_name",
            "lat",
            "lng"
          ]
        }
      }
    },
    {
      "name": "cross_layer_query",
      "description": "Query all configured Berlin data layers at a geographic point (lat, lng) and return one structured hit per layer with full provenance (source, updated_at, license, reason).",
      "input_schema": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          }
        },
        "required": [
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "layer": {
              "type": "string"
            },
            "value": {},
            "source": {
              "type": "string"
            },
            "updated_at": {
              "type": "string"
            },
            "license": {
              "type": "string"
            },
            "reason": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "required": [
            "layer",
            "value",
            "source",
            "updated_at",
            "license"
          ]
        }
      }
    },
    {
      "name": "list_layers_at_point",
      "description": "Lightweight discovery: list which Berlin data layers cover a given point. Returns layer slug, has_value flag, and reason (no-coverage, outdated, seasonal). Use this to decide which deeper queries to run.",
      "input_schema": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          }
        },
        "required": [
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "layer": {
              "type": "string"
            },
            "has_value": {
              "type": "boolean"
            },
            "reason": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          "required": [
            "layer",
            "has_value"
          ]
        }
      }
    },
    {
      "name": "get_kiez_profile",
      "description": "Return the public profile of a Berlin Kiez (LOR Bezirksregion) by slug. Includes name, Bezirk, population, area, centroid, and a list of data sources with license + updated_at provenance.",
      "input_schema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "locale": {
            "type": "string",
            "enum": [
              "de",
              "en"
            ]
          }
        },
        "required": [
          "slug"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "bezirk": {
            "type": "string"
          },
          "einwohner": {
            "type": "number"
          },
          "flaeche_ha": {
            "type": "number"
          },
          "centroid": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2
          },
          "data_sources": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "layer": {
                  "type": "string"
                },
                "source": {
                  "type": "string"
                },
                "updated_at": {
                  "type": "string"
                },
                "license": {
                  "type": "string"
                }
              },
              "required": [
                "layer",
                "source",
                "updated_at",
                "license"
              ]
            }
          }
        },
        "required": [
          "name",
          "slug",
          "bezirk",
          "einwohner",
          "flaeche_ha",
          "centroid",
          "data_sources"
        ]
      }
    },
    {
      "name": "get_layer_metadata",
      "description": "Return rich metadata for a single data layer by slug: source URL, license, license URL, geometry type, feature count, last update, and methodology summary.",
      "input_schema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "locale": {
            "type": "string",
            "enum": [
              "de",
              "en"
            ]
          }
        },
        "required": [
          "slug"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "bundle": {
            "type": "string"
          },
          "geometry_type": {
            "type": "string"
          },
          "feature_count": {
            "type": "number"
          },
          "source_url": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "license": {
            "type": "string"
          },
          "license_url": {
            "type": "string"
          },
          "methodology": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "summary": {
                "type": "string"
              },
              "aggregation_level": {
                "type": "string"
              },
              "source_layers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": [
          "slug",
          "bundle",
          "geometry_type",
          "feature_count",
          "source_url",
          "updated_at",
          "license",
          "license_url"
        ]
      }
    },
    {
      "name": "list_elections",
      "description": "List all Berlin elections available in navigator.berlin (Bundestagswahl, Abgeordnetenhauswahl, BVV-Wahl). Per election: slug like 2025-btw-zweitstimme or 2023-bvv, year, type, Stimmtyp, repeat-election flag with parent slug, has_stimmbezirks_geometry flag, source authority + license. Slugs from this tool are the canonical input for get_election_result and compare_elections.",
      "input_schema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "elections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "jahr": {
                  "type": "number"
                },
                "typ": {
                  "type": "string",
                  "enum": [
                    "btw",
                    "agh",
                    "bvv"
                  ]
                },
                "stimmtyp": {
                  "type": "string",
                  "enum": [
                    "erststimme",
                    "zweitstimme",
                    "einstimme"
                  ]
                },
                "is_repeat_election": {
                  "type": "boolean"
                },
                "parent_slug": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "has_stimmbezirks_geometry": {
                  "type": "boolean"
                },
                "source_name": {
                  "type": "string"
                },
                "source_url": {
                  "type": "string"
                },
                "license": {
                  "type": "string"
                }
              },
              "required": [
                "slug",
                "jahr",
                "typ",
                "stimmtyp",
                "is_repeat_election",
                "has_stimmbezirks_geometry",
                "source_name",
                "license"
              ]
            }
          }
        },
        "required": [
          "elections"
        ]
      }
    },
    {
      "name": "get_election_result",
      "description": "Return the top parties at a Berlin address for one election on a selectable aggregation level (stimmbezirk/kiez/bezirk/berlin). Default: finest available. Output: top-5 with vote count + share + color, source + license, caveats for pre-2021 stimmbezirks-level (Briefwahl-asymmetry) or repeat elections.",
      "input_schema": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "election_slug": {
            "type": "string",
            "pattern": "^\\d{4}-(btw-(erststimme|zweitstimme)|agh-(erststimme|zweitstimme)|bvv)$"
          },
          "level": {
            "type": "string",
            "enum": [
              "stimmbezirk",
              "kiez",
              "bezirk",
              "berlin"
            ]
          }
        },
        "required": [
          "lat",
          "lng",
          "election_slug"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "election_slug": {
            "type": "string"
          },
          "level": {
            "type": "string",
            "enum": [
              "stimmbezirk",
              "kiez",
              "bezirk",
              "berlin"
            ]
          },
          "top": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kurzname": {
                  "type": "string"
                },
                "vollname": {
                  "type": "string"
                },
                "stimmen": {
                  "type": "number"
                },
                "anteil": {
                  "type": "number"
                },
                "farbe_hex": {
                  "type": "string"
                }
              },
              "required": [
                "kurzname",
                "vollname",
                "stimmen",
                "anteil",
                "farbe_hex"
              ]
            }
          },
          "caveats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "license": {
            "type": "string"
          }
        },
        "required": [
          "election_slug",
          "level",
          "top",
          "source",
          "license"
        ]
      }
    },
    {
      "name": "compare_elections",
      "description": "Compare multiple elections at a Berlin address on the same aggregation level (sparkline-compatible). Input: 2–8 election_slugs from list_elections. The tool picks the finest level available across ALL elections. Output: series per election with top-5 + caveats.",
      "input_schema": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "election_slugs": {
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^\\d{4}-(btw-(erststimme|zweitstimme)|agh-(erststimme|zweitstimme)|bvv)$"
            },
            "minItems": 2,
            "maxItems": 8
          },
          "level": {
            "type": "string",
            "enum": [
              "stimmbezirk",
              "kiez",
              "bezirk",
              "berlin"
            ]
          }
        },
        "required": [
          "lat",
          "lng",
          "election_slugs"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "level": {
            "type": "string",
            "enum": [
              "stimmbezirk",
              "kiez",
              "bezirk",
              "berlin"
            ]
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "election_slug": {
                  "type": "string"
                },
                "jahr": {
                  "type": "number"
                },
                "top": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kurzname": {
                        "type": "string"
                      },
                      "anteil": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "kurzname",
                      "anteil"
                    ]
                  }
                },
                "caveats": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "election_slug",
                "jahr",
                "top"
              ]
            }
          }
        },
        "required": [
          "level",
          "series"
        ]
      }
    },
    {
      "name": "get_voting_district_geometry",
      "description": "Return the GeoJSON Feature for a single Berlin Stimmbezirk in a given year. Input: district_id (uwbId from get_election_result on stimmbezirks-level, format depends on year) + year. Errors with geometry_not_available for pre-2017 BTW / pre-2016 AGH/BVV.",
      "input_schema": {
        "type": "object",
        "properties": {
          "district_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 40
          },
          "year": {
            "type": "number",
            "minimum": 2011,
            "maximum": 2099
          }
        },
        "required": [
          "district_id",
          "year"
        ],
        "additionalProperties": false
      },
      "output_schema": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "Feature"
            ]
          },
          "geometry": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string"
              },
              "coordinates": {}
            },
            "required": [
              "type",
              "coordinates"
            ]
          },
          "properties": {
            "type": "object",
            "properties": {
              "district_id": {
                "type": "string"
              },
              "year": {
                "type": "number"
              },
              "bezirk_code": {
                "type": "string"
              }
            },
            "required": [
              "district_id",
              "year"
            ]
          }
        },
        "required": [
          "type",
          "geometry",
          "properties"
        ]
      }
    }
  ],
  "resources": [
    {
      "uri_template": "navigator://address/current",
      "name": "active-address",
      "description": "The address currently selected in the navigator.berlin Inspector (display name, lat/lng, Bezirk, Kiez, postcode). Empty when no address is active."
    },
    {
      "uri_template": "navigator://layers/active",
      "name": "loaded-layers",
      "description": "Currently active and soft-hidden layer slugs in the live UI state. Reflects user-toggled data layers in real time."
    },
    {
      "uri_template": "navigator://bezirk/{slug}",
      "name": "bezirk-profile-ref",
      "description": "Read-only reference to a Berlin Bezirk by slug. Fetch the actual profile via the `get_kiez_profile` tool (Bezirk-level via separate tool)."
    },
    {
      "uri_template": "navigator://kiez/{slug}",
      "name": "kiez-profile-ref",
      "description": "Read-only reference to a Berlin Kiez (LOR Bezirksregion) by slug. Fetch the actual profile via the `get_kiez_profile` tool."
    }
  ],
  "prompts": [
    {
      "name": "address_overview",
      "description": "Summarize what is notable about a Berlin address (noise, air, green, mobility, housing) using cross_layer_query and get_kiez_profile, with full source citations.",
      "arguments": [
        {
          "name": "address",
          "description": "Human-readable address string or display name.",
          "required": true
        }
      ],
      "supported_locales": [
        "de",
        "en"
      ]
    },
    {
      "name": "compare_kieze",
      "description": "Compare two Berlin Kieze (LOR Bezirksregionen) by slug using get_kiez_profile, with cited differences across population, area, and data coverage.",
      "arguments": [
        {
          "name": "slug_a",
          "description": "Slug of the first Kiez.",
          "required": true
        },
        {
          "name": "slug_b",
          "description": "Slug of the second Kiez.",
          "required": true
        }
      ],
      "supported_locales": [
        "de",
        "en"
      ]
    },
    {
      "name": "explain_layer",
      "description": "Explain a single navigator.berlin data layer (by slug) to a non-expert: source, license, methodology, gaps, citations.",
      "arguments": [
        {
          "name": "slug",
          "description": "Layer slug, e.g. `laerm-2023` or `wohnlagen-2024`.",
          "required": true
        }
      ],
      "supported_locales": [
        "de",
        "en"
      ]
    }
  ]
}
