import fetch from 'node-fetch';
export async function searchLocations(args: any) {
const { name, count = 10, language = 'en' } = args;
if (typeof name !== 'string' || name.trim().length === 0) {
throw new Error('Location name must be a non-empty string');
}
if (count < 1 || count > 100) {
throw new Error('Count must be between 1 and 100');
}
const encodedName = encodeURIComponent(name.trim());
const url = `https://geocoding-api.open-meteo.com/v1/search?name=${encodedName}&count=${count}&language=${language}&format=json`;
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Open Meteo Geocoding API error: ${response.status} ${response.statusText}`);
}
const data = await response.json() as any;
if (!data.results || data.results.length === 0) {
return {
content: [
{
type: 'text',
text: `# Location Search Results
No locations found for "${name}". Please try:
- Different spelling
- More specific location name
- Adding country or region name
- Using a different language`,
},
],
};
}
const results = data.results.map((location: any) => ({
id: location.id,
name: location.name,
latitude: location.latitude,
longitude: location.longitude,
elevation: location.elevation || 0,
feature_code: location.feature_code,
country_code: location.country_code,
country: location.country,
admin1: location.admin1, // State/Province
admin2: location.admin2, // County/District
admin3: location.admin3,
admin4: location.admin4,
timezone: location.timezone,
population: location.population,
postcodes: location.postcodes,
}));
let searchText = `# Location Search Results
**Search Query:** "${name}"
**Results Found:** ${results.length}
**Language:** ${language}
`;
results.forEach((location: any, index: number) => {
const adminParts = [location.admin4, location.admin3, location.admin2, location.admin1, location.country]
.filter(Boolean)
.join(', ');
const fullLocation = adminParts ? `${location.name}, ${adminParts}` : location.name;
searchText += `## ${index + 1}. ${fullLocation}
- **Coordinates:** ${location.latitude.toFixed(4)}°N, ${location.longitude.toFixed(4)}°E
- **Elevation:** ${location.elevation}m
- **Country Code:** ${location.country_code}
- **Feature:** ${location.feature_code}`;
if (location.timezone) {
searchText += `\n- **Timezone:** ${location.timezone}`;
}
if (location.population) {
searchText += `\n- **Population:** ${location.population.toLocaleString()}`;
}
if (location.postcodes && location.postcodes.length > 0) {
searchText += `\n- **Postcodes:** ${location.postcodes.join(', ')}`;
}
searchText += '\n\n';
});
// Add usage examples
if (results.length > 0) {
const firstResult = results[0];
searchText += `## Quick Usage Examples
To get current weather for **${firstResult.name}**:
\`\`\`
latitude: ${firstResult.latitude}
longitude: ${firstResult.longitude}
\`\`\`
To get weather forecast for **${firstResult.name}**:
\`\`\`
latitude: ${firstResult.latitude}
longitude: ${firstResult.longitude}
days: 7
\`\`\`
`;
}
return {
content: [
{
type: 'text',
text: searchText,
},
{
type: 'text',
text: JSON.stringify({ query: name, results }, null, 2),
},
],
};
} catch (error) {
throw new Error(`Failed to search locations: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}