docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
156
mcp-unifi/README.md
Normal file
156
mcp-unifi/README.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# UniFi MCP Server
|
||||
|
||||
Model Context Protocol (MCP) server for managing Ubiquiti UniFi/UDM Pro devices through Claude Desktop and other MCP clients.
|
||||
|
||||
## Features
|
||||
|
||||
- List and query UniFi devices (APs, switches, gateways)
|
||||
- View client/station information
|
||||
- Get network and VLAN configurations
|
||||
- View WLAN/WiFi configurations
|
||||
- Monitor events and alarms
|
||||
- Get system information and health status
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Create or update `~/.env` with the following:
|
||||
|
||||
#### Private API Mode (Default)
|
||||
|
||||
```bash
|
||||
# UniFi Controller Configuration
|
||||
UNIFI_UDM_URL=https://192.168.1.1
|
||||
UNIFI_USERNAME=admin
|
||||
UNIFI_PASSWORD=your-password
|
||||
UNIFI_SITE_ID=default # Optional, will use default site if not set
|
||||
UNIFI_API_MODE=private # Optional, defaults to private
|
||||
UNIFI_VERIFY_SSL=false # Set to true for production (requires valid SSL cert)
|
||||
```
|
||||
|
||||
#### Official API Mode
|
||||
|
||||
```bash
|
||||
# UniFi Controller Configuration
|
||||
UNIFI_UDM_URL=https://192.168.1.1
|
||||
UNIFI_API_KEY=your-api-key
|
||||
UNIFI_SITE_ID=default # Optional, will use default site if not set
|
||||
UNIFI_API_MODE=official
|
||||
UNIFI_VERIFY_SSL=false # Set to true for production (requires valid SSL cert)
|
||||
```
|
||||
|
||||
### Getting API Credentials
|
||||
|
||||
#### Official API (API Key)
|
||||
|
||||
1. Access your UniFi Network app
|
||||
2. Navigate to **Settings → Control Plane → Integrations**
|
||||
3. Generate an API key
|
||||
4. Use the API key in `UNIFI_API_KEY` environment variable
|
||||
|
||||
#### Private API (Username/Password)
|
||||
|
||||
- Use your UniFi Controller admin username and password
|
||||
- Private API uses cookie-based session authentication
|
||||
|
||||
## Claude Desktop Integration
|
||||
|
||||
Add to your Claude Desktop config file:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"unifi": {
|
||||
"command": "node",
|
||||
"args": ["/path/to/proxmox/mcp-unifi/dist/index.js"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Config File Locations
|
||||
|
||||
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
||||
- **Linux**: `~/.config/Claude/claude_desktop_config.json`
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Site Management
|
||||
|
||||
- `unifi_list_sites` - List all sites
|
||||
- `unifi_get_site_stats` - Get site statistics
|
||||
|
||||
### Device Management
|
||||
|
||||
- `unifi_list_devices` - List all devices
|
||||
- `unifi_get_device` - Get device by MAC address
|
||||
- `unifi_get_device_stats` - Get device statistics
|
||||
|
||||
### Client Management
|
||||
|
||||
- `unifi_list_clients` - List all active clients
|
||||
- `unifi_get_client` - Get client by ID or MAC address
|
||||
|
||||
### Network Management
|
||||
|
||||
- `unifi_list_networks` - List all networks/VLANs
|
||||
- `unifi_get_network` - Get network by ID
|
||||
|
||||
### WLAN Management
|
||||
|
||||
- `unifi_list_wlans` - List all WLAN configurations
|
||||
- `unifi_get_wlan` - Get WLAN by ID
|
||||
|
||||
### Events & Monitoring
|
||||
|
||||
- `unifi_list_events` - List events
|
||||
- `unifi_list_alarms` - List alarms
|
||||
|
||||
### System Operations
|
||||
|
||||
- `unifi_get_system_info` - Get system information
|
||||
- `unifi_get_health` - Get site health status
|
||||
|
||||
## Usage Examples
|
||||
|
||||
Once configured, you can ask Claude Desktop:
|
||||
|
||||
- "List all devices in my UniFi network"
|
||||
- "Show me the active clients"
|
||||
- "What are the network configurations?"
|
||||
- "Get system information"
|
||||
- "Show me recent events"
|
||||
- "What's the health status of the site?"
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Errors
|
||||
|
||||
- Verify `UNIFI_UDM_URL` is correct (IP address or hostname)
|
||||
- Check that the UniFi Controller is running and accessible
|
||||
- If using self-signed certificates, ensure `UNIFI_VERIFY_SSL=false`
|
||||
|
||||
### Authentication Errors
|
||||
|
||||
- For Private API: Verify `UNIFI_USERNAME` and `UNIFI_PASSWORD` are correct
|
||||
- For Official API: Verify `UNIFI_API_KEY` is correct and valid
|
||||
- Check that the API mode matches your credentials
|
||||
|
||||
### Device/Client Not Found
|
||||
|
||||
- Verify IDs/MAC addresses are correct
|
||||
- Check that `siteId` matches the device's site (if provided)
|
||||
- Ensure the device/client is adopted and online
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
33
mcp-unifi/package.json
Normal file
33
mcp-unifi/package.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "mcp-unifi-server",
|
||||
"version": "1.0.0",
|
||||
"description": "MCP server for Ubiquiti UniFi/UDM Pro Controller management",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "tsc --watch & node --watch dist/index.js",
|
||||
"clean": "rm -rf dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^0.4.0",
|
||||
"unifi-api": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
"typescript": "^5.9.0"
|
||||
},
|
||||
"keywords": [
|
||||
"mcp",
|
||||
"unifi",
|
||||
"ubiquiti",
|
||||
"udm-pro",
|
||||
"network"
|
||||
],
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
110
mcp-unifi/src/index.ts
Normal file
110
mcp-unifi/src/index.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* MCP Server for UniFi Controller
|
||||
*
|
||||
* Entry point for the Model Context Protocol server that provides
|
||||
* tools for managing Ubiquiti UniFi/UDM Pro devices
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { homedir } from 'os';
|
||||
import { UnifiServer } from './server/UnifiServer.js';
|
||||
import { ApiMode } from 'unifi-api';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Load environment variables from ~/.env file (standardized location)
|
||||
const envPath = join(homedir(), '.env');
|
||||
const envPathFallback = join(__dirname, '../.env');
|
||||
|
||||
function loadEnvFile(filePath: string): boolean {
|
||||
try {
|
||||
const envFile = readFileSync(filePath, 'utf8');
|
||||
const envVars = envFile.split('\n').filter(
|
||||
(line) => line.includes('=') && !line.trim().startsWith('#')
|
||||
);
|
||||
for (const line of envVars) {
|
||||
const [key, ...values] = line.split('=');
|
||||
// Validate key is a valid environment variable name
|
||||
if (key && values.length > 0 && /^[A-Z_][A-Z0-9_]*$/.test(key.trim())) {
|
||||
// Remove surrounding quotes if present and trim
|
||||
let value = values.join('=').trim();
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
process.env[key.trim()] = value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Try ~/.env first, then fallback to relative path
|
||||
if (!loadEnvFile(envPath)) {
|
||||
if (!loadEnvFile(envPathFallback)) {
|
||||
console.error('Warning: Could not load .env file from ~/.env or ../.env');
|
||||
}
|
||||
}
|
||||
|
||||
// Get configuration from environment variables
|
||||
const baseUrl = process.env.UNIFI_UDM_URL || 'https://192.168.1.1';
|
||||
const apiMode = (process.env.UNIFI_API_MODE || 'private') as ApiMode;
|
||||
const siteId = process.env.UNIFI_SITE_ID;
|
||||
const verifySSL = process.env.UNIFI_VERIFY_SSL !== 'false';
|
||||
|
||||
let config: {
|
||||
baseUrl: string;
|
||||
apiMode: ApiMode;
|
||||
siteId?: string;
|
||||
verifySSL: boolean;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
};
|
||||
|
||||
if (apiMode === ApiMode.OFFICIAL) {
|
||||
const apiKey = process.env.UNIFI_API_KEY;
|
||||
if (!apiKey) {
|
||||
console.error('Error: UNIFI_API_KEY must be set in environment variables for Official API mode');
|
||||
process.exit(1);
|
||||
}
|
||||
config = {
|
||||
baseUrl,
|
||||
apiMode,
|
||||
apiKey,
|
||||
siteId,
|
||||
verifySSL,
|
||||
};
|
||||
} else {
|
||||
const username = process.env.UNIFI_USERNAME;
|
||||
const password = process.env.UNIFI_PASSWORD;
|
||||
if (!username || !password) {
|
||||
console.error('Error: UNIFI_USERNAME and UNIFI_PASSWORD must be set in environment variables for Private API mode');
|
||||
process.exit(1);
|
||||
}
|
||||
config = {
|
||||
baseUrl,
|
||||
apiMode,
|
||||
username,
|
||||
password,
|
||||
siteId,
|
||||
verifySSL,
|
||||
};
|
||||
}
|
||||
|
||||
// Create and run the server
|
||||
const server = new UnifiServer(config);
|
||||
|
||||
server.run().catch((error) => {
|
||||
console.error('Fatal error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
467
mcp-unifi/src/server/UnifiServer.ts
Normal file
467
mcp-unifi/src/server/UnifiServer.ts
Normal file
@@ -0,0 +1,467 @@
|
||||
/**
|
||||
* MCP Server for UniFi Controller
|
||||
*/
|
||||
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ListToolsRequestSchema,
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import {
|
||||
UnifiClient,
|
||||
ApiMode,
|
||||
SitesService,
|
||||
DevicesService,
|
||||
ClientsService,
|
||||
NetworksService,
|
||||
WlansService,
|
||||
EventsService,
|
||||
SystemService,
|
||||
} from 'unifi-api';
|
||||
|
||||
export interface UnifiServerConfig {
|
||||
baseUrl: string;
|
||||
apiMode?: ApiMode;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
siteId?: string;
|
||||
verifySSL?: boolean;
|
||||
}
|
||||
|
||||
export class UnifiServer {
|
||||
private server: Server;
|
||||
private client: UnifiClient;
|
||||
private sitesService: SitesService;
|
||||
private devicesService: DevicesService;
|
||||
private clientsService: ClientsService;
|
||||
private networksService: NetworksService;
|
||||
private wlansService: WlansService;
|
||||
private eventsService: EventsService;
|
||||
private systemService: SystemService;
|
||||
|
||||
constructor(config: UnifiServerConfig) {
|
||||
this.server = new Server(
|
||||
{
|
||||
name: 'unifi-server',
|
||||
version: '1.0.0',
|
||||
}
|
||||
);
|
||||
|
||||
this.client = new UnifiClient(config);
|
||||
this.sitesService = new SitesService(this.client);
|
||||
this.devicesService = new DevicesService(this.client);
|
||||
this.clientsService = new ClientsService(this.client);
|
||||
this.networksService = new NetworksService(this.client);
|
||||
this.wlansService = new WlansService(this.client);
|
||||
this.eventsService = new EventsService(this.client);
|
||||
this.systemService = new SystemService(this.client);
|
||||
|
||||
this.setupToolHandlers();
|
||||
}
|
||||
|
||||
private setupToolHandlers() {
|
||||
// List tools
|
||||
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
||||
tools: [
|
||||
{
|
||||
name: 'unifi_list_sites',
|
||||
description: 'List all sites',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_site_stats',
|
||||
description: 'Get site statistics',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
siteId: {
|
||||
type: 'string',
|
||||
description: 'Site ID (optional, uses default if not provided)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_devices',
|
||||
description: 'List all devices',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_device',
|
||||
description: 'Get device by MAC address',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
mac: {
|
||||
type: 'string',
|
||||
description: 'Device MAC address',
|
||||
},
|
||||
},
|
||||
required: ['mac'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_device_stats',
|
||||
description: 'Get device statistics',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
mac: {
|
||||
type: 'string',
|
||||
description: 'Device MAC address (optional, returns all if not provided)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_clients',
|
||||
description: 'List all active clients',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_client',
|
||||
description: 'Get client by ID or MAC address',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
clientId: {
|
||||
type: 'string',
|
||||
description: 'Client ID or MAC address',
|
||||
},
|
||||
},
|
||||
required: ['clientId'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_networks',
|
||||
description: 'List all networks/VLANs',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_network',
|
||||
description: 'Get network by ID',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
networkId: {
|
||||
type: 'string',
|
||||
description: 'Network ID',
|
||||
},
|
||||
},
|
||||
required: ['networkId'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_wlans',
|
||||
description: 'List all WLAN configurations',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_wlan',
|
||||
description: 'Get WLAN by ID',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
wlanId: {
|
||||
type: 'string',
|
||||
description: 'WLAN ID',
|
||||
},
|
||||
},
|
||||
required: ['wlanId'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_events',
|
||||
description: 'List events',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
limit: {
|
||||
type: 'number',
|
||||
description: 'Maximum number of events to return',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_list_alarms',
|
||||
description: 'List alarms',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
archived: {
|
||||
type: 'boolean',
|
||||
description: 'Include archived alarms',
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_system_info',
|
||||
description: 'Get system information',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'unifi_get_health',
|
||||
description: 'Get site health status',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
// Handle tool calls
|
||||
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
try {
|
||||
switch (name) {
|
||||
case 'unifi_list_sites': {
|
||||
const sites = await this.sitesService.listSites();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(sites, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_site_stats': {
|
||||
const siteId = args?.siteId as string | undefined;
|
||||
if (siteId) {
|
||||
this.client.setSiteId(siteId);
|
||||
}
|
||||
const stats = await this.sitesService.getSiteStats(siteId);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(stats, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_devices': {
|
||||
const devices = await this.devicesService.listDevices();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(devices, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_device': {
|
||||
const mac = args?.mac as string;
|
||||
if (!mac) {
|
||||
throw new Error('MAC address is required');
|
||||
}
|
||||
const device = await this.devicesService.getDevice(mac);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(device, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_device_stats': {
|
||||
const mac = args?.mac as string | undefined;
|
||||
const stats = await this.devicesService.getDeviceStats(mac);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(stats, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_clients': {
|
||||
const clients = await this.clientsService.listClients();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(clients, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_client': {
|
||||
const clientId = args?.clientId as string;
|
||||
if (!clientId) {
|
||||
throw new Error('Client ID is required');
|
||||
}
|
||||
const client = await this.clientsService.getClient(clientId);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(client, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_networks': {
|
||||
const networks = await this.networksService.listNetworks();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(networks, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_network': {
|
||||
const networkId = args?.networkId as string;
|
||||
if (!networkId) {
|
||||
throw new Error('Network ID is required');
|
||||
}
|
||||
const network = await this.networksService.getNetwork(networkId);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(network, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_wlans': {
|
||||
const wlans = await this.wlansService.listWlans();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(wlans, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_wlan': {
|
||||
const wlanId = args?.wlanId as string;
|
||||
if (!wlanId) {
|
||||
throw new Error('WLAN ID is required');
|
||||
}
|
||||
const wlan = await this.wlansService.getWlan(wlanId);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(wlan, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_events': {
|
||||
const limit = args?.limit as number | undefined;
|
||||
const events = await this.eventsService.listEvents(limit);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(events, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_list_alarms': {
|
||||
const archived = (args?.archived as boolean) ?? false;
|
||||
const alarms = await this.eventsService.listAlarms(archived);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(alarms, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_system_info': {
|
||||
const info = await this.systemService.getSystemInfo();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(info, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
case 'unifi_get_health': {
|
||||
const health = await this.systemService.getHealth();
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify(health, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: `Error: ${errorMessage}`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const transport = new StdioServerTransport();
|
||||
await this.server.connect(transport);
|
||||
}
|
||||
}
|
||||
23
mcp-unifi/tsconfig.json
Normal file
23
mcp-unifi/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user