UNPKG

tak-server-mcp-skyfi

Version:

Model Context Protocol (MCP) server for TAK Server integration with geospatial support

295 lines 13 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.createGeofenceTool = void 0; const turf = __importStar(require("@turf/turf")); const uuid_1 = require("uuid"); exports.createGeofenceTool = { name: 'tak_create_geofence', description: 'Create and manage geofenced areas with alert triggers', category: 'geospatial', requiresAuth: true, requiresWrite: true, inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name for the geofence' }, shape: { type: 'object', properties: { type: { type: 'string', enum: ['circle', 'polygon', 'rectangle'], description: 'Type of geofence shape' }, center: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2, description: 'Center point [lat, lon] for circle or rectangle' }, radius: { type: 'number', minimum: 0, description: 'Radius in meters (for circle)' }, vertices: { type: 'array', items: { type: 'array', items: { type: 'number' }, minItems: 2, maxItems: 2 }, minItems: 3, description: 'Polygon vertices [[lat, lon], ...] (for polygon)' }, width: { type: 'number', minimum: 0, description: 'Width in meters (for rectangle)' }, height: { type: 'number', minimum: 0, description: 'Height in meters (for rectangle)' } }, required: ['type'] }, triggers: { type: 'object', properties: { onEntry: { type: 'boolean', default: true, description: 'Trigger alerts on entry' }, onExit: { type: 'boolean', default: true, description: 'Trigger alerts on exit' }, onDwell: { type: 'object', properties: { enabled: { type: 'boolean', default: false }, duration: { type: 'number', minimum: 1, description: 'Dwell time in seconds before alert' } }, description: 'Trigger alerts on dwelling inside' } } }, monitorTypes: { type: 'array', items: { type: 'string' }, description: 'Entity types to monitor (e.g., ["a-h-*", "a-u-*"])' }, alertLevel: { type: 'string', enum: ['low', 'medium', 'high', 'critical'], default: 'medium', description: 'Alert severity level' }, active: { type: 'boolean', default: true, description: 'Whether the geofence is active' } }, required: ['name', 'shape'] }, handler: async (context) => { const { takClient, params, logger } = context; try { // Generate unique ID for the geofence const geofenceId = `geofence-${(0, uuid_1.v4)()}`; // Create the geofence geometry let geometry; let area = 0; let perimeter = 0; switch (params.shape.type) { case 'circle': if (!params.shape.center || !params.shape.radius) { throw new Error('Circle geofence requires center and radius'); } const center = turf.point([params.shape.center[1], params.shape.center[0]]); geometry = turf.circle(center, params.shape.radius / 1000, { units: 'kilometers' }); area = Math.PI * Math.pow(params.shape.radius, 2); perimeter = 2 * Math.PI * params.shape.radius; break; case 'polygon': if (!params.shape.vertices || params.shape.vertices.length < 3) { throw new Error('Polygon geofence requires at least 3 vertices'); } const vertices = params.shape.vertices.map((v) => [v[1], v[0]]); vertices.push(vertices[0]); // Close the polygon geometry = turf.polygon([vertices]); area = turf.area(geometry); perimeter = turf.length(turf.polygonToLine(geometry), { units: 'meters' }) * 1000; break; case 'rectangle': if (!params.shape.center || !params.shape.width || !params.shape.height) { throw new Error('Rectangle geofence requires center, width, and height'); } const rectCenter = turf.point([params.shape.center[1], params.shape.center[0]]); const bearing = 0; // North-aligned rectangle // Calculate rectangle corners const halfWidth = params.shape.width / 2; const halfHeight = params.shape.height / 2; const topLeft = turf.destination(turf.destination(rectCenter, halfHeight / 1000, bearing, { units: 'kilometers' }), halfWidth / 1000, bearing - 90, { units: 'kilometers' }); const topRight = turf.destination(turf.destination(rectCenter, halfHeight / 1000, bearing, { units: 'kilometers' }), halfWidth / 1000, bearing + 90, { units: 'kilometers' }); const bottomRight = turf.destination(turf.destination(rectCenter, halfHeight / 1000, bearing + 180, { units: 'kilometers' }), halfWidth / 1000, bearing + 90, { units: 'kilometers' }); const bottomLeft = turf.destination(turf.destination(rectCenter, halfHeight / 1000, bearing + 180, { units: 'kilometers' }), halfWidth / 1000, bearing - 90, { units: 'kilometers' }); geometry = turf.polygon([[ topLeft.geometry.coordinates, topRight.geometry.coordinates, bottomRight.geometry.coordinates, bottomLeft.geometry.coordinates, topLeft.geometry.coordinates ]]); area = params.shape.width * params.shape.height; perimeter = 2 * (params.shape.width + params.shape.height); break; default: throw new Error(`Unknown geofence shape: ${params.shape.type}`); } // Create geofence object const geofence = { id: geofenceId, name: params.name, type: params.shape.type, geometry: geometry, triggers: params.triggers || { onEntry: true, onExit: true }, monitorTypes: params.monitorTypes || ['a-*'], // Monitor all by default alertLevel: params.alertLevel || 'medium', active: params.active !== false, created: new Date().toISOString(), creator: 'tak-server-mcp', stats: { area: Math.round(area), perimeter: Math.round(perimeter), areaUnits: 'square meters', perimeterUnits: 'meters' } }; // Send geofence as a CoT event const cotEvent = { type: 'u-d-f', // Drawing feature uid: geofenceId, time: new Date().toISOString(), start: new Date().toISOString(), stale: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // 24 hours how: 'm-g', // Machine generated point: params.shape.center || turf.centroid(geometry).geometry.coordinates.reverse(), detail: { shape: geometry, fillColor: params.alertLevel === 'critical' ? 'FF0000' : params.alertLevel === 'high' ? 'FFA500' : params.alertLevel === 'medium' ? 'FFFF00' : '00FF00', strokeColor: '000000', strokeWidth: 2, labels_on: params.name, remarks: `Geofence: ${params.name}`, contact: { callsign: params.name }, usericon: { iconsetpath: '34ae1613-9645-4222-a9d2-e5f243dea2865/Military/Boundary.png' } } }; await takClient.sendCotEvent({ event: { _attributes: { version: '2.0', uid: geofenceId, type: cotEvent.type, time: cotEvent.time, start: cotEvent.start, stale: cotEvent.stale, how: cotEvent.how }, point: { _attributes: { lat: cotEvent.point[0].toString(), lon: cotEvent.point[1].toString(), hae: '0', ce: '10', le: '10' } }, detail: cotEvent.detail } }); logger.info(`Created geofence: ${geofenceId}`); return { success: true, data: { geofence: geofence, message: `Geofence '${params.name}' created successfully`, cotUid: geofenceId }, metadata: { timestamp: new Date().toISOString(), source: 'tak-server' } }; } catch (error) { logger.error('Failed to create geofence:', error); return { success: false, error: { code: 'TAK_GEOFENCE_ERROR', message: 'Failed to create geofence', details: error instanceof Error ? error.message : 'Unknown error' } }; } } }; //# sourceMappingURL=create-geofence.js.map