@mgcrea/mcp-unifi-protect 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,385 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ //#region src/config.d.ts
4
+ /**
5
+ * The private (undocumented) Protect API, mounted under UniFi OS's proxy. This
6
+ * server deliberately wraps this rather than the official Integration API at
7
+ * `/proxy/protect/integration/v1`: the official one has NO historical query
8
+ * capability at all — its only query parameters in the entire published OpenAPI
9
+ * spec are `channel`, `highQuality` and `qualities` — so "what happened at the
10
+ * front door last night" is unanswerable through it.
11
+ *
12
+ * The trade is real and accepted: nothing below is contractual, and Ubiquiti
13
+ * moves these endpoints between Protect releases. `unifi_protect_get_system_info`
14
+ * reports the running version so a mismatch is visible, and
15
+ * `unifi_protect_request` reaches anything that moved without a code change.
16
+ */
17
+ declare const PRIVATE_API_PATH = "/proxy/protect/api";
18
+ /** UniFi OS's own auth surface, which is NOT under the Protect proxy path. */
19
+ declare const LOGIN_PATH = "/api/auth/login";
20
+ /** The realtime channel. Not used yet — see the WebSocket note in the README. */
21
+ declare const UPDATES_WS_PATH = "/proxy/protect/ws/updates";
22
+ declare const ConfigSchema: z.ZodObject<{
23
+ baseUrl: z.ZodOptional<z.ZodString>;
24
+ username: z.ZodOptional<z.ZodString>;
25
+ password: z.ZodOptional<z.ZodString>;
26
+ totp: z.ZodOptional<z.ZodString>;
27
+ verifyTls: z.ZodDefault<z.ZodBoolean>;
28
+ allowWrites: z.ZodDefault<z.ZodBoolean>;
29
+ sessionFile: z.ZodString;
30
+ snapshotDir: z.ZodString;
31
+ maxRetries: z.ZodDefault<z.ZodNumber>;
32
+ maxDownloadBytes: z.ZodDefault<z.ZodNumber>;
33
+ deviceCacheTtlSeconds: z.ZodDefault<z.ZodNumber>;
34
+ }, z.core.$strict>;
35
+ type Config = z.infer<typeof ConfigSchema>;
36
+ /**
37
+ * The on-disk config document. Keys are camelCase to mirror `Config` rather
38
+ * than the env var names: this is a typed JSON file, not a shell.
39
+ *
40
+ * `.strict()` on purpose — a typo'd `userName` must be an error. Silently
41
+ * ignoring an unknown key looks exactly like "that setting had no effect",
42
+ * which is the worst way to learn your credentials came from somewhere else.
43
+ */
44
+ declare const FileConfigSchema: z.ZodObject<{
45
+ host: z.ZodOptional<z.ZodString>;
46
+ username: z.ZodOptional<z.ZodString>;
47
+ password: z.ZodOptional<z.ZodString>;
48
+ verifyTls: z.ZodOptional<z.ZodBoolean>;
49
+ allowWrites: z.ZodOptional<z.ZodBoolean>;
50
+ sessionFile: z.ZodOptional<z.ZodString>;
51
+ snapshotDir: z.ZodOptional<z.ZodString>;
52
+ maxRetries: z.ZodOptional<z.ZodNumber>;
53
+ maxDownloadBytes: z.ZodOptional<z.ZodNumber>;
54
+ deviceCacheTtlSeconds: z.ZodOptional<z.ZodNumber>;
55
+ }, z.core.$strict>;
56
+ type FileConfig = z.infer<typeof FileConfigSchema>;
57
+ /**
58
+ * Normalize whatever someone pasted into a console origin, preserving the port.
59
+ *
60
+ * "192.168.1.1" -> "https://192.168.1.1"
61
+ * "10.0.0.1:8443" -> "https://10.0.0.1:8443"
62
+ * "https://udm.lan/protect/" -> "https://udm.lan"
63
+ *
64
+ * A port must survive: consoles are commonly reached on a non-443 port, and the
65
+ * normalizers in mcp-keycloak and mcp-shopify both drop it. Everything after
66
+ * the origin is discarded — the API paths are this server's business, and a
67
+ * pasted `/protect/dashboard` URL would otherwise be prefixed onto every call.
68
+ *
69
+ * `https` is forced: UniFi OS redirects plain HTTP, and following that redirect
70
+ * would send the session cookie over cleartext on the first hop.
71
+ */
72
+ declare const normalizeBaseUrl: (raw: string) => string;
73
+ /** `readFileSync` does not expand `~`, but it is the natural thing to write in a config file. */
74
+ declare const expandTilde: (path: string) => string;
75
+ /**
76
+ * Where the config file lives, most specific first: an explicit override, then
77
+ * the XDG location, then the conventional `~/.config`.
78
+ */
79
+ declare const resolveConfigPath: (env?: NodeJS.ProcessEnv) => string;
80
+ /** The session file sits beside the config file unless told otherwise. */
81
+ declare const resolveSessionPath: (env?: NodeJS.ProcessEnv) => string;
82
+ /**
83
+ * Environment first, config file second, **per field** — not whole-source.
84
+ * Docker and CI inject the environment and must keep working untouched, while a
85
+ * one-off `UNIFI_PROTECT_ALLOW_WRITES=0` still has to override a file that says
86
+ * `true`. Merging field by field is the only rule that gives both.
87
+ */
88
+ declare const loadConfig: (env?: NodeJS.ProcessEnv, configPath?: string) => Config;
89
+ /** True once the server has everything it needs to reach a console. */
90
+ declare const isConfigured: (config: Config) => boolean;
91
+ /**
92
+ * Returned by unifi_protect_auth_status and printed to stderr at startup. Prose
93
+ * rather than a code, because this is the text someone acts on when nothing
94
+ * works — and the server can no longer signal it by refusing to start.
95
+ */
96
+ declare const setupInstructions: (config: Config) => string[];
97
+ //#endregion
98
+ //#region src/client/auth.d.ts
99
+ type Logger = {
100
+ debug?(...args: unknown[]): void;
101
+ warn?(...args: unknown[]): void;
102
+ error?(...args: unknown[]): void;
103
+ };
104
+ /** The two headers that authenticate every request to a UniFi OS console. */
105
+ type SessionHeaders = {
106
+ cookie: string;
107
+ "x-csrf-token": string;
108
+ };
109
+ type SessionStatus = {
110
+ authenticated: boolean;
111
+ /** Where the live session came from, for unifi_protect_auth_status. */
112
+ source: "none" | "restored" | "login";
113
+ username: string | undefined;
114
+ savedAt: string | undefined;
115
+ };
116
+ /**
117
+ * A pluggable source of console session headers. The client calls `headers()`
118
+ * on every request and `invalidate()` on a 401 to force the next call to
119
+ * re-run the handshake.
120
+ */
121
+ type SessionProvider = {
122
+ headers(): Promise<SessionHeaders>;
123
+ invalidate(): void;
124
+ /** Force a fresh handshake now, optionally with a 2FA code. Used by auth_login. */
125
+ login(totp?: string): Promise<SessionStatus>;
126
+ /** Drop the session in memory and on disk. */
127
+ logout(): Promise<void>;
128
+ describe(): SessionStatus;
129
+ };
130
+ type SessionProviderOptions = {
131
+ config: Config;
132
+ fetch?: typeof fetch;
133
+ logger?: Logger;
134
+ now?: () => number;
135
+ };
136
+ declare const createSessionProvider: (opts: SessionProviderOptions) => SessionProvider;
137
+ /** For tests: fixed headers, no network, no disk. */
138
+ declare const staticSessionProvider: (headers?: SessionHeaders) => SessionProvider;
139
+ //#endregion
140
+ //#region src/client/protect.d.ts
141
+ /** Array values become repeated params, which is how Protect expects `types`. */
142
+ type Query = Record<string, string | number | boolean | string[] | undefined>;
143
+ declare const backoffMs: (attempt: number) => number;
144
+ declare const retryAfterMs: (res: Response) => number | undefined;
145
+ declare const buildQuery: (query: Query | undefined) => string;
146
+ type ProtectClientOptions = {
147
+ baseUrl: string;
148
+ session: SessionProvider;
149
+ maxRetries: number;
150
+ userAgent: string;
151
+ maxDownloadBytes: number;
152
+ fetch?: typeof fetch;
153
+ logger?: Logger;
154
+ };
155
+ type BinaryResult = {
156
+ bytes: Uint8Array;
157
+ contentType: string;
158
+ };
159
+ /**
160
+ * The private Protect API client. Every path passed in is relative to
161
+ * `/proxy/protect/api` — callers write `cameras/abc123`, not the full path.
162
+ */
163
+ declare class ProtectClient {
164
+ readonly baseUrl: string;
165
+ private readonly session;
166
+ private readonly maxRetries;
167
+ private readonly userAgent;
168
+ private readonly maxDownloadBytes;
169
+ private readonly fetchImpl;
170
+ private readonly logger;
171
+ constructor(opts: ProtectClientOptions);
172
+ /** Absolute URL for a path relative to the private API root. */
173
+ url(path: string, query?: Query): string;
174
+ /**
175
+ * Perform one authenticated request, retrying on 401 (re-login), 429 and 5xx.
176
+ * Returns the raw Response so callers can decide between JSON and bytes.
177
+ */
178
+ private send;
179
+ /** A JSON request against the private API. */
180
+ request<T = unknown>(method: string, path: string, opts?: {
181
+ query?: Query;
182
+ body?: unknown;
183
+ }): Promise<T>;
184
+ get<T = unknown>(path: string, query?: Query): Promise<T>;
185
+ post<T = unknown>(path: string, body?: unknown, query?: Query): Promise<T>;
186
+ patch<T = unknown>(path: string, body?: unknown, query?: Query): Promise<T>;
187
+ del<T = unknown>(path: string, query?: Query): Promise<T>;
188
+ /**
189
+ * Fetch a binary asset — a snapshot JPEG, an event thumbnail, an exported
190
+ * MP4. Size is checked against `maxDownloadBytes` from Content-Length where
191
+ * the console supplies one, and again after reading where it does not, so an
192
+ * unexpectedly huge export fails with a clear message rather than by
193
+ * exhausting the heap.
194
+ */
195
+ requestBytes(path: string, opts?: {
196
+ query?: Query;
197
+ accept?: string;
198
+ }): Promise<BinaryResult>;
199
+ /** Status-aware prose, because this is the text someone acts on. */
200
+ private errorMessage;
201
+ }
202
+ //#endregion
203
+ //#region src/client/shape.d.ts
204
+ type Rec = Record<string, unknown>;
205
+ /** Apply a summarizer across an array, passing non-arrays through untouched. */
206
+ declare const summarizeEach: <T>(value: unknown, fn: (item: Rec) => T) => unknown;
207
+ /**
208
+ * Protect timestamps are milliseconds since the Unix epoch. Rendering them as
209
+ * ISO 8601 costs a few characters and saves the model from having to reason
210
+ * about a bare 13-digit integer — which it does get wrong, usually by reading
211
+ * it as seconds and landing in 1970.
212
+ */
213
+ declare const isoTime: (value: unknown) => string | undefined;
214
+ /** An index from device id to display name, used to resolve event references. */
215
+ type NameIndex = ReadonlyMap<string, string>;
216
+ declare const buildNameIndex: (devices: unknown) => NameIndex;
217
+ declare const summarizeCamera: (camera: Rec) => Rec;
218
+ /**
219
+ * Events reference their camera by id. Resolving that to a name server-side is
220
+ * the single most useful thing this layer does: it removes a join the model
221
+ * would otherwise have to perform against a separate camera list, and get
222
+ * silently wrong. The id is kept too, since the write and snapshot tools need it.
223
+ */
224
+ declare const summarizeEvent: (event: Rec, cameras?: NameIndex) => Rec;
225
+ declare const summarizeLight: (light: Rec) => Rec;
226
+ declare const summarizeSensor: (sensor: Rec) => Rec;
227
+ declare const summarizeViewer: (viewer: Rec) => Rec;
228
+ declare const summarizeChime: (chime: Rec) => Rec;
229
+ declare const summarizeLiveview: (liveview: Rec) => Rec;
230
+ declare const summarizeUser: (user: Rec) => Rec;
231
+ declare const summarizeNvr: (nvr: Rec) => Rec;
232
+ /**
233
+ * The bootstrap document is the entire console state and must never be returned
234
+ * raw — it is the single largest context bomb this API offers. This reduces it
235
+ * to the NVR summary plus per-type counts, which is what "tell me about my
236
+ * system" actually wants.
237
+ */
238
+ declare const summarizeBootstrap: (bootstrap: Rec) => Rec;
239
+ //#endregion
240
+ //#region src/client/device-cache.d.ts
241
+ type DeviceCacheOptions = {
242
+ client: ProtectClient;
243
+ ttlSeconds: number;
244
+ now?: () => number;
245
+ };
246
+ /**
247
+ * A short-lived camera id→name index, used to resolve the `camera` reference on
248
+ * every event into something readable.
249
+ *
250
+ * It is cached because event search is the hot path and every result set needs
251
+ * the same index: fetching the camera list once per search rather than once per
252
+ * event is the difference between one extra request and none. The TTL is short
253
+ * because a renamed or newly adopted camera should appear without a restart,
254
+ * and a stale name is only ever cosmetic — the id travels alongside it.
255
+ */
256
+ type DeviceCache = {
257
+ cameras(): Promise<NameIndex>;
258
+ invalidate(): void;
259
+ };
260
+ declare const createDeviceCache: (opts: DeviceCacheOptions) => DeviceCache;
261
+ //#endregion
262
+ //#region src/server.d.ts
263
+ declare const SERVER_NAME: string;
264
+ declare const SERVER_VERSION: string;
265
+ declare const USER_AGENT: string;
266
+ type CreateServerOptions = {
267
+ config: Config;
268
+ fetch?: typeof fetch;
269
+ logger?: Logger;
270
+ /** Override the session provider (tests, and the interactive login flow). */
271
+ session?: SessionProvider;
272
+ };
273
+ type CreatedServer = {
274
+ server: McpServer;
275
+ client: ProtectClient;
276
+ session: SessionProvider;
277
+ devices: DeviceCache;
278
+ };
279
+ declare const createServer: (opts: CreateServerOptions) => CreatedServer;
280
+ //#endregion
281
+ //#region src/client/session-store.d.ts
282
+ /**
283
+ * A console session: the bare cookie value plus the CSRF token that was current
284
+ * when it was issued. Both are needed on every request, and neither is derivable
285
+ * from the other, so they are stored and invalidated as one unit.
286
+ */
287
+ type PersistedSession = {
288
+ /** The `TOKEN=<jwt>` pair, attributes already stripped. */
289
+ cookie: string;
290
+ csrfToken: string;
291
+ /** Which console this belongs to, so a changed host does not reuse a stale session. */
292
+ baseUrl: string;
293
+ /** Which account it was issued to, for the same reason. */
294
+ username: string;
295
+ savedAt: string;
296
+ };
297
+ /** Load a persisted session, or undefined if none / unreadable / not JSON. */
298
+ declare const loadSession: (path: string) => Promise<PersistedSession | undefined>;
299
+ /** Persist a session with owner-only permissions. */
300
+ declare const saveSession: (path: string, session: PersistedSession) => Promise<void>;
301
+ /** Remove a persisted session. Absent is success — logout is idempotent. */
302
+ declare const clearSession: (path: string) => Promise<void>;
303
+ //#endregion
304
+ //#region src/client/errors.d.ts
305
+ /** A non-2xx answer from the console. */
306
+ declare class ProtectApiError extends Error {
307
+ readonly name = "ProtectApiError";
308
+ readonly status: number;
309
+ /** The request path, so an error names what failed without a stack trace. */
310
+ readonly path: string | undefined;
311
+ readonly errors: unknown;
312
+ constructor(message: string, opts: {
313
+ status: number;
314
+ path?: string | undefined;
315
+ errors?: unknown;
316
+ });
317
+ }
318
+ /** The console rejected the credentials, or 2FA is required and was not supplied. */
319
+ declare class ProtectAuthError extends Error {
320
+ readonly name = "ProtectAuthError";
321
+ /** True when the console asked for a 2FA code rather than refusing the password. */
322
+ readonly needsTwoFactor: boolean;
323
+ constructor(message: string, opts?: {
324
+ needsTwoFactor?: boolean;
325
+ });
326
+ }
327
+ /** Thrown when a write path is reached while UNIFI_PROTECT_ALLOW_WRITES is off. */
328
+ declare class WritesDisabledError extends Error {
329
+ readonly name = "WritesDisabledError";
330
+ constructor(what: string);
331
+ }
332
+ /** Thrown when the server is asked to reach a console it has no credentials for. */
333
+ declare class NotConfiguredError extends Error {
334
+ readonly name = "NotConfiguredError";
335
+ constructor();
336
+ }
337
+ //#endregion
338
+ //#region src/tools/index.d.ts
339
+ type ToolContext = {
340
+ config: Config;
341
+ /** Register the mutating tools too. Off by default — see UNIFI_PROTECT_ALLOW_WRITES. */
342
+ allowWrites: boolean;
343
+ session: SessionProvider;
344
+ devices: DeviceCache;
345
+ };
346
+ /**
347
+ * Register the UniFi Protect tools.
348
+ *
349
+ * unifi_protect_auth_status comes first and unconditionally, so a server with no
350
+ * console configured is still a useful one — it can say what to set — rather
351
+ * than a connection that closes with its own error message swallowed.
352
+ *
353
+ * Read tools are then always registered; the write tools only when
354
+ * `allowWrites` is set, so with the flag off they are not merely refused — they
355
+ * are absent from tools/list and cannot be called at all. A refusal still lets a
356
+ * model try, retry, and reason about how to get around it; a tool that does not
357
+ * exist ends the conversation.
358
+ */
359
+ declare const registerTools: (server: McpServer, client: ProtectClient, ctx: ToolContext) => void;
360
+ //#endregion
361
+ //#region src/tools/request.d.ts
362
+ /**
363
+ * Reject anything that is not a plain relative path. The server decides the
364
+ * host and the `/proxy/protect/api` prefix; letting a caller supply either
365
+ * would send the console session somewhere it does not belong.
366
+ */
367
+ declare const assertSafePath: (path: string) => void;
368
+ //#endregion
369
+ //#region src/tools/util.d.ts
370
+ /**
371
+ * Convert a time expression to milliseconds since the Unix epoch.
372
+ *
373
+ * This exists because the console's `/events` endpoint takes JavaScript
374
+ * millisecond timestamps — not ISO 8601, and NOT Unix seconds. A seconds value
375
+ * is not rejected: it is interpreted as a moment in January 1970, so the query
376
+ * succeeds and returns an empty list. That reads as "nothing happened last
377
+ * night", which is the most expensive possible failure for this server.
378
+ *
379
+ * Accepts ISO 8601, a relative expression like "2h ago" or "30m", the literal
380
+ * "now", or a raw millisecond number.
381
+ */
382
+ declare const toEpochMs: (value: string | number, now?: number) => number;
383
+ //#endregion
384
+ export { type BinaryResult, type Config, type CreateServerOptions, type CreatedServer, type DeviceCache, type FileConfig, LOGIN_PATH, type Logger, type NameIndex, NotConfiguredError, PRIVATE_API_PATH, type PersistedSession, ProtectApiError, ProtectAuthError, ProtectClient, type ProtectClientOptions, type Query, SERVER_NAME, SERVER_VERSION, type SessionHeaders, type SessionProvider, type SessionStatus, type ToolContext, UPDATES_WS_PATH, USER_AGENT, WritesDisabledError, assertSafePath, backoffMs, buildNameIndex, buildQuery, clearSession, createDeviceCache, createServer, createSessionProvider, expandTilde, isConfigured, isoTime, loadConfig, loadSession, normalizeBaseUrl, registerTools, resolveConfigPath, resolveSessionPath, retryAfterMs, saveSession, setupInstructions, staticSessionProvider, summarizeBootstrap, summarizeCamera, summarizeChime, summarizeEach, summarizeEvent, summarizeLight, summarizeLiveview, summarizeNvr, summarizeSensor, summarizeUser, summarizeViewer, toEpochMs };
385
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/config.ts","../src/client/auth.ts","../src/client/protect.ts","../src/client/shape.ts","../src/client/device-cache.ts","../src/server.ts","../src/client/session-store.ts","../src/client/errors.ts","../src/tools/index.ts","../src/tools/request.ts","../src/tools/util.ts"],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { A as saveSession, B as loadConfig, C as summarizeSensor, D as staticSessionProvider, E as createSessionProvider, F as LOGIN_PATH, H as resolveConfigPath, I as PRIVATE_API_PATH, L as UPDATES_WS_PATH, M as ProtectApiError, N as ProtectAuthError, O as clearSession, P as WritesDisabledError, R as expandTilde, S as summarizeNvr, T as summarizeViewer, U as resolveSessionPath, V as normalizeBaseUrl, W as setupInstructions, _ as summarizeChime, a as registerTools, b as summarizeLight, c as ProtectClient, d as retryAfterMs, f as createDeviceCache, g as summarizeCamera, h as summarizeBootstrap, i as createServer, j as NotConfiguredError, k as loadSession, l as backoffMs, m as isoTime, n as SERVER_VERSION, o as assertSafePath, p as buildNameIndex, r as USER_AGENT, s as toEpochMs, t as SERVER_NAME, u as buildQuery, v as summarizeEach, w as summarizeUser, x as summarizeLiveview, y as summarizeEvent, z as isConfigured } from "./server-iu_3JECB.js";
2
+ export { LOGIN_PATH, NotConfiguredError, PRIVATE_API_PATH, ProtectApiError, ProtectAuthError, ProtectClient, SERVER_NAME, SERVER_VERSION, UPDATES_WS_PATH, USER_AGENT, WritesDisabledError, assertSafePath, backoffMs, buildNameIndex, buildQuery, clearSession, createDeviceCache, createServer, createSessionProvider, expandTilde, isConfigured, isoTime, loadConfig, loadSession, normalizeBaseUrl, registerTools, resolveConfigPath, resolveSessionPath, retryAfterMs, saveSession, setupInstructions, staticSessionProvider, summarizeBootstrap, summarizeCamera, summarizeChime, summarizeEach, summarizeEvent, summarizeLight, summarizeLiveview, summarizeNvr, summarizeSensor, summarizeUser, summarizeViewer, toEpochMs };