Skip to main content
Glama
index.ts13.9 kB
import fetch from "node-fetch"; // Types matching SDK 1.0.1 interface Tool { name: string; description: string; inputSchema: any; } const DEBUG = process.env.DEBUG === 'true'; function debugLog(...args: any[]) { if (DEBUG) { console.error('[DEBUG]', ...args); } } const BASE_URL = "https://external-api.faa.gov/adip"; export const TOOLS: Tool[] = [ { name: "get_airport_details", description: "Get airport details by airport identifier (locId)", inputSchema: { type: "object", properties: { locId: { type: "string", description: "Airport identifier (e.g. SFO)" }, filter: { type: "string", description: "JSONPath filter expression (optional)" } }, required: ["locId"] } }, /* { name: "get_airport_changes_logs", description: "Get all airport changes logs between two timestamps (global)", inputSchema: { type: "object", properties: { from: { type: "string", description: "Timestamp from when to fetch changes (required)" }, to: { type: "string", description: "Timestamp until when to fetch changes (optional)" } }, required: ["from"] } }, { name: "get_airport_changes_logs_for_loc", description: "Get all airport changes logs for a specific airport (locId)", inputSchema: { type: "object", properties: { locId: { type: "string", description: "Airport identifier (e.g. SFO)" }, from: { type: "string", description: "Timestamp from when to fetch changes (optional)" }, to: { type: "string", description: "Timestamp until when to fetch changes (optional)" } }, required: ["locId"] } }, { name: "get_airport_changes_diff", description: "Get data differences for an airport between two timestamps", inputSchema: { type: "object", properties: { locId: { type: "string", description: "Airport identifier (e.g. SFO)" }, from: { type: "string", description: "Timestamp from when to fetch differences (required)" }, to: { type: "string", description: "Timestamp until when to fetch differences (optional)" } }, required: ["locId", "from"] } }, */ { name: "list_airports_radius", description: "Get list of airports in a radius from a lat/lon point", inputSchema: { type: "object", properties: { lat: { type: "number", description: "Latitude (required)" }, lon: { type: "number", description: "Longitude (required)" }, radius: { type: "number", description: "Radius (required)" }, unit: { type: "string", enum: ["KM", "NM", "M", "FT", "MI"], default: "KM", description: "Unit of radius (optional)" }, filter: { type: "string", description: "JSONPath filter expression (optional)" } }, required: ["lat", "lon", "radius"] } }, { name: "list_airports_radius_for_loc", description: "Get list of airports in a radius from a specific airport (locId)", inputSchema: { type: "object", properties: { locId: { type: "string", description: "Airport identifier (e.g. SFO)" }, radius: { type: "number", description: "Radius (required)" }, unit: { type: "string", enum: ["KM", "NM", "M", "FT", "MI"], default: "KM", description: "Unit of radius (optional)" }, filter: { type: "string", description: "JSONPath filter expression (optional)" } }, required: ["locId", "radius"] } }, { name: "list_airports_bbox", description: "Get list of airports in a bounding box from a lat/lon point", inputSchema: { type: "object", properties: { lat: { type: "number", description: "Latitude (required)" }, lon: { type: "number", description: "Longitude (required)" }, bbox: { type: "string", description: "Bounding box as [width,height] (required)" }, unit: { type: "string", enum: ["KM", "NM", "M", "FT", "MI"], default: "KM", description: "Unit of bbox (optional)" } }, required: ["lat", "lon", "bbox"] } }, /* { name: "list_airports_bbox_for_loc", description: "Get list of airports in a bounding box from a specific airport (locId)", inputSchema: { type: "object", properties: { locId: { type: "string", description: "Airport identifier (e.g. SFO)" }, bbox: { type: "string", description: "Bounding box as [width,height] (required)" }, unit: { type: "string", enum: ["KM", "NM", "M", "FT", "MI"], default: "KM", description: "Unit of bbox (optional)" } }, required: ["locId", "bbox"] } }, */ { name: "airport_search", description: "Search for airports (POST)", inputSchema: { type: "object", properties: { search: { type: "object", description: "Search object (see API spec)" } }, required: ["search"] } } ]; function requireAuth() { if (!process.env.FAA_CLIENT_ID || !process.env.FAA_CLIENT_SECRET) { throw new Error('Client ID and Client Secret are required for ADIP API authentication'); } } async function handleGetAirportDetails(locId, filter) { requireAuth(); const url = new URL(`${BASE_URL}/airport-details/${encodeURIComponent(locId)}`); if (filter) url.searchParams.append('filter', filter); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleGetAirportChangesLogs(from, to) { requireAuth(); const url = new URL(`${BASE_URL}/airport-changes/logs`); url.searchParams.append('from', from); if (to) url.searchParams.append('to', to); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleGetAirportChangesLogsForLoc(locId, from, to) { requireAuth(); const url = new URL(`${BASE_URL}/airport-changes/logs/${encodeURIComponent(locId)}`); if (from) url.searchParams.append('from', from); if (to) url.searchParams.append('to', to); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleGetAirportChangesDiff(locId, from, to) { requireAuth(); const url = new URL(`${BASE_URL}/airport-changes/diff/${encodeURIComponent(locId)}`); url.searchParams.append('from', from); if (to) url.searchParams.append('to', to); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleListAirportsRadius(lat, lon, radius, unit, filter) { requireAuth(); const url = new URL(`${BASE_URL}/airport-list/radius`); url.searchParams.append('lat', lat); url.searchParams.append('lon', lon); url.searchParams.append('radius', radius); if (unit) url.searchParams.append('unit', unit); if (filter) url.searchParams.append('filter', filter); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleListAirportsRadiusForLoc(locId, radius, unit, filter) { requireAuth(); const url = new URL(`${BASE_URL}/airport-list/radius/${encodeURIComponent(locId)}`); url.searchParams.append('radius', radius); if (unit) url.searchParams.append('unit', unit); if (filter) url.searchParams.append('filter', filter); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleListAirportsBBox(lat, lon, bbox, unit) { requireAuth(); const url = new URL(`${BASE_URL}/airport-list/bbox`); url.searchParams.append('lat', lat); url.searchParams.append('lon', lon); url.searchParams.append('bbox', bbox); if (unit) url.searchParams.append('unit', unit); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleListAirportsBBoxForLoc(locId, bbox, unit) { requireAuth(); const url = new URL(`${BASE_URL}/airport-list/bbox/${encodeURIComponent(locId)}`); url.searchParams.append('bbox', bbox); if (unit) url.searchParams.append('unit', unit); const response = await fetch(url.toString(), { headers: { 'Accept': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET } }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } async function handleAirportSearch(search) { requireAuth(); const url = new URL(`${BASE_URL}/airport-search`); const response = await fetch(url.toString(), { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'client_id': process.env.FAA_CLIENT_ID, 'client_secret': process.env.FAA_CLIENT_SECRET }, body: JSON.stringify(search) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`ADIP API Error (${response.status}): ${errorText}`); } const data = await response.text(); return { content: [{ type: "text", text: data }], isError: false }; } // Export unified handler function for the main server export async function handleToolCall(toolName: string, args: any) { debugLog('Airports handleToolCall called with:', { toolName, args }); try { switch (toolName) { case "get_airport_details": { const { locId, filter } = args; return await handleGetAirportDetails(locId, filter); } case "get_airport_changes_logs": { const { from, to } = args; return await handleGetAirportChangesLogs(from, to); } case "get_airport_changes_logs_for_loc": { const { locId, from, to } = args; return await handleGetAirportChangesLogsForLoc(locId, from, to); } case "get_airport_changes_diff": { const { locId, from, to } = args; return await handleGetAirportChangesDiff(locId, from, to); } case "list_airports_radius": { const { lat, lon, radius, unit, filter } = args; return await handleListAirportsRadius(lat, lon, radius, unit, filter); } case "list_airports_radius_for_loc": { const { locId, radius, unit, filter } = args; return await handleListAirportsRadiusForLoc(locId, radius, unit, filter); } case "list_airports_bbox": { const { lat, lon, bbox, unit } = args; return await handleListAirportsBBox(lat, lon, bbox, unit); } case "list_airports_bbox_for_loc": { const { locId, bbox, unit } = args; return await handleListAirportsBBoxForLoc(locId, bbox, unit); } case "airport_search": { const { search } = args; return await handleAirportSearch(search); } default: debugLog('Unknown tool:', toolName); return { content: [{ type: "text", text: `Unknown tool: ${toolName}` }], isError: true }; } } catch (error) { debugLog('Error handling tool call:', error); return { content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/blevinstein/aviation-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server