Spaces:
Sleeping
Sleeping
serichard1
commited on
Commit
·
12e7a1a
1
Parent(s):
327efa4
new day
Browse files- app.py +291 -406
- gradio_mcp_server.py +335 -97
- lexison +1 -0
app.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
import asyncio
|
| 2 |
import os
|
| 3 |
import json
|
| 4 |
-
import base64
|
| 5 |
from typing import List, Dict, Any, Union, Optional
|
| 6 |
from contextlib import AsyncExitStack
|
| 7 |
|
|
@@ -10,8 +9,6 @@ from gradio.components.chatbot import ChatMessage
|
|
| 10 |
from mcp import ClientSession, StdioServerParameters
|
| 11 |
from mcp.client.stdio import stdio_client
|
| 12 |
from anthropic import Anthropic
|
| 13 |
-
from openai import OpenAI
|
| 14 |
-
from mistralai.client import MistralClient
|
| 15 |
from dotenv import load_dotenv
|
| 16 |
|
| 17 |
load_dotenv()
|
|
@@ -23,50 +20,27 @@ class MCPClientWrapper:
|
|
| 23 |
def __init__(self):
|
| 24 |
self.session = None
|
| 25 |
self.exit_stack = None
|
| 26 |
-
self.
|
| 27 |
self.tools = []
|
| 28 |
self.connected = False
|
| 29 |
-
self.
|
| 30 |
-
self.
|
| 31 |
|
| 32 |
-
def
|
| 33 |
-
"""Initialize
|
| 34 |
if os.getenv("ANTHROPIC_API_KEY"):
|
| 35 |
-
self.
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
self.clients["openai"] = OpenAI()
|
| 39 |
-
|
| 40 |
-
if os.getenv("MISTRAL_API_KEY"):
|
| 41 |
-
self.clients["mistral"] = MistralClient(api_key=os.getenv("MISTRAL_API_KEY"))
|
| 42 |
-
|
| 43 |
-
if os.getenv("LLAMAINDEX_API_KEY"):
|
| 44 |
-
# Assuming this is for a generic API that accepts OpenAI-compatible format
|
| 45 |
-
self.clients["llama"] = OpenAI(
|
| 46 |
-
api_key=os.getenv("LLAMAINDEX_API_KEY"),
|
| 47 |
-
base_url="https://api.llamaindex.ai/v1" # Adjust URL as needed
|
| 48 |
-
)
|
| 49 |
-
|
| 50 |
-
def set_provider(self, provider: str):
|
| 51 |
-
"""Set the current LLM provider"""
|
| 52 |
-
if provider in self.clients:
|
| 53 |
-
self.current_provider = provider
|
| 54 |
-
return f"✅ Switched to {provider.upper()}"
|
| 55 |
-
return f"❌ {provider.upper()} API key not found"
|
| 56 |
-
|
| 57 |
-
def get_available_providers(self) -> List[str]:
|
| 58 |
-
"""Get list of available providers"""
|
| 59 |
-
return list(self.clients.keys())
|
| 60 |
|
| 61 |
def connect(self) -> str:
|
| 62 |
return loop.run_until_complete(self._connect())
|
| 63 |
-
|
| 64 |
async def _connect(self) -> str:
|
| 65 |
if self.exit_stack:
|
| 66 |
await self.exit_stack.aclose()
|
| 67 |
|
| 68 |
self.exit_stack = AsyncExitStack()
|
| 69 |
-
|
| 70 |
server_path = "gradio_mcp_server.py"
|
| 71 |
|
| 72 |
server_params = StdioServerParameters(
|
|
@@ -90,11 +64,10 @@ class MCPClientWrapper:
|
|
| 90 |
} for tool in response.tools]
|
| 91 |
|
| 92 |
self.connected = True
|
| 93 |
-
|
| 94 |
-
return f"✅ Connected to MCP Weather Server. Available tools: {', '.join(tool_names)}"
|
| 95 |
except Exception as e:
|
| 96 |
self.connected = False
|
| 97 |
-
return f"
|
| 98 |
|
| 99 |
def _read_file_content(self, file_path: str) -> str:
|
| 100 |
"""Read and extract text content from uploaded file"""
|
|
@@ -122,7 +95,6 @@ class MCPClientWrapper:
|
|
| 122 |
return f.read()
|
| 123 |
|
| 124 |
else:
|
| 125 |
-
# Try to read as text, fallback to binary info
|
| 126 |
try:
|
| 127 |
with open(file_path, 'r', encoding='utf-8') as f:
|
| 128 |
return f.read()
|
|
@@ -133,14 +105,15 @@ class MCPClientWrapper:
|
|
| 133 |
except Exception as e:
|
| 134 |
return f"Error reading file {os.path.basename(file_path)}: {str(e)}"
|
| 135 |
|
| 136 |
-
|
|
|
|
|
|
|
| 137 |
if not self.session or not self.connected:
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
], gr.Textbox(value=""), None
|
| 142 |
|
| 143 |
-
# Process uploaded files
|
| 144 |
file_content = ""
|
| 145 |
if files:
|
| 146 |
file_content = "\n\n--- UPLOADED FILES ---\n"
|
|
@@ -151,42 +124,68 @@ class MCPClientWrapper:
|
|
| 151 |
file_path = file
|
| 152 |
|
| 153 |
content = self._read_file_content(file_path)
|
| 154 |
-
file_content += f"\
|
| 155 |
file_content += "--- END FILES ---\n\n"
|
| 156 |
|
| 157 |
# Combine message with file content
|
| 158 |
full_message = file_content + message if file_content else message
|
| 159 |
|
|
|
|
| 160 |
new_messages = loop.run_until_complete(self._process_query(full_message, history))
|
| 161 |
-
|
| 162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
|
| 164 |
async def _process_query(self, message: str, history: List[Union[Dict[str, Any], ChatMessage]]):
|
| 165 |
-
if
|
| 166 |
-
return [{"role": "assistant", "content":
|
| 167 |
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
- Always analyze tool results to determine if you need additional calls
|
| 179 |
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
|
|
|
|
|
|
|
|
|
| 185 |
|
| 186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
|
|
|
|
| 188 |
claude_messages = []
|
| 189 |
-
|
| 190 |
for msg in history:
|
| 191 |
if isinstance(msg, ChatMessage):
|
| 192 |
role, content = msg.role, msg.content
|
|
@@ -199,414 +198,300 @@ class MCPClientWrapper:
|
|
| 199 |
claude_messages.append({"role": "user", "content": message})
|
| 200 |
|
| 201 |
try:
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
model="claude-3-5-sonnet-20241022",
|
| 205 |
-
max_tokens=1500,
|
| 206 |
-
system=system_prompt, # System prompt as separate parameter
|
| 207 |
-
messages=claude_messages,
|
| 208 |
-
tools=self.tools
|
| 209 |
-
)
|
| 210 |
-
return await self._process_claude_response(response, claude_messages, system_prompt)
|
| 211 |
|
| 212 |
-
elif self.current_provider == "openai":
|
| 213 |
-
# For OpenAI, add system message to messages array
|
| 214 |
-
openai_messages = [{"role": "system", "content": system_prompt}] + claude_messages
|
| 215 |
-
|
| 216 |
-
openai_tools = []
|
| 217 |
-
for tool in self.tools:
|
| 218 |
-
openai_tools.append({
|
| 219 |
-
"type": "function",
|
| 220 |
-
"function": {
|
| 221 |
-
"name": tool["name"],
|
| 222 |
-
"description": tool["description"],
|
| 223 |
-
"parameters": tool["input_schema"]
|
| 224 |
-
}
|
| 225 |
-
})
|
| 226 |
-
|
| 227 |
-
response = client.chat.completions.create(
|
| 228 |
-
model="gpt-4-turbo-preview",
|
| 229 |
-
max_tokens=1500,
|
| 230 |
-
messages=openai_messages,
|
| 231 |
-
tools=openai_tools if openai_tools else None
|
| 232 |
-
)
|
| 233 |
-
return await self._process_openai_response(response, openai_messages)
|
| 234 |
-
|
| 235 |
-
elif self.current_provider == "mistral":
|
| 236 |
-
response = client.chat(
|
| 237 |
-
model="mistral-large-latest",
|
| 238 |
-
max_tokens=1500,
|
| 239 |
-
messages=claude_messages,
|
| 240 |
-
tools=self.tools if self.tools else None
|
| 241 |
-
)
|
| 242 |
-
return await self._process_mistral_response(response, claude_messages)
|
| 243 |
-
|
| 244 |
-
elif self.current_provider == "llama":
|
| 245 |
-
response = client.chat.completions.create(
|
| 246 |
-
model="llama-2-70b-chat", # Adjust model name as needed
|
| 247 |
-
max_tokens=1500,
|
| 248 |
-
messages=claude_messages,
|
| 249 |
-
tools=self.tools if self.tools else None
|
| 250 |
-
)
|
| 251 |
-
return await self._process_openai_response(response, claude_messages) # Same format as OpenAI
|
| 252 |
-
|
| 253 |
except Exception as e:
|
| 254 |
-
return [{"role": "assistant", "content": f"
|
| 255 |
|
| 256 |
-
async def
|
|
|
|
| 257 |
result_messages = []
|
| 258 |
-
|
| 259 |
-
|
| 260 |
|
| 261 |
-
while
|
| 262 |
-
|
| 263 |
-
current_round += 1
|
| 264 |
|
| 265 |
-
|
| 266 |
-
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
result_messages.append({
|
| 275 |
"role": "assistant",
|
| 276 |
-
"content":
|
| 277 |
-
"metadata": {"title": f"Tool {current_round}: {tool_name}", "status": "pending"}
|
| 278 |
})
|
| 279 |
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
if isinstance(result_content, list):
|
| 284 |
-
result_content = "\n".join(str(item) for item in result_content)
|
| 285 |
-
|
| 286 |
-
result_messages.append({
|
| 287 |
"role": "assistant",
|
| 288 |
-
"content":
|
| 289 |
-
"metadata": {"title": f"Tool {current_round} Result", "status": "done"}
|
| 290 |
-
})
|
| 291 |
-
|
| 292 |
-
# Add tool result to conversation context for next round
|
| 293 |
-
claude_messages.append({
|
| 294 |
-
"role": "assistant",
|
| 295 |
-
"content": f"I used {tool_name} and got this result: {result_content}"
|
| 296 |
-
})
|
| 297 |
-
claude_messages.append({
|
| 298 |
-
"role": "user",
|
| 299 |
-
"content": "Based on this result, continue helping me with my original request. If you need more specific information (like station codes, parcel IDs), use the data from previous tool calls to make additional tool calls as needed."
|
| 300 |
})
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
"role": "assistant",
|
| 305 |
-
"content": f"❌ Error calling {tool_name}: {str(e)}",
|
| 306 |
-
"metadata": {"title": "Tool Error", "status": "error"}
|
| 307 |
-
})
|
| 308 |
-
break
|
| 309 |
-
|
| 310 |
-
# If we made tool calls, get Claude's next response
|
| 311 |
-
if has_tool_calls:
|
| 312 |
-
try:
|
| 313 |
-
next_response = self.clients["claude"].messages.create(
|
| 314 |
-
model="claude-3-5-sonnet-20241022",
|
| 315 |
-
max_tokens=1500,
|
| 316 |
-
system=system_prompt, # Keep system prompt consistent
|
| 317 |
-
messages=claude_messages,
|
| 318 |
-
tools=self.tools
|
| 319 |
-
)
|
| 320 |
-
response = next_response
|
| 321 |
-
except Exception as e:
|
| 322 |
-
result_messages.append({
|
| 323 |
-
"role": "assistant",
|
| 324 |
-
"content": f"❌ Error in follow-up analysis: {str(e)}"
|
| 325 |
-
})
|
| 326 |
break
|
| 327 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 328 |
break
|
| 329 |
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
})
|
| 335 |
-
|
| 336 |
-
return result_messages
|
| 337 |
-
|
| 338 |
-
async def _process_openai_response(self, response, claude_messages):
|
| 339 |
-
result_messages = []
|
| 340 |
-
message = response.choices[0].message
|
| 341 |
-
|
| 342 |
-
if message.content:
|
| 343 |
-
result_messages.append({"role": "assistant", "content": message.content})
|
| 344 |
-
|
| 345 |
-
if message.tool_calls:
|
| 346 |
-
for tool_call in message.tool_calls:
|
| 347 |
-
tool_name = tool_call.function.name
|
| 348 |
-
tool_args = json.loads(tool_call.function.arguments)
|
| 349 |
|
| 350 |
-
|
| 351 |
-
"role": "
|
| 352 |
-
"content":
|
| 353 |
-
"metadata": {"title": f"Tool: {tool_name}", "status": "pending"}
|
| 354 |
})
|
| 355 |
|
| 356 |
-
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
|
|
|
|
|
|
|
|
|
|
| 360 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
result_messages.append({
|
| 362 |
"role": "assistant",
|
| 363 |
-
"content":
|
| 364 |
-
"metadata": {"title": "Tool Result", "status": "done"}
|
| 365 |
})
|
| 366 |
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
if message.content:
|
| 374 |
-
result_messages.append({"role": "assistant", "content": message.content})
|
| 375 |
|
| 376 |
return result_messages
|
| 377 |
-
|
| 378 |
-
def _format_tool_result(self, result_content: str) -> str:
|
| 379 |
-
"""Enhanced tool result formatting with data extraction"""
|
| 380 |
-
try:
|
| 381 |
-
result_json = json.loads(result_content)
|
| 382 |
-
|
| 383 |
-
if isinstance(result_json, dict) and result_json.get("type") == "success":
|
| 384 |
-
data = result_json.get("data", {})
|
| 385 |
-
endpoint = result_json.get("endpoint", "")
|
| 386 |
-
|
| 387 |
-
# Handle weather stations list
|
| 388 |
-
if "stations" in endpoint and isinstance(data, list):
|
| 389 |
-
formatted_response = f"## 🌤️ Found {len(data)} Weather Stations\n\n"
|
| 390 |
-
for station in data[:10]: # Show first 10
|
| 391 |
-
if isinstance(station, dict):
|
| 392 |
-
code = station.get("code", station.get("id", "N/A"))
|
| 393 |
-
name = station.get("name", station.get("description", "N/A"))
|
| 394 |
-
formatted_response += f"- **{code}**: {name}\n"
|
| 395 |
-
if len(data) > 10:
|
| 396 |
-
formatted_response += f"\n... and {len(data) - 10} more stations"
|
| 397 |
-
return formatted_response
|
| 398 |
-
|
| 399 |
-
# Handle single weather station
|
| 400 |
-
elif "stations/" in endpoint and "hourly-reports" not in endpoint:
|
| 401 |
-
station_code = result_json.get("station_code", data.get("code", "Unknown"))
|
| 402 |
-
formatted_response = f"## 🌤️ Weather Station: {station_code}\n\n"
|
| 403 |
-
if isinstance(data, dict):
|
| 404 |
-
for key, value in data.items():
|
| 405 |
-
if key not in ["id", "code"]:
|
| 406 |
-
formatted_response += f"- **{key.title()}**: {value}\n"
|
| 407 |
-
return formatted_response
|
| 408 |
-
|
| 409 |
-
# Handle weather data reports (existing logic)
|
| 410 |
-
elif isinstance(data, dict) and "reports" in data:
|
| 411 |
-
return self._format_weather_reports(data, result_json.get("station_code", "Unknown"))
|
| 412 |
-
|
| 413 |
-
# Handle municipalities, parcels, etc.
|
| 414 |
-
elif isinstance(data, list) and len(data) > 0:
|
| 415 |
-
item_type = "Items"
|
| 416 |
-
if "municipalities" in endpoint:
|
| 417 |
-
item_type = "Municipalities"
|
| 418 |
-
elif "parcels" in endpoint:
|
| 419 |
-
item_type = "Parcels"
|
| 420 |
-
|
| 421 |
-
formatted_response = f"## 📍 Found {len(data)} {item_type}\n\n"
|
| 422 |
-
for item in data[:10]:
|
| 423 |
-
if isinstance(item, dict):
|
| 424 |
-
name = item.get("name", item.get("id", item.get("code", "N/A")))
|
| 425 |
-
id_val = item.get("id", item.get("code", ""))
|
| 426 |
-
formatted_response += f"- **{id_val}**: {name}\n"
|
| 427 |
-
return formatted_response
|
| 428 |
-
|
| 429 |
-
# Generic JSON formatting
|
| 430 |
-
return f"```json\n{json.dumps(data, indent=2)}\n```"
|
| 431 |
-
|
| 432 |
-
elif isinstance(result_json, dict) and result_json.get("type") == "error":
|
| 433 |
-
error_msg = result_json.get("message", "Unknown error")
|
| 434 |
-
return f"## ❌ Error\n\n{error_msg}"
|
| 435 |
-
|
| 436 |
-
return f"```json\n{json.dumps(result_json, indent=2)}\n```"
|
| 437 |
-
|
| 438 |
-
except json.JSONDecodeError:
|
| 439 |
-
return f"```\n{result_content}\n```"
|
| 440 |
-
|
| 441 |
-
def _format_weather_reports(self, weather_data: dict, station_code: str) -> str:
|
| 442 |
-
"""Format weather reports data"""
|
| 443 |
-
formatted_response = f"## 🌤️ Weather Data for Station: {station_code}\n\n"
|
| 444 |
-
|
| 445 |
-
reports = weather_data.get("reports", [])
|
| 446 |
-
if isinstance(reports, list) and len(reports) > 0:
|
| 447 |
-
formatted_response += f"**Found {len(reports)} weather reports**\n\n"
|
| 448 |
-
for i, report in enumerate(reports[:5]): # Show first 5
|
| 449 |
-
if isinstance(report, dict):
|
| 450 |
-
timestamp = report.get("timestamp", "Unknown time")
|
| 451 |
-
temperature = report.get("temperature", "N/A")
|
| 452 |
-
humidity = report.get("humidity", "N/A")
|
| 453 |
-
formatted_response += f"**Report {i+1}** ({timestamp}):\n"
|
| 454 |
-
formatted_response += f"- Temperature: {temperature}\n"
|
| 455 |
-
formatted_response += f"- Humidity: {humidity}\n\n"
|
| 456 |
-
|
| 457 |
-
if len(reports) > 5:
|
| 458 |
-
formatted_response += f"... and {len(reports) - 5} more reports\n\n"
|
| 459 |
-
|
| 460 |
-
return formatted_response
|
| 461 |
|
| 462 |
client = MCPClientWrapper()
|
| 463 |
|
| 464 |
def gradio_interface():
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
gr.
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
|
|
|
|
|
|
| 471 |
|
| 472 |
-
#
|
| 473 |
with gr.Row():
|
| 474 |
-
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
label="🤖 LLM Provider",
|
| 481 |
-
scale=1
|
| 482 |
-
)
|
| 483 |
-
else:
|
| 484 |
-
provider_choice = gr.Dropdown(
|
| 485 |
-
choices=["No API keys found"],
|
| 486 |
-
value="No API keys found",
|
| 487 |
-
label="🤖 LLM Provider",
|
| 488 |
-
scale=1,
|
| 489 |
interactive=False
|
| 490 |
)
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
value=
|
| 497 |
-
|
|
|
|
|
|
|
|
|
|
| 498 |
)
|
|
|
|
| 499 |
|
| 500 |
-
#
|
| 501 |
-
chatbot = gr.Chatbot(
|
| 502 |
-
value=[],
|
| 503 |
-
height=600,
|
| 504 |
-
type="messages",
|
| 505 |
-
show_copy_button=True,
|
| 506 |
-
avatar_images=("👤", "🤖"),
|
| 507 |
-
bubble_full_width=False
|
| 508 |
-
)
|
| 509 |
-
|
| 510 |
-
# Input row with file upload
|
| 511 |
with gr.Row():
|
| 512 |
-
with gr.Column(scale=
|
| 513 |
msg = gr.Textbox(
|
| 514 |
-
label="
|
| 515 |
-
placeholder="Ask about weather
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
with gr.Column(scale=2):
|
| 519 |
-
file_upload = gr.File(
|
| 520 |
-
label="📎 Upload Files",
|
| 521 |
-
file_count="multiple",
|
| 522 |
-
file_types=[".txt", ".pdf", ".csv", ".json", ".md", ".py", ".js", ".html", ".xml", ".yaml"]
|
| 523 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
|
| 525 |
-
#
|
| 526 |
-
with gr.Row():
|
| 527 |
-
submit_btn = gr.Button("Send", variant="primary", scale=2)
|
| 528 |
-
clear_btn = gr.Button("🗑️ Clear", scale=1)
|
| 529 |
-
reconnect_btn = gr.Button("🔄 Reconnect MCP", scale=1)
|
| 530 |
-
|
| 531 |
-
# Example queries
|
| 532 |
with gr.Accordion("💡 Example Queries", open=False):
|
| 533 |
gr.Examples(
|
| 534 |
examples=[
|
| 535 |
-
"What weather stations
|
| 536 |
-
"
|
| 537 |
-
"
|
| 538 |
-
"Compare weather patterns between two stations",
|
| 539 |
-
"Analyze the uploaded CSV data with weather information"
|
| 540 |
],
|
| 541 |
inputs=msg
|
| 542 |
)
|
| 543 |
|
| 544 |
# Event handlers
|
| 545 |
def auto_connect():
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
def change_provider(provider):
|
| 549 |
-
if provider != "No API keys found":
|
| 550 |
-
result = client.set_provider(provider)
|
| 551 |
-
return result
|
| 552 |
-
return "❌ No valid provider selected"
|
| 553 |
|
| 554 |
def process_and_clear(message, files, history):
|
| 555 |
if not message.strip() and not files:
|
| 556 |
return history, "", None
|
|
|
|
| 557 |
return client.process_message(message, files, history)
|
| 558 |
|
| 559 |
# Setup events
|
| 560 |
-
demo.load(auto_connect, outputs=
|
| 561 |
-
|
| 562 |
-
provider_choice.change(
|
| 563 |
-
change_provider,
|
| 564 |
-
inputs=provider_choice,
|
| 565 |
-
outputs=gr.Textbox(visible=False) # Hidden output for status
|
| 566 |
-
)
|
| 567 |
|
| 568 |
submit_btn.click(
|
| 569 |
process_and_clear,
|
| 570 |
-
inputs=[msg,
|
| 571 |
-
outputs=[chatbot, msg,
|
| 572 |
)
|
| 573 |
|
| 574 |
msg.submit(
|
| 575 |
process_and_clear,
|
| 576 |
-
inputs=[msg,
|
| 577 |
-
outputs=[chatbot, msg,
|
| 578 |
)
|
| 579 |
|
| 580 |
-
clear_btn.click(lambda: ([], "", None), outputs=[chatbot, msg,
|
| 581 |
-
reconnect_btn.click(auto_connect, outputs=status)
|
| 582 |
|
| 583 |
return demo
|
| 584 |
|
| 585 |
if __name__ == "__main__":
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
"
|
| 589 |
-
"OPENAI_API_KEY": "OpenAI",
|
| 590 |
-
"MISTRAL_API_KEY": "Mistral",
|
| 591 |
-
"LLAMAINDEX_API_KEY": "Llama"
|
| 592 |
-
}
|
| 593 |
-
|
| 594 |
-
found_keys = []
|
| 595 |
-
for key, name in api_keys.items():
|
| 596 |
-
if os.getenv(key):
|
| 597 |
-
found_keys.append(name)
|
| 598 |
-
|
| 599 |
-
if found_keys:
|
| 600 |
-
print(f"🔑 Found API keys for: {', '.join(found_keys)}")
|
| 601 |
else:
|
| 602 |
-
print("
|
| 603 |
-
print("Please set them in your .env file:")
|
| 604 |
-
for key in api_keys.keys():
|
| 605 |
-
print(f"{key}=your_key_here")
|
| 606 |
|
| 607 |
-
print("
|
| 608 |
-
print("
|
| 609 |
-
print("🌐 Weather API endpoint: https://lexicon.osfarm.org/weather/stations")
|
| 610 |
|
| 611 |
interface = gradio_interface()
|
| 612 |
-
interface.launch(debug=True, share=True)
|
|
|
|
|
|
|
|
|
| 1 |
import asyncio
|
| 2 |
import os
|
| 3 |
import json
|
|
|
|
| 4 |
from typing import List, Dict, Any, Union, Optional
|
| 5 |
from contextlib import AsyncExitStack
|
| 6 |
|
|
|
|
| 9 |
from mcp import ClientSession, StdioServerParameters
|
| 10 |
from mcp.client.stdio import stdio_client
|
| 11 |
from anthropic import Anthropic
|
|
|
|
|
|
|
| 12 |
from dotenv import load_dotenv
|
| 13 |
|
| 14 |
load_dotenv()
|
|
|
|
| 20 |
def __init__(self):
|
| 21 |
self.session = None
|
| 22 |
self.exit_stack = None
|
| 23 |
+
self.client = None
|
| 24 |
self.tools = []
|
| 25 |
self.connected = False
|
| 26 |
+
self.max_iterations = 3 # Prevent infinite loops
|
| 27 |
+
self._init_client()
|
| 28 |
|
| 29 |
+
def _init_client(self):
|
| 30 |
+
"""Initialize Claude client"""
|
| 31 |
if os.getenv("ANTHROPIC_API_KEY"):
|
| 32 |
+
self.client = Anthropic()
|
| 33 |
+
else:
|
| 34 |
+
raise ValueError("ANTHROPIC_API_KEY not found in environment")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
def connect(self) -> str:
|
| 37 |
return loop.run_until_complete(self._connect())
|
| 38 |
+
|
| 39 |
async def _connect(self) -> str:
|
| 40 |
if self.exit_stack:
|
| 41 |
await self.exit_stack.aclose()
|
| 42 |
|
| 43 |
self.exit_stack = AsyncExitStack()
|
|
|
|
| 44 |
server_path = "gradio_mcp_server.py"
|
| 45 |
|
| 46 |
server_params = StdioServerParameters(
|
|
|
|
| 64 |
} for tool in response.tools]
|
| 65 |
|
| 66 |
self.connected = True
|
| 67 |
+
return f"Connected to MCP Server. Available tools: {len(self.tools)}"
|
|
|
|
| 68 |
except Exception as e:
|
| 69 |
self.connected = False
|
| 70 |
+
return f"Failed to connect to MCP server: {str(e)}"
|
| 71 |
|
| 72 |
def _read_file_content(self, file_path: str) -> str:
|
| 73 |
"""Read and extract text content from uploaded file"""
|
|
|
|
| 95 |
return f.read()
|
| 96 |
|
| 97 |
else:
|
|
|
|
| 98 |
try:
|
| 99 |
with open(file_path, 'r', encoding='utf-8') as f:
|
| 100 |
return f.read()
|
|
|
|
| 105 |
except Exception as e:
|
| 106 |
return f"Error reading file {os.path.basename(file_path)}: {str(e)}"
|
| 107 |
|
| 108 |
+
# In the MCPClientWrapper class...
|
| 109 |
+
|
| 110 |
+
def process_message(self, message: str, files: Optional[List], history: List[List[str]]) -> tuple:
|
| 111 |
if not self.session or not self.connected:
|
| 112 |
+
# Format the error message correctly for the chatbot
|
| 113 |
+
error_response = "MCP server is not connected. Please check the connection status above."
|
| 114 |
+
return history + [[message, error_response]], "", None
|
|
|
|
| 115 |
|
| 116 |
+
# Process uploaded files (your existing code is fine here)
|
| 117 |
file_content = ""
|
| 118 |
if files:
|
| 119 |
file_content = "\n\n--- UPLOADED FILES ---\n"
|
|
|
|
| 124 |
file_path = file
|
| 125 |
|
| 126 |
content = self._read_file_content(file_path)
|
| 127 |
+
file_content += f"\nFile: {os.path.basename(file_path)}\n{content}\n"
|
| 128 |
file_content += "--- END FILES ---\n\n"
|
| 129 |
|
| 130 |
# Combine message with file content
|
| 131 |
full_message = file_content + message if file_content else message
|
| 132 |
|
| 133 |
+
# This returns a list of dictionaries like [{'role': 'assistant', 'content': '...'}, ...]
|
| 134 |
new_messages = loop.run_until_complete(self._process_query(full_message, history))
|
| 135 |
+
|
| 136 |
+
# 1. Combine all the assistant's generated messages (tool calls, analysis) into a single string.
|
| 137 |
+
assistant_response_parts = [
|
| 138 |
+
msg.get('content', '') for msg in new_messages if msg.get('role') == 'assistant'
|
| 139 |
+
]
|
| 140 |
+
assistant_full_response = "\n\n".join(assistant_response_parts)
|
| 141 |
+
|
| 142 |
+
# 2. Update the history in the format Gradio expects: a list of [user, assistant] pairs.
|
| 143 |
+
updated_history = history + [[message, assistant_full_response]]
|
| 144 |
+
|
| 145 |
+
# 3. Return the correctly formatted history and other component updates.
|
| 146 |
+
return updated_history, "", None
|
| 147 |
|
| 148 |
async def _process_query(self, message: str, history: List[Union[Dict[str, Any], ChatMessage]]):
|
| 149 |
+
if not self.client:
|
| 150 |
+
return [{"role": "assistant", "content": "Claude client not available"}]
|
| 151 |
|
| 152 |
+
# Enhanced system prompt that encourages planning and comprehensive analysis
|
| 153 |
+
system_prompt = """You are LEXICON, an intelligent agricultural and weather data assistant with access to comprehensive databases through specialized tools.
|
| 154 |
+
|
| 155 |
+
CORE MISSION: When users ask questions, you must create and execute detailed plans to provide complete, accurate answers using ALL relevant data sources.
|
| 156 |
|
| 157 |
+
PLANNING APPROACH:
|
| 158 |
+
1. **ANALYZE** the user's question to identify all information needs
|
| 159 |
+
2. **PLAN** a systematic approach using multiple tools and data sources
|
| 160 |
+
3. **EXECUTE** your plan step-by-step, making multiple tool calls as needed
|
| 161 |
+
4. **SYNTHESIZE** all gathered data into a comprehensive, well-structured answer
|
|
|
|
| 162 |
|
| 163 |
+
AVAILABLE DATA SOURCES:
|
| 164 |
+
- Weather stations and meteorological data (current and historical)
|
| 165 |
+
- Municipalities and geographical references
|
| 166 |
+
- Cadastral parcels and CAP (Common Agricultural Policy) parcels
|
| 167 |
+
- Agricultural production data and statistics
|
| 168 |
+
- Seed varieties and vine varieties databases
|
| 169 |
+
- Phytosanitary products and crop protection information
|
| 170 |
+
- Geolocation data (GeoJSON) for mapping and spatial analysis
|
| 171 |
|
| 172 |
+
EXECUTION PRINCIPLES:
|
| 173 |
+
- Make MULTIPLE tool calls to gather complete information
|
| 174 |
+
- Follow up on IDs, codes, or references found in initial results
|
| 175 |
+
- Cross-reference data between different sources when relevant
|
| 176 |
+
- Always aim for comprehensive coverage of the topic
|
| 177 |
+
- If initial results suggest additional relevant data exists, pursue it
|
| 178 |
+
- Provide context and explain relationships between different data points
|
| 179 |
+
|
| 180 |
+
EXAMPLE WORKFLOWS:
|
| 181 |
+
- Location query → Search municipalities → Get detailed info → Fetch cadastral/CAP data → Analyze geographical context
|
| 182 |
+
- Weather inquiry → Find relevant stations → Get station details → Retrieve weather data → Analyze patterns
|
| 183 |
+
- Agricultural question → Search relevant databases → Cross-reference production data → Provide comprehensive agricultural context
|
| 184 |
+
|
| 185 |
+
Remember: Your goal is thorough investigation and complete answers, not quick single-tool responses."""
|
| 186 |
|
| 187 |
+
# Build conversation history for Claude
|
| 188 |
claude_messages = []
|
|
|
|
| 189 |
for msg in history:
|
| 190 |
if isinstance(msg, ChatMessage):
|
| 191 |
role, content = msg.role, msg.content
|
|
|
|
| 198 |
claude_messages.append({"role": "user", "content": message})
|
| 199 |
|
| 200 |
try:
|
| 201 |
+
# Start the iterative tool calling process
|
| 202 |
+
return await self._iterative_tool_calling(claude_messages)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
except Exception as e:
|
| 205 |
+
return [{"role": "assistant", "content": f"Error with Claude: {str(e)}"}]
|
| 206 |
|
| 207 |
+
async def _iterative_tool_calling(self, messages: List[Dict[str, str]]):
|
| 208 |
+
"""Enhanced method that allows Claude to reason through multiple tool calls"""
|
| 209 |
result_messages = []
|
| 210 |
+
conversation_messages = messages.copy()
|
| 211 |
+
iteration = 0
|
| 212 |
|
| 213 |
+
while iteration < self.max_iterations:
|
| 214 |
+
iteration += 1
|
|
|
|
| 215 |
|
| 216 |
+
try:
|
| 217 |
+
# Make API call to Claude
|
| 218 |
+
response = self.client.messages.create(
|
| 219 |
+
model="claude-3-5-sonnet-20241022",
|
| 220 |
+
max_tokens=8192,
|
| 221 |
+
system="""You are LEXICON, an intelligent agricultural and weather data assistant with access to comprehensive databases through specialized tools.
|
| 222 |
+
|
| 223 |
+
CORE MISSION: When users ask questions, you must create and execute detailed plans to provide complete, accurate answers using ALL relevant data sources.
|
| 224 |
+
|
| 225 |
+
PLANNING APPROACH:
|
| 226 |
+
1. **ANALYZE** the user's question to identify all information needs
|
| 227 |
+
2. **PLAN** a systematic approach using multiple tools and data sources
|
| 228 |
+
3. **EXECUTE** your plan step-by-step, making multiple tool calls as needed
|
| 229 |
+
4. **SYNTHESIZE** all gathered data into a comprehensive, well-structured answer
|
| 230 |
+
|
| 231 |
+
AVAILABLE DATA SOURCES:
|
| 232 |
+
- Weather stations and meteorological data (current and historical)
|
| 233 |
+
- Municipalities and geographical references
|
| 234 |
+
- Cadastral parcels and CAP (Common Agricultural Policy) parcels
|
| 235 |
+
- Agricultural production data and statistics
|
| 236 |
+
- Seed varieties and vine varieties databases
|
| 237 |
+
- Phytosanitary products and crop protection information
|
| 238 |
+
- Geolocation data (GeoJSON) for mapping and spatial analysis
|
| 239 |
+
|
| 240 |
+
EXECUTION PRINCIPLES:
|
| 241 |
+
- Make MULTIPLE tool calls to gather complete information
|
| 242 |
+
- Follow up on IDs, codes, or references found in initial results
|
| 243 |
+
- Cross-reference data between different sources when relevant
|
| 244 |
+
- Always aim for comprehensive coverage of the topic
|
| 245 |
+
- If initial results suggest additional relevant data exists, pursue it
|
| 246 |
+
- Provide context and explain relationships between different data points
|
| 247 |
+
|
| 248 |
+
EXAMPLE WORKFLOWS:
|
| 249 |
+
- Location query → Search municipalities → Get detailed info → Fetch cadastral/CAP data → Analyze geographical context
|
| 250 |
+
- Weather inquiry → Find relevant stations → Get station details → Retrieve weather data → Analyze patterns
|
| 251 |
+
- Agricultural question → Search relevant databases → Cross-reference production data → Provide comprehensive agricultural context
|
| 252 |
+
|
| 253 |
+
Remember: Your goal is thorough investigation and complete answers, not quick single-tool responses.""",
|
| 254 |
+
messages=conversation_messages,
|
| 255 |
+
tools=self.tools
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
# Process the response
|
| 259 |
+
has_tool_calls = False
|
| 260 |
+
response_text = ""
|
| 261 |
+
|
| 262 |
+
for content in response.content:
|
| 263 |
+
if content.type == 'text':
|
| 264 |
+
response_text = content.text
|
| 265 |
+
|
| 266 |
+
elif content.type == 'tool_use':
|
| 267 |
+
has_tool_calls = True
|
| 268 |
+
tool_name = content.name
|
| 269 |
+
tool_args = content.input
|
| 270 |
+
tool_call_id = content.id
|
| 271 |
+
|
| 272 |
+
try:
|
| 273 |
+
# Execute the tool call
|
| 274 |
+
result = await self.session.call_tool(tool_name, tool_args)
|
| 275 |
+
raw_result = result.content
|
| 276 |
+
|
| 277 |
+
if isinstance(raw_result, list):
|
| 278 |
+
raw_result = "\n".join(str(item) for item in raw_result)
|
| 279 |
+
|
| 280 |
+
# Add tool result to conversation for Claude to see
|
| 281 |
+
conversation_messages.append({
|
| 282 |
+
"role": "assistant",
|
| 283 |
+
"content": [
|
| 284 |
+
{"type": "tool_use", "id": tool_call_id, "name": tool_name, "input": tool_args}
|
| 285 |
+
]
|
| 286 |
+
})
|
| 287 |
+
conversation_messages.append({
|
| 288 |
+
"role": "user",
|
| 289 |
+
"content": [
|
| 290 |
+
{
|
| 291 |
+
"type": "tool_result",
|
| 292 |
+
"tool_use_id": tool_call_id,
|
| 293 |
+
"content": str(raw_result)
|
| 294 |
+
}
|
| 295 |
+
]
|
| 296 |
+
})
|
| 297 |
+
|
| 298 |
+
# Add to result messages for display
|
| 299 |
+
tool_display = f"🔧 **{tool_name}**({', '.join(f'{k}={v}' for k, v in tool_args.items())})\n\n```json\n{raw_result}\n```"
|
| 300 |
+
result_messages.append({
|
| 301 |
+
"role": "assistant",
|
| 302 |
+
"content": tool_display
|
| 303 |
+
})
|
| 304 |
+
|
| 305 |
+
except Exception as e:
|
| 306 |
+
error_msg = f"❌ Error calling {tool_name}: {str(e)}"
|
| 307 |
+
result_messages.append({
|
| 308 |
+
"role": "assistant",
|
| 309 |
+
"content": error_msg
|
| 310 |
+
})
|
| 311 |
+
|
| 312 |
+
# Add error to conversation
|
| 313 |
+
conversation_messages.append({
|
| 314 |
+
"role": "user",
|
| 315 |
+
"content": [
|
| 316 |
+
{
|
| 317 |
+
"type": "tool_result",
|
| 318 |
+
"tool_use_id": tool_call_id,
|
| 319 |
+
"content": f"Error: {str(e)}"
|
| 320 |
+
}
|
| 321 |
+
]
|
| 322 |
+
})
|
| 323 |
+
|
| 324 |
+
# If there was response text, add it
|
| 325 |
+
if response_text.strip():
|
| 326 |
result_messages.append({
|
| 327 |
"role": "assistant",
|
| 328 |
+
"content": response_text
|
|
|
|
| 329 |
})
|
| 330 |
|
| 331 |
+
# Add to conversation if this isn't just a tool call
|
| 332 |
+
if not has_tool_calls:
|
| 333 |
+
conversation_messages.append({
|
|
|
|
|
|
|
|
|
|
|
|
|
| 334 |
"role": "assistant",
|
| 335 |
+
"content": response_text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
})
|
| 337 |
+
|
| 338 |
+
# If no tool calls were made, we're done with data gathering
|
| 339 |
+
if not has_tool_calls:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
break
|
| 341 |
+
|
| 342 |
+
except Exception as e:
|
| 343 |
+
result_messages.append({
|
| 344 |
+
"role": "assistant",
|
| 345 |
+
"content": f"❌ Error in iteration {iteration}: {str(e)}"
|
| 346 |
+
})
|
| 347 |
break
|
| 348 |
|
| 349 |
+
# After all tool calls, get Claude's final synthesis
|
| 350 |
+
if iteration > 1: # Only if we actually made tool calls
|
| 351 |
+
try:
|
| 352 |
+
final_prompt = "Based on all the data you've gathered above, please provide a comprehensive, well-structured answer to the user's original question. Synthesize the information from all sources and present it in a clear, useful format. Don't repeat the raw data - instead, analyze and explain what it means for the user."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 353 |
|
| 354 |
+
conversation_messages.append({
|
| 355 |
+
"role": "user",
|
| 356 |
+
"content": final_prompt
|
|
|
|
| 357 |
})
|
| 358 |
|
| 359 |
+
final_response = self.client.messages.create(
|
| 360 |
+
model="claude-3-5-sonnet-20241022",
|
| 361 |
+
max_tokens=8192,
|
| 362 |
+
system="You are LEXICON. Provide a comprehensive, synthesized answer based on all the data gathered. Focus on insights, analysis, and practical information rather than repeating raw data.",
|
| 363 |
+
messages=conversation_messages,
|
| 364 |
+
tools=[] # No tools for final synthesis
|
| 365 |
+
)
|
| 366 |
|
| 367 |
+
for content in final_response.content:
|
| 368 |
+
if content.type == 'text':
|
| 369 |
+
result_messages.append({
|
| 370 |
+
"role": "assistant",
|
| 371 |
+
"content": f"## 📋 **Comprehensive Analysis**\n\n{content.text}"
|
| 372 |
+
})
|
| 373 |
+
|
| 374 |
+
except Exception as e:
|
| 375 |
result_messages.append({
|
| 376 |
"role": "assistant",
|
| 377 |
+
"content": f"❌ Error generating final analysis: {str(e)}"
|
|
|
|
| 378 |
})
|
| 379 |
|
| 380 |
+
# # If we hit max iterations, add a note
|
| 381 |
+
# if iteration >= self.max_iterations:
|
| 382 |
+
# result_messages.append({
|
| 383 |
+
# "role": "assistant",
|
| 384 |
+
# "content": f"ℹ️ Reached maximum analysis depth ({self.max_iterations} steps)."
|
| 385 |
+
# })
|
|
|
|
|
|
|
| 386 |
|
| 387 |
return result_messages
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
|
| 389 |
client = MCPClientWrapper()
|
| 390 |
|
| 391 |
def gradio_interface():
|
| 392 |
+
# Keep the custom orange and red theme
|
| 393 |
+
theme = gr.themes.Default(
|
| 394 |
+
primary_hue=gr.themes.colors.orange,
|
| 395 |
+
secondary_hue=gr.themes.colors.red,
|
| 396 |
+
neutral_hue=gr.themes.colors.slate,
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
with gr.Blocks(title="MCP LEXICON", theme=theme, css=".gradio-container {max-width: 95% !important;}") as demo:
|
| 400 |
|
| 401 |
+
# 1. Top row with title and the new dynamic status button
|
| 402 |
with gr.Row():
|
| 403 |
+
with gr.Column(scale=8):
|
| 404 |
+
gr.Markdown("## 🌾 LEXICON CHATBOT")
|
| 405 |
+
with gr.Column(scale=2, min_width=220):
|
| 406 |
+
status_button = gr.Button(
|
| 407 |
+
"Connecting...",
|
| 408 |
+
variant="stop",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 409 |
interactive=False
|
| 410 |
)
|
| 411 |
+
|
| 412 |
+
# 2. Main chat interface with a clear button
|
| 413 |
+
with gr.Row():
|
| 414 |
+
chatbot = gr.Chatbot(
|
| 415 |
+
label="Conversation",
|
| 416 |
+
value=[],
|
| 417 |
+
height=650,
|
| 418 |
+
show_copy_button=True,
|
| 419 |
+
avatar_images=("👤", "🌾"),
|
| 420 |
+
bubble_full_width=False,
|
| 421 |
)
|
| 422 |
+
clear_btn = gr.Button("🗑️ Clear", scale=0)
|
| 423 |
|
| 424 |
+
# 3. Concise input bar at the bottom (standard chatbot layout)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 425 |
with gr.Row():
|
| 426 |
+
with gr.Column(scale=10):
|
| 427 |
msg = gr.Textbox(
|
| 428 |
+
label="User Prompt",
|
| 429 |
+
placeholder="Ask a question about agriculture, weather, or geography...",
|
| 430 |
+
show_label=False,
|
| 431 |
+
container=False # Removes border for a cleaner look
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
)
|
| 433 |
+
|
| 434 |
+
file_btn = gr.UploadButton("📎", file_count="multiple", scale=1)
|
| 435 |
+
|
| 436 |
+
submit_btn = gr.Button(
|
| 437 |
+
"Ask",
|
| 438 |
+
variant="primary",
|
| 439 |
+
scale=1
|
| 440 |
+
)
|
| 441 |
|
| 442 |
+
# Examples accordion remains at the bottom
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
with gr.Accordion("💡 Example Queries", open=False):
|
| 444 |
gr.Examples(
|
| 445 |
examples=[
|
| 446 |
+
"What's the complete agricultural profile of Bignan including weather stations, cadastral parcels, and production data?",
|
| 447 |
+
"Find all weather stations near Paris, get their latest data, and analyze weather patterns",
|
| 448 |
+
"I need comprehensive information about vine varieties and which phytosanitary products are recommended for vineyard management",
|
|
|
|
|
|
|
| 449 |
],
|
| 450 |
inputs=msg
|
| 451 |
)
|
| 452 |
|
| 453 |
# Event handlers
|
| 454 |
def auto_connect():
|
| 455 |
+
for status_update in client.connect():
|
| 456 |
+
yield status_update
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
|
| 458 |
def process_and_clear(message, files, history):
|
| 459 |
if not message.strip() and not files:
|
| 460 |
return history, "", None
|
| 461 |
+
# Simply return the result from the client method
|
| 462 |
return client.process_message(message, files, history)
|
| 463 |
|
| 464 |
# Setup events
|
| 465 |
+
demo.load(auto_connect, outputs=status_button)
|
| 466 |
+
status_button.click(auto_connect, outputs=status_button)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
|
| 468 |
submit_btn.click(
|
| 469 |
process_and_clear,
|
| 470 |
+
inputs=[msg, file_btn, chatbot],
|
| 471 |
+
outputs=[chatbot, msg, file_btn]
|
| 472 |
)
|
| 473 |
|
| 474 |
msg.submit(
|
| 475 |
process_and_clear,
|
| 476 |
+
inputs=[msg, file_btn, chatbot],
|
| 477 |
+
outputs=[chatbot, msg, file_btn]
|
| 478 |
)
|
| 479 |
|
| 480 |
+
clear_btn.click(lambda: ([], "", None), outputs=[chatbot, msg, file_btn], queue=False)
|
|
|
|
| 481 |
|
| 482 |
return demo
|
| 483 |
|
| 484 |
if __name__ == "__main__":
|
| 485 |
+
if not os.getenv("ANTHROPIC_API_KEY"):
|
| 486 |
+
print("Warning: ANTHROPIC_API_KEY not found in environment.")
|
| 487 |
+
print("Please set it in your .env file: ANTHROPIC_API_KEY=your_key_here")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
else:
|
| 489 |
+
print("Found Anthropic API key")
|
|
|
|
|
|
|
|
|
|
| 490 |
|
| 491 |
+
print("Starting Enhanced MCP Client with Multi-Step Planning...")
|
| 492 |
+
print("API endpoint: https://lexicon.osfarm.org")
|
|
|
|
| 493 |
|
| 494 |
interface = gradio_interface()
|
| 495 |
+
interface.launch(debug=True, share=True)
|
| 496 |
+
|
| 497 |
+
# provide everything you know about the municipality of ABANCOURT
|
gradio_mcp_server.py
CHANGED
|
@@ -69,162 +69,400 @@ def make_api_request(endpoint: str, params: dict = None) -> str:
|
|
| 69 |
"message": f"Unexpected error: {str(e)}"
|
| 70 |
})
|
| 71 |
|
| 72 |
-
# WEATHER TOOLS
|
| 73 |
@mcp.tool()
|
| 74 |
-
async def
|
| 75 |
-
"""
|
| 76 |
-
|
| 77 |
|
| 78 |
-
@mcp.tool()
|
| 79 |
-
async def get_weather_station(station_code: str) -> str:
|
| 80 |
-
"""Get details of a specific weather station
|
| 81 |
-
|
| 82 |
Args:
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
"""
|
| 85 |
-
|
|
|
|
| 86 |
|
| 87 |
@mcp.tool()
|
| 88 |
-
async def
|
| 89 |
-
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
Args:
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
"""
|
| 97 |
params = {"page": page}
|
| 98 |
-
if
|
| 99 |
-
|
| 100 |
-
if
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
return make_api_request(f"/weather/stations/{station_code}/hourly-reports.json", params)
|
| 104 |
|
| 105 |
-
# TOOLS
|
| 106 |
@mcp.tool()
|
| 107 |
-
async def
|
| 108 |
-
"""
|
| 109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
@mcp.tool()
|
| 112 |
-
async def
|
| 113 |
-
"""
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
|
| 116 |
-
# GEOGRAPHICAL REFERENCES - CADASTRAL PARCELS
|
| 117 |
@mcp.tool()
|
| 118 |
-
async def
|
| 119 |
-
"""
|
| 120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
@mcp.tool()
|
| 123 |
-
async def
|
| 124 |
-
"""
|
| 125 |
-
|
|
|
|
| 126 |
Args:
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
"""
|
| 129 |
-
return make_api_request(f"/geographical-references/
|
| 130 |
|
| 131 |
@mcp.tool()
|
| 132 |
-
async def
|
| 133 |
-
"""
|
| 134 |
-
|
|
|
|
| 135 |
Args:
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
"""
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
-
# GEOGRAPHICAL REFERENCES - CAP PARCELS
|
| 141 |
@mcp.tool()
|
| 142 |
-
async def
|
| 143 |
-
"""
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
@mcp.tool()
|
| 147 |
-
async def
|
| 148 |
-
"""
|
| 149 |
-
|
|
|
|
| 150 |
Args:
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
"""
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
@mcp.tool()
|
| 156 |
-
async def
|
| 157 |
-
"""
|
|
|
|
|
|
|
| 158 |
Args:
|
| 159 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
"""
|
| 161 |
-
|
|
|
|
| 162 |
|
| 163 |
@mcp.tool()
|
| 164 |
-
async def
|
| 165 |
-
"""
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
|
| 168 |
@mcp.tool()
|
| 169 |
-
async def
|
| 170 |
-
"""
|
| 171 |
-
|
|
|
|
| 172 |
Args:
|
| 173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
"""
|
| 175 |
-
|
|
|
|
| 176 |
|
| 177 |
@mcp.tool()
|
| 178 |
-
async def
|
| 179 |
-
"""
|
| 180 |
-
|
|
|
|
| 181 |
Args:
|
| 182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
"""
|
| 184 |
-
|
|
|
|
|
|
|
| 185 |
|
| 186 |
@mcp.tool()
|
| 187 |
-
async def
|
| 188 |
-
"""
|
| 189 |
-
|
|
|
|
| 190 |
Args:
|
| 191 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
"""
|
| 193 |
-
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
-
# PRODUCTION
|
| 196 |
@mcp.tool()
|
| 197 |
-
async def
|
| 198 |
-
"""
|
| 199 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
|
| 201 |
-
# PHYTOSANITARY
|
| 202 |
@mcp.tool()
|
| 203 |
-
async def
|
| 204 |
-
"""
|
| 205 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
|
| 207 |
@mcp.tool()
|
| 208 |
-
async def
|
| 209 |
-
"""
|
| 210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
|
| 212 |
@mcp.tool()
|
| 213 |
-
async def
|
| 214 |
-
"""
|
| 215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
|
| 217 |
-
# SEEDS
|
| 218 |
@mcp.tool()
|
| 219 |
-
async def
|
| 220 |
-
"""
|
| 221 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
|
| 223 |
-
# VITICULTURE
|
| 224 |
@mcp.tool()
|
| 225 |
-
async def
|
| 226 |
-
"""
|
| 227 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
if __name__ == "__main__":
|
| 230 |
mcp.run(transport='stdio')
|
|
|
|
| 69 |
"message": f"Unexpected error: {str(e)}"
|
| 70 |
})
|
| 71 |
|
|
|
|
| 72 |
@mcp.tool()
|
| 73 |
+
async def get_parcel_identifier_json(latitude: float, longitude: float) -> str:
|
| 74 |
+
"""
|
| 75 |
+
Retrieve parcel identifier information in JSON format for a given geographic location.
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
Args:
|
| 78 |
+
latitude (float): Latitude of the point of interest.
|
| 79 |
+
longitude (float): Longitude of the point of interest.
|
| 80 |
+
|
| 81 |
+
Returns:
|
| 82 |
+
str: JSON string containing parcel identifier data for the specified coordinates.
|
| 83 |
+
|
| 84 |
+
This tool allows you to obtain parcel identification data by providing precise geographic coordinates.
|
| 85 |
+
Useful for reverse-geocoding a location to its cadastral reference.
|
| 86 |
"""
|
| 87 |
+
params = {"latitude": latitude, "longitude": longitude}
|
| 88 |
+
return make_api_request("/tools/parcel-identifier.json", params)
|
| 89 |
|
| 90 |
@mcp.tool()
|
| 91 |
+
async def get_cadastral_parcels(
|
| 92 |
+
page: int = 1,
|
| 93 |
+
code: str = None,
|
| 94 |
+
prefix: str = None,
|
| 95 |
+
section: str = None,
|
| 96 |
+
number: str = None
|
| 97 |
+
) -> str:
|
| 98 |
+
"""
|
| 99 |
+
Retrieve a paginated list of cadastral parcels, with optional filters.
|
| 100 |
+
|
| 101 |
Args:
|
| 102 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 103 |
+
code (str, optional): Commune code to filter parcels.
|
| 104 |
+
prefix (str, optional): Parcel prefix for more precise filtering.
|
| 105 |
+
section (str, optional): Parcel section identifier.
|
| 106 |
+
number (str, optional): Parcel number.
|
| 107 |
+
|
| 108 |
+
Returns:
|
| 109 |
+
str: JSON string containing a list of cadastral parcels matching the filters.
|
| 110 |
+
|
| 111 |
+
This tool enables searching for cadastral parcels using various administrative and parcel-specific filters.
|
| 112 |
+
Useful for exploring land registry data at different levels of granularity.
|
| 113 |
"""
|
| 114 |
params = {"page": page}
|
| 115 |
+
if code: params["code"] = code
|
| 116 |
+
if prefix: params["prefix"] = prefix
|
| 117 |
+
if section: params["section"] = section
|
| 118 |
+
if number: params["number"] = number
|
| 119 |
+
return make_api_request("/geographical-references/cadastral-parcels.json", params)
|
|
|
|
| 120 |
|
|
|
|
| 121 |
@mcp.tool()
|
| 122 |
+
async def get_cadastral_parcel(parcel_id: str) -> str:
|
| 123 |
+
"""
|
| 124 |
+
Retrieve detailed information about a specific cadastral parcel.
|
| 125 |
+
|
| 126 |
+
Args:
|
| 127 |
+
parcel_id (str): Unique identifier of the cadastral parcel.
|
| 128 |
+
|
| 129 |
+
Returns:
|
| 130 |
+
str: JSON string with detailed information about the parcel.
|
| 131 |
+
|
| 132 |
+
Use this tool to get all available data for a single cadastral parcel, including administrative and spatial attributes.
|
| 133 |
+
"""
|
| 134 |
+
return make_api_request(f"/geographical-references/cadastral-parcels/{parcel_id}.json")
|
| 135 |
|
| 136 |
@mcp.tool()
|
| 137 |
+
async def get_cadastral_parcel_prices(postal_code: str = None, city: str = None, department: str = None) -> str:
|
| 138 |
+
"""
|
| 139 |
+
Retrieve cadastral parcel price information, filtered by postal code, city, or department.
|
| 140 |
+
|
| 141 |
+
Args:
|
| 142 |
+
postal_code (str, optional): Postal code to filter results.
|
| 143 |
+
city (str, optional): City name for filtering.
|
| 144 |
+
department (str, optional): Department code or name.
|
| 145 |
+
|
| 146 |
+
Returns:
|
| 147 |
+
str: JSON string with price information for cadastral parcels.
|
| 148 |
+
|
| 149 |
+
This tool provides access to price data for cadastral parcels, supporting multiple administrative filters.
|
| 150 |
+
"""
|
| 151 |
+
params = {}
|
| 152 |
+
if postal_code: params["postal_code"] = postal_code
|
| 153 |
+
if city: params["city"] = city
|
| 154 |
+
if department: params["department"] = department
|
| 155 |
+
return make_api_request("/geographical-references/cadastral-parcel-prices.json", params)
|
| 156 |
|
|
|
|
| 157 |
@mcp.tool()
|
| 158 |
+
async def get_cap_parcels(page: int = 1, city: str = None) -> str:
|
| 159 |
+
"""
|
| 160 |
+
Retrieve a paginated list of CAP (Common Agricultural Policy) parcels, optionally filtered by city.
|
| 161 |
+
|
| 162 |
+
Args:
|
| 163 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 164 |
+
city (str, optional): City name to filter CAP parcels.
|
| 165 |
+
|
| 166 |
+
Returns:
|
| 167 |
+
str: JSON string containing CAP parcels matching the filters.
|
| 168 |
+
|
| 169 |
+
This tool allows you to explore CAP parcels, which are relevant for agricultural policy and subsidy management.
|
| 170 |
+
"""
|
| 171 |
+
params = {"page": page}
|
| 172 |
+
if city: params["city"] = city
|
| 173 |
+
return make_api_request("/geographical-references/cap-parcels.json", params)
|
| 174 |
|
| 175 |
@mcp.tool()
|
| 176 |
+
async def get_cap_parcel(cap_id: str) -> str:
|
| 177 |
+
"""
|
| 178 |
+
Retrieve detailed information about a specific CAP parcel.
|
| 179 |
+
|
| 180 |
Args:
|
| 181 |
+
cap_id (str): Unique identifier of the CAP parcel.
|
| 182 |
+
|
| 183 |
+
Returns:
|
| 184 |
+
str: JSON string with detailed information about the CAP parcel.
|
| 185 |
+
|
| 186 |
+
Use this tool to access all available data for a single CAP parcel, including administrative and spatial attributes.
|
| 187 |
"""
|
| 188 |
+
return make_api_request(f"/geographical-references/cap-parcels/{cap_id}.json")
|
| 189 |
|
| 190 |
@mcp.tool()
|
| 191 |
+
async def get_municipalities(page: int = 1, country: str = None, city: str = None) -> str:
|
| 192 |
+
"""
|
| 193 |
+
Retrieve a paginated list of municipalities, with optional filters for country and city.
|
| 194 |
+
|
| 195 |
Args:
|
| 196 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 197 |
+
country (str, optional): Country name to filter municipalities.
|
| 198 |
+
city (str, optional): City name for more precise filtering.
|
| 199 |
+
|
| 200 |
+
Returns:
|
| 201 |
+
str: JSON string containing municipalities matching the filters.
|
| 202 |
+
|
| 203 |
+
This tool is useful for exploring administrative boundaries and locating municipalities by name or country.
|
| 204 |
"""
|
| 205 |
+
params = {"page": page}
|
| 206 |
+
if country: params["country"] = country
|
| 207 |
+
if city: params["city"] = city
|
| 208 |
+
return make_api_request("/geographical-references/municipalities.json", params)
|
| 209 |
|
|
|
|
| 210 |
@mcp.tool()
|
| 211 |
+
async def get_municipality(municipality_id: str) -> str:
|
| 212 |
+
"""
|
| 213 |
+
Retrieve detailed information about a specific municipality.
|
| 214 |
+
|
| 215 |
+
Args:
|
| 216 |
+
municipality_id (str): Unique identifier of the municipality.
|
| 217 |
+
|
| 218 |
+
Returns:
|
| 219 |
+
str: JSON string with detailed information about the municipality.
|
| 220 |
+
|
| 221 |
+
Use this tool to access all available data for a single municipality, including administrative and spatial attributes.
|
| 222 |
+
"""
|
| 223 |
+
return make_api_request(f"/geographical-references/municipalities/{municipality_id}.json")
|
| 224 |
|
| 225 |
@mcp.tool()
|
| 226 |
+
async def get_productions(page: int = 1, family: str = None, usage: str = None) -> str:
|
| 227 |
+
"""
|
| 228 |
+
Retrieve a paginated list of production data, with optional filters for family and usage.
|
| 229 |
+
|
| 230 |
Args:
|
| 231 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 232 |
+
family (str, optional): Production family (e.g., crop type).
|
| 233 |
+
usage (str, optional): Usage type (e.g., food, feed).
|
| 234 |
+
|
| 235 |
+
Returns:
|
| 236 |
+
str: JSON string containing production data matching the filters.
|
| 237 |
+
|
| 238 |
+
This tool is useful for analyzing agricultural production by type and intended use.
|
| 239 |
"""
|
| 240 |
+
params = {"page": page}
|
| 241 |
+
if family: params["family"] = family
|
| 242 |
+
if usage: params["usage"] = usage
|
| 243 |
+
return make_api_request("/production/productions.json", params)
|
| 244 |
|
| 245 |
@mcp.tool()
|
| 246 |
+
async def get_cropsets(page: int = 1) -> str:
|
| 247 |
+
"""
|
| 248 |
+
Retrieve a paginated list of phytosanitary cropsets.
|
| 249 |
+
|
| 250 |
Args:
|
| 251 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 252 |
+
|
| 253 |
+
Returns:
|
| 254 |
+
str: JSON string containing cropset data.
|
| 255 |
+
|
| 256 |
+
This tool provides access to phytosanitary cropsets, which are important for plant protection and regulatory compliance.
|
| 257 |
"""
|
| 258 |
+
params = {"page": page}
|
| 259 |
+
return make_api_request("/phytosanitary/cropsets.json", params)
|
| 260 |
|
| 261 |
@mcp.tool()
|
| 262 |
+
async def get_phytosanitary_products(page: int = 1, type: str = None, state: str = None) -> str:
|
| 263 |
+
"""
|
| 264 |
+
Retrieve a paginated list of phytosanitary products, with optional filters for type and state.
|
| 265 |
+
|
| 266 |
+
Args:
|
| 267 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 268 |
+
type (str, optional): Product type (e.g., herbicide, fungicide).
|
| 269 |
+
state (str, optional): Product state (e.g., approved, withdrawn).
|
| 270 |
+
|
| 271 |
+
Returns:
|
| 272 |
+
str: JSON string containing phytosanitary products matching the filters.
|
| 273 |
+
|
| 274 |
+
This tool is useful for exploring available plant protection products and their regulatory status.
|
| 275 |
+
"""
|
| 276 |
+
params = {"page": page}
|
| 277 |
+
if type: params["type"] = type
|
| 278 |
+
if state: params["state"] = state
|
| 279 |
+
return make_api_request("/phytosanitary/products.json", params)
|
| 280 |
|
| 281 |
@mcp.tool()
|
| 282 |
+
async def get_phytosanitary_symbols(page: int = 1) -> str:
|
| 283 |
+
"""
|
| 284 |
+
Retrieve a paginated list of phytosanitary symbols.
|
| 285 |
+
|
| 286 |
Args:
|
| 287 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 288 |
+
|
| 289 |
+
Returns:
|
| 290 |
+
str: JSON string containing phytosanitary symbols.
|
| 291 |
+
|
| 292 |
+
This tool provides access to symbols used in plant protection and regulatory documentation.
|
| 293 |
"""
|
| 294 |
+
params = {"page": page}
|
| 295 |
+
return make_api_request("/phytosanitary/symbols.json", params)
|
| 296 |
|
| 297 |
@mcp.tool()
|
| 298 |
+
async def get_seed_varieties(page: int = 1, species: str = None) -> str:
|
| 299 |
+
"""
|
| 300 |
+
Retrieve a paginated list of seed varieties, optionally filtered by species.
|
| 301 |
+
|
| 302 |
Args:
|
| 303 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 304 |
+
species (str, optional): Species name to filter seed varieties.
|
| 305 |
+
|
| 306 |
+
Returns:
|
| 307 |
+
str: JSON string containing seed varieties matching the filters.
|
| 308 |
+
|
| 309 |
+
This tool is useful for exploring available seed varieties for different crops.
|
| 310 |
"""
|
| 311 |
+
params = {"page": page}
|
| 312 |
+
if species: params["species"] = species
|
| 313 |
+
return make_api_request("/seeds/varieties.json", params)
|
| 314 |
|
| 315 |
@mcp.tool()
|
| 316 |
+
async def get_vine_varieties(page: int = 1, category: str = None, color: str = None) -> str:
|
| 317 |
+
"""
|
| 318 |
+
Retrieve a paginated list of vine varieties, with optional filters for category and color.
|
| 319 |
+
|
| 320 |
Args:
|
| 321 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 322 |
+
category (str, optional): Vine category (e.g., table, wine).
|
| 323 |
+
color (str, optional): Grape color (e.g., red, white).
|
| 324 |
+
|
| 325 |
+
Returns:
|
| 326 |
+
str: JSON string containing vine varieties matching the filters.
|
| 327 |
+
|
| 328 |
+
This tool is useful for exploring grapevine diversity and selecting varieties for viticulture.
|
| 329 |
"""
|
| 330 |
+
params = {"page": page}
|
| 331 |
+
if category: params["category"] = category
|
| 332 |
+
if color: params["color"] = color
|
| 333 |
+
return make_api_request("/viticulture/vine-varieties.json", params)
|
| 334 |
|
|
|
|
| 335 |
@mcp.tool()
|
| 336 |
+
async def get_weather_stations(page: int = 1, country: str = None, name: str = None) -> str:
|
| 337 |
+
"""
|
| 338 |
+
Retrieve a paginated list of weather stations, with optional filters for country and station name.
|
| 339 |
+
|
| 340 |
+
Args:
|
| 341 |
+
page (int, optional): Page number for pagination (default: 1).
|
| 342 |
+
country (str, optional): Country name to filter stations.
|
| 343 |
+
name (str, optional): Station name for more precise filtering.
|
| 344 |
+
|
| 345 |
+
Returns:
|
| 346 |
+
str: JSON string containing weather stations matching the filters.
|
| 347 |
+
|
| 348 |
+
This tool is useful for discovering available weather stations and narrowing down by location or name.
|
| 349 |
+
"""
|
| 350 |
+
params = {"page": page}
|
| 351 |
+
if country: params["country"] = country
|
| 352 |
+
if name: params["name"] = name
|
| 353 |
+
return make_api_request("/weather/stations.json", params)
|
| 354 |
|
|
|
|
| 355 |
@mcp.tool()
|
| 356 |
+
async def get_weather_station(station_code: str) -> str:
|
| 357 |
+
"""
|
| 358 |
+
Retrieve detailed information about a specific weather station.
|
| 359 |
+
|
| 360 |
+
Args:
|
| 361 |
+
station_code (str): Unique code identifying the weather station.
|
| 362 |
+
|
| 363 |
+
Returns:
|
| 364 |
+
str: JSON string with detailed information about the weather station.
|
| 365 |
+
|
| 366 |
+
Use this tool to access metadata and attributes for a single weather station.
|
| 367 |
+
"""
|
| 368 |
+
return make_api_request(f"/weather/stations/{station_code}.json")
|
| 369 |
|
| 370 |
@mcp.tool()
|
| 371 |
+
async def get_weather_data(station_code: str, start: str = None, end: str = None) -> str:
|
| 372 |
+
"""
|
| 373 |
+
Retrieve hourly weather reports for a specific station, optionally filtered by date range.
|
| 374 |
+
|
| 375 |
+
Args:
|
| 376 |
+
station_code (str): Unique code identifying the weather station.
|
| 377 |
+
start (str, optional): Start date/time in ISO format (e.g., '2024-01-01T00:00:00Z').
|
| 378 |
+
end (str, optional): End date/time in ISO format (e.g., '2024-01-31T23:59:59Z').
|
| 379 |
+
|
| 380 |
+
Returns:
|
| 381 |
+
str: JSON string containing hourly weather reports for the specified station and date range.
|
| 382 |
+
|
| 383 |
+
This tool is useful for analyzing weather data over time for a given location.
|
| 384 |
+
"""
|
| 385 |
+
params = {}
|
| 386 |
+
if start: params["start"] = start
|
| 387 |
+
if end: params["end"] = end
|
| 388 |
+
return make_api_request(f"/weather/stations/{station_code}/hourly-reports.json", params)
|
| 389 |
|
| 390 |
@mcp.tool()
|
| 391 |
+
async def get_parcel_identifier_geojson(latitude: float, longitude: float) -> str:
|
| 392 |
+
"""
|
| 393 |
+
Retrieve parcel identifier information in GeoJSON format for a given geographic location.
|
| 394 |
+
|
| 395 |
+
Args:
|
| 396 |
+
latitude (float): Latitude of the point of interest.
|
| 397 |
+
longitude (float): Longitude of the point of interest.
|
| 398 |
+
|
| 399 |
+
Returns:
|
| 400 |
+
str: GeoJSON string containing parcel identifier data for the specified coordinates.
|
| 401 |
+
|
| 402 |
+
This tool allows you to obtain spatial parcel identification data for mapping and GIS applications.
|
| 403 |
+
"""
|
| 404 |
+
params = {"latitude": latitude, "longitude": longitude}
|
| 405 |
+
return make_api_request("/tools/parcel-identifier.geojson", params)
|
| 406 |
+
|
| 407 |
+
@mcp.tool()
|
| 408 |
+
async def get_cadastral_parcel_geolocation(parcel_id: str) -> str:
|
| 409 |
+
"""
|
| 410 |
+
Retrieve geolocation data for a specific cadastral parcel in GeoJSON format.
|
| 411 |
+
|
| 412 |
+
Args:
|
| 413 |
+
parcel_id (str): Unique identifier of the cadastral parcel.
|
| 414 |
+
|
| 415 |
+
Returns:
|
| 416 |
+
str: GeoJSON string with spatial data for the parcel.
|
| 417 |
+
|
| 418 |
+
Use this tool to obtain the geometry of a cadastral parcel for mapping or spatial analysis.
|
| 419 |
+
"""
|
| 420 |
+
return make_api_request(f"/geographical-references/cadastral-parcels/{parcel_id}/geolocation.geojson")
|
| 421 |
+
|
| 422 |
+
@mcp.tool()
|
| 423 |
+
async def get_cap_parcel_geolocation(cap_id: str) -> str:
|
| 424 |
+
"""
|
| 425 |
+
Retrieve geolocation data for a specific CAP parcel in GeoJSON format.
|
| 426 |
+
|
| 427 |
+
Args:
|
| 428 |
+
cap_id (str): Unique identifier of the CAP parcel.
|
| 429 |
+
|
| 430 |
+
Returns:
|
| 431 |
+
str: GeoJSON string with spatial data for the CAP parcel.
|
| 432 |
+
|
| 433 |
+
Use this tool to obtain the geometry of a CAP parcel for mapping or spatial analysis.
|
| 434 |
+
"""
|
| 435 |
+
return make_api_request(f"/geographical-references/cap-parcels/{cap_id}/geolocation.geojson")
|
| 436 |
|
|
|
|
| 437 |
@mcp.tool()
|
| 438 |
+
async def get_municipality_cadastre(municipality_id: str) -> str:
|
| 439 |
+
"""
|
| 440 |
+
Retrieve cadastre data for a municipality in GeoJSON format.
|
| 441 |
+
|
| 442 |
+
Args:
|
| 443 |
+
municipality_id (str): Unique identifier of the municipality.
|
| 444 |
+
|
| 445 |
+
Returns:
|
| 446 |
+
str: GeoJSON string with cadastre data for the municipality.
|
| 447 |
+
|
| 448 |
+
Use this tool to obtain the spatial extent of a municipality's cadastre for mapping or GIS analysis.
|
| 449 |
+
"""
|
| 450 |
+
return make_api_request(f"/geographical-references/municipalities/{municipality_id}/cadastre.geojson")
|
| 451 |
|
|
|
|
| 452 |
@mcp.tool()
|
| 453 |
+
async def get_municipality_cap_parcels(municipality_id: str) -> str:
|
| 454 |
+
"""
|
| 455 |
+
Retrieve CAP parcels geolocation data for a municipality in GeoJSON format.
|
| 456 |
+
|
| 457 |
+
Args:
|
| 458 |
+
municipality_id (str): Unique identifier of the municipality.
|
| 459 |
+
|
| 460 |
+
Returns:
|
| 461 |
+
str: GeoJSON string with CAP parcels spatial data for the municipality.
|
| 462 |
+
|
| 463 |
+
Use this tool to obtain the geometry of all CAP parcels within a municipality for mapping or spatial analysis.
|
| 464 |
+
"""
|
| 465 |
+
return make_api_request(f"/geographical-references/municipalities/{municipality_id}/cap-parcels.geojson")
|
| 466 |
|
| 467 |
if __name__ == "__main__":
|
| 468 |
mcp.run(transport='stdio')
|
lexison
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"@id":"http://lexicon.osfarm.org/geographical-references/municipalities.json","title":"Communes","breadcrumbs":[{"@type":"Link","value":"Accueil","method":"GET","href":"/"},{"@type":"Link","value":"Références géographiques","method":"GET","href":"/geographical-references"}],"form":{"country":{"@type":"Select","label":"Pays","options":{"FR":"France"},"required":false},"city":{"@type":"Text","label":"Ville","required":false}},"table":{"columns":{"country":"Pays","city":"Ville","city-code":"Code commune","postal-code":"Code postal","details":"Détails"},"rows":[{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AAST"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64460"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64001_64460_AAST_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABAINVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"55001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"55130"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/55001_55130_ABAINV_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABANCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"59001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"59268"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/59001_59268_ABANCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABANCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60220"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60001_60220_ABANCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABAUCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54610"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54001_54610_ABAUCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABAUCOURT HAUTECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"55002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"55400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/55002_55400_ABAUCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABAUCOURT HAUTECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"55002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"55400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/55002_55400_ABAUCO_HAUTECOURTLE"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBANS DESSOUS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25320"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25001_25320_ABBANS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBANS DESSUS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25440"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25002_25440_ABBANS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBARETZ"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"44001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"44170"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/44001_44170_ABBARE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60430"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60002_60430_ABBECO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"02001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"02300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/02001_02300_ABBECO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBENANS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25340"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25003_25340_ABBENA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBEVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80100"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80001_80100_ABBEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBEVILLE LA RIVIERE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"91001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"91150"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/91001_91150_ABBEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBEVILLE LES CONFLANS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54002_54800_ABBEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBEVILLE ST LUCIEN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60480"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60003_60480_ABBEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABBEVILLERS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25310"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25004_25310_ABBEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABEILHAN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34290"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34001_34290_ABEILH_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABELCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"70001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"70300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/70001_70300_ABELCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABERE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64160"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64002_64160_ABERE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABERGEMENT LA RONCE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"39001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"39500"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/39001_39500_ABERGE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABERGEMENT LE GRAND"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"39002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"39600"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/39002_39600_ABERGE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABERGEMENT LE PETIT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"39003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"39800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/39003_39800_ABERGE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABERGEMENT LES THESY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"39004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"39110"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/39004_39110_ABERGE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABIDOS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64150"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64003_64150_ABIDOS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABILLY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"37001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"37160"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/37001_37160_ABILLY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABITAIN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64390"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64004_64390_ABITAI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABJAT SUR BANDIAT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"24001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"24300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/24001_24300_ABJATS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLAIN ST NAZAIRE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62153"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62001_62153_ABLAIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLAINCOURT PRESSOIR"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80320"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80002_80320_ABLAIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLAINZEVELLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62116"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62002_62116_ABLAIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLANCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"51001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"51240"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/51001_51240_ABLANC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLEIGES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"95002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"95450"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/95002_95450_ABLEIG_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLIS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"78003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"78660"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/78003_78660_ABLIS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLON"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"14001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"14600"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/14001_14600_ABLON_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABLON SUR SEINE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"94001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"94480"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/94001_94480_ABLONS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABOEN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"42001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"42380"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/42001_42380_ABOEN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57920"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57001_57920_ABONCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54115"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54003_54115_ABONCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONCOURT GESINCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"70002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"70500"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/70002_70500_ABONCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONCOURT SUR SEILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57590"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57002_57590_ABONCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONDANCE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"74001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"74360"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/74001_74360_ABONDA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABONDANT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"28001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"28410"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/28001_28410_ABONDA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABOS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64360"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64005_64360_ABOS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABRESCHVILLER"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57560"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57003_57560_ABRESC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABREST"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"03001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"03200"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/03001_03200_ABREST_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABRIES RISTOLAS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"05001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"05460"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/05001_05460_ABRIES_ABRIES"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABRIES RISTOLAS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"05001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"05460"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/05001_05460_ABRIES_RISTOLAS"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABSCON"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"59002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"59215"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/59002_59215_ABSCON_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABZAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"33001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"33230"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/33001_33230_ABZAC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ABZAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"16001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"16500"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/16001_16500_ABZAC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACCOLANS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25250"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25005_25250_ACCOLA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACCONS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"07001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"07160"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/07001_07160_ACCONS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACCOUS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64490"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64006_64490_ACCOUS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHAIN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57340"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57004_57340_ACHAIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHEN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57412"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57006_57412_ACHEN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHENHEIM"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"67001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"67204"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/67001_67204_ACHENH_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHERES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"18001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"18250"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/18001_18250_ACHERE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHERES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"78005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"78260"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/78005_78260_ACHERE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHERES LA FORET"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"77001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"77760"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/77001_77760_ACHERE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHERY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"02002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"02800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/02002_02800_ACHERY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHEUX EN AMIENOIS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80560"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80003_80560_ACHEUX_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHEUX EN VIMEU"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80210"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80004_80210_ACHEUX_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHEVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62320"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62003_62320_ACHEVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHEY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"70003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"70180"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/70003_70180_ACHEY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHICOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62217"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62004_62217_ACHICO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHIET LE GRAND"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62121"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62005_62121_ACHIET_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHIET LE PETIT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62121"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62006_62121_ACHIET_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHUN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"58001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"58110"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/58001_58110_ACHUN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACHY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60690"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60004_60690_ACHY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACIGNE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"35001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"35690"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/35001_35690_ACIGNE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACLOU"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"27001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"27800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/27001_27800_ACLOU_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACON"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"27002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"27570"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/27002_27570_ACON_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACOUA"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"97601"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"97630"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/97601_97630_ACOUA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACQ"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62007"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62144"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62007_62144_ACQ_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACQUIGNY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"27003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"27400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/27003_27400_ACQUIG_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACQUIGNY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"27003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"27400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/27003_27400_ACQUIG_LESPLANCHES"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACQUIN WESTBECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62008"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62380"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62008_62380_ACQUIN_WESTBECOURT"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACQUIN WESTBECOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62008"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62380"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62008_62380_ACQUIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"02003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"02200"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/02003_02200_ACY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACY EN MULTIEN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60620"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60005_60620_ACYENM_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ACY ROMANCE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"08001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"08300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/08001_08300_ACYROM_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAINCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57007"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57580"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57007_57580_ADAINC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAINVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"78006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"78113"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/78006_78113_ADAINV_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAM LES PASSAVANT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25360"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25006_25360_ADAMLE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAM LES VERCEL"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25007"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25530"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25007_25530_ADAMLE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAMSWILLER"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"67002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"67320"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/67002_67320_ADAMSW_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADAST"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"65001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"65260"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/65001_65260_ADAST_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"65002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"65100"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/65002_65100_ADE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADELANGE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"57008"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"57380"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/57008_57380_ADELAN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADELANS ET LE VAL DE BITHAINE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"70004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"70200"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/70004_70200_ADELAN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADERVIELLE POUCHERGUES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"65003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"65240"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/65003_65240_ADERVI_POUCHERGUES"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADERVIELLE POUCHERGUES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"65003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"65240"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/65003_65240_ADERVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADILLY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"79002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"79200"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/79002_79200_ADILLY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADINFER"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62009"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62116"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62009_62116_ADINFE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADISSAN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34230"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34002_34230_ADISSA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADON"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"45001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"45230"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/45001_45230_ADON_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"ADRIERS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"86001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"86430"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/86001_86430_ADRIER_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFA"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"2A001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"20167"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/2A001_20167_AFA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFFIEUX"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"19001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"19260"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/19001_19260_AFFIEU_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFFLEVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54004_54800_AFFLEV_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFFOUX"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"69001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"69170"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/69001_69170_AFFOUX_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFFRACOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54740"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54005_54740_AFFRAC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AFFRINGUES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62010"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62380"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62010_62380_AFFRIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGASSAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"31001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"31230"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/31001_31230_AGASSA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGDE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34003_34300_AGDE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGDE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34300"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34003_34300_AGDE_LECAPDAGDE"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGEL"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34210"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34004_34210_AGEL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGEN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"47001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"47000"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/47001_47000_AGEN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGEN D'AVEYRON"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"12001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"12630"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/12001_12630_AGENDA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGENCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"21001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"21700"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/21001_21700_AGENCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGENVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80370"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80005_80370_AGENVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGENVILLERS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"80006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"80150"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/80006_80150_AGENVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGEVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"52001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"52340"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/52001_52340_AGEVIL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGEY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"21002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"21410"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/21002_21410_AGEY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGHIONE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"2B002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"20270"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/2B002_20270_AGHION_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGINCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"54006"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"54770"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/54006_54770_AGINCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGME"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"47002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"47350"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/47002_47350_AGME_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"47003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"47800"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/47003_47800_AGNAC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNAT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"43001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"43100"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/43001_43100_AGNAT_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNEAUX"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"50002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"50180"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/50002_50180_AGNEAU_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNETZ"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"60007"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"60600"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/60007_60600_AGNETZ_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNEZ LES DUISANS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62011"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62161"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62011_62161_AGNEZL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNICOURT ET SECHELLES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"02004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"02340"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/02004_02340_AGNICO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNIERES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62012"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62690"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62012_62690_AGNIER_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNIN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"38003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"38150"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/38003_38150_AGNIN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNOS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64007"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64007_64400_AGNOS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGNY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"62013"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"62217"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/62013_62217_AGNY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGON COUTAINVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"50003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"50230"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/50003_50230_AGONCO_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGONAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"24002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"24460"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/24002_24460_AGONAC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGONES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"34005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"34190"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/34005_34190_AGONES_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGONGES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"03002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"03210"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/03002_03210_AGONGE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGOS VIDALOS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"65004"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"65400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/65004_65400_AGOSVI_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGRIS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"16003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"16110"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/16003_16110_AGRIS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGUDELLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"17002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"17500"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/17002_17500_AGUDEL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGUESSAC"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"12002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"12520"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/12002_12520_AGUESS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGUILCOURT"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"02005"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"02190"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/02005_02190_AGUILC_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGUTS"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"81001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"81470"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/81001_81470_AGUTS_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AGY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"14003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"14400"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/14003_14400_AGY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHAXE ALCIETTE BASCASSAN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64008"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64220"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64008_64220_AHAXEA_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHETZE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64009"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64210"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64009_64210_AHETZE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHEVILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"88002"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"88500"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/88002_88500_AHEVIL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHUILLE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"53001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"53940"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/53001_53940_AHUILL_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHUN"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"23001"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"23150"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/23001_23150_AHUN_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AHUY"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"21003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"21121"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/21003_21121_AHUY_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AIBES"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"59003"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"59149"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/59003_59149_AIBES_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AIBRE"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"25008"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"25750"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/25008_25750_AIBRE_"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AICIRITS CAMOU SUHAST"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64010"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64120"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64010_64120_AICIRI_CAMOUMIXESUH"}},{"country":{"@type":"Text","label":"Pays","value":"France"},"city":{"@type":"Text","label":"Code postal","value":"AICIRITS CAMOU SUHAST"},"city-code":{"@type":"Text","label":"geographical_references_municipality_postal_code_code","value":"64010"},"postal-code":{"@type":"Text","label":"geographical_references_municipality_code","value":"64120"},"details":{"@type":"Link","value":"Voir","method":"GET","href":"/geographical-references/municipalities/64010_64120_AICIRI_"}}]},"items-per-page":150,"items-count":150,"items-total":39192,"page":1,"total-pages":262,"pages":[{"@type":"Link","value":"1","method":"GET","href":"/geographical-references/municipalities.json?page=1"},{"@type":"Link","value":"2","method":"GET","href":"/geographical-references/municipalities.json?page=2"},{"@type":"Link","value":"3","method":"GET","href":"/geographical-references/municipalities.json?page=3"},{"@type":"Link","value":"4","method":"GET","href":"/geographical-references/municipalities.json?page=4"},{"@type":"Link","value":"5","method":"GET","href":"/geographical-references/municipalities.json?page=5"},{"@type":"Link","value":"6","method":"GET","href":"/geographical-references/municipalities.json?page=6"}],"navigation":{"next-page":{"@type":"Link","value":"Page suivante","method":"GET","href":"/geographical-references/municipalities.json?page=2"},"last-page":{"@type":"Link","value":"262","method":"GET","href":"/geographical-references/municipalities.json?page=262"}},"formats":{"html":{"@type":"Link","value":"HTML","method":"GET","href":"/geographical-references/municipalities"},"json":{"@type":"Link","value":"JSON","method":"GET","href":"/geographical-references/municipalities.json"},"csv":{"@type":"Link","value":"CSV","method":"GET","href":"/geographical-references/municipalities.csv"}}}
|