GAIA-431: require countryCode in KKTC-aware city listing tools and ADMINISTRATIVE boundaries

The backend now serves city catalogs per country, so the list_cities tools for forecast and geo alarms take a required countryCode (TUR or CTR) and call /v1/alarms/{forecasts|geometries}/{countryCode}/cities instead of the removed country-less path, which the MCP could no longer reach.

The boundary schema of both register and update tools now rejects ADMINISTRATIVE boundaries without a countryCode of TUR or CTR, mirroring the server-side validation so the client gets a clear error before the request is sent, since city and district ids are only unique within a country. Tool descriptions also explain that KKTC neighbourhoods are sub-districts.
This commit is contained in:
2026-10-05 17:47:47 +03:00
parent c5a57344f0
commit 5adee33546
2 changed files with 38 additions and 16 deletions
+18 -7
View File
@@ -6,7 +6,7 @@ const webhookDescription =
const boundaryDescription =
"Boundary definition. One of:\n" +
"- Administrative: { type: 'ADMINISTRATIVE', cityId: 6, districtId: 557 }\n" +
"- Administrative: { type: 'ADMINISTRATIVE', countryCode: 'TUR', cityId: 6, districtId: 557 } (countryCode is required: TUR for Türkiye, CTR for Northern Cyprus; city and district IDs come from forecast_alarm_list_cities / forecast_alarm_list_districts for that country)\n" +
"- Point: { type: 'POINT', point: { lat: 39.93, lng: 32.85 } }";
export const forecastAlarmTools = [
@@ -167,11 +167,17 @@ export const forecastAlarmTools = [
},
{
name: "forecast_alarm_list_cities",
description: "List all cities in Türkiye available for forecast alarm boundaries.",
description: "List all cities of a country available for forecast alarm boundaries. Supported countries: TUR (Türkiye) and CTR (Northern Cyprus).",
inputSchema: {
type: "object" as const,
properties: {},
required: [],
properties: {
countryCode: {
type: "string",
enum: ["TUR", "CTR"],
description: "ISO 3166 alpha-3 country code: TUR (Türkiye) or CTR (Northern Cyprus)",
},
},
required: ["countryCode"],
},
},
{
@@ -222,7 +228,10 @@ const WebhookSchema = z.object({
const ForecastBoundarySchema = z.object({
type: z.enum(["ADMINISTRATIVE", "POINT"]),
}).passthrough();
}).passthrough().refine(
(boundary) => boundary.type !== "ADMINISTRATIVE" || boundary.countryCode === "TUR" || boundary.countryCode === "CTR",
{ message: "countryCode (TUR or CTR) is required for ADMINISTRATIVE boundaries", path: ["countryCode"] }
);
const ForecastRegisterSchema = z.object({
recipientId: z.string(),
@@ -327,8 +336,10 @@ export async function handleForecastAlarmTool(
case "forecast_alarm_list":
return apiPost("/v1/alarms/forecasts/page", ListSchema.parse(args));
case "forecast_alarm_list_cities":
return apiGet("/v1/alarms/forecasts/cities");
case "forecast_alarm_list_cities": {
const countryCode = z.enum(["TUR", "CTR"]).parse(args.countryCode);
return apiGet(`/v1/alarms/forecasts/${countryCode}/cities`);
}
case "forecast_alarm_get_city": {
const cityId = z.number().parse(args.cityId);
+20 -9
View File
@@ -6,7 +6,7 @@ const webhookDescription =
const boundaryDescription =
"Boundary definition. One of:\n" +
"- Administrative: { type: 'ADMINISTRATIVE', cityId: 6, districtId: 557, neighborhoodId: 55766 }\n" +
"- Administrative: { type: 'ADMINISTRATIVE', countryCode: 'TUR', cityId: 6, districtId: 557, neighborhoodId: 55766 } (countryCode is required: TUR for Türkiye, CTR for Northern Cyprus; IDs come from the catalog tools for that country. For CTR the neighborhood level is the sub-district)\n" +
"- Polygon: { type: 'POLYGON', polygon: { exterior: [{lat, lng}, ...] } }\n" +
"- H3 Index: { type: 'H3INDEX', h3Address: '8928308280fffff' }";
@@ -133,11 +133,17 @@ export const geoAlarmTools = [
},
{
name: "geo_alarm_list_cities",
description: "List all cities in Türkiye available for geo alarm boundaries.",
description: "List all cities of a country available for geo alarm boundaries. Supported countries: TUR (Türkiye) and CTR (Northern Cyprus).",
inputSchema: {
type: "object" as const,
properties: {},
required: [],
properties: {
countryCode: {
type: "string",
enum: ["TUR", "CTR"],
description: "ISO 3166 alpha-3 country code: TUR (Türkiye) or CTR (Northern Cyprus)",
},
},
required: ["countryCode"],
},
},
{
@@ -175,7 +181,7 @@ export const geoAlarmTools = [
},
{
name: "geo_alarm_list_neighborhoods",
description: "List all neighborhoods for a given district.",
description: "List all neighborhoods for a given district. For CTR (Northern Cyprus) neighborhoods are the sub-district level.",
inputSchema: {
type: "object" as const,
properties: {
@@ -186,7 +192,7 @@ export const geoAlarmTools = [
},
{
name: "geo_alarm_get_neighborhood",
description: "Get boundary details for a specific neighborhood by its ID.",
description: "Get boundary details for a specific neighborhood by its ID. For CTR (Northern Cyprus) neighborhoods are the sub-district level.",
inputSchema: {
type: "object" as const,
properties: {
@@ -210,7 +216,10 @@ const WebhookSchema = z.object({
const GeoBoundarySchema = z.object({
type: z.enum(["ADMINISTRATIVE", "POLYGON", "H3INDEX"]),
}).passthrough();
}).passthrough().refine(
(boundary) => boundary.type !== "ADMINISTRATIVE" || boundary.countryCode === "TUR" || boundary.countryCode === "CTR",
{ message: "countryCode (TUR or CTR) is required for ADMINISTRATIVE boundaries", path: ["countryCode"] }
);
const GeoRegisterSchema = z.object({
recipientId: z.string(),
@@ -302,8 +311,10 @@ export async function handleGeoAlarmTool(
case "geo_alarm_list":
return apiPost("/v1/alarms/geometries/page", ListSchema.parse(args));
case "geo_alarm_list_cities":
return apiGet("/v1/alarms/geometries/cities");
case "geo_alarm_list_cities": {
const countryCode = z.enum(["TUR", "CTR"]).parse(args.countryCode);
return apiGet(`/v1/alarms/geometries/${countryCode}/cities`);
}
case "geo_alarm_get_city": {
const cityId = z.number().parse(args.cityId);