unifi-mcp-worker 1.3.0 → 1.3.1

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.
package/README.md CHANGED
@@ -32,7 +32,7 @@ The Durable Object persists location registrations in SQLite and maintains live
32
32
  ### Install
33
33
 
34
34
  ```bash
35
- curl -fsSL https://raw.githubusercontent.com/sirkirby/unifi-mcp-worker/main/install.sh | bash
35
+ curl -fsSL https://raw.githubusercontent.com/sirkirby/unifi-mcp/main/apps/worker/install.sh | bash
36
36
  ```
37
37
 
38
38
  Or install the CLI directly:
@@ -119,13 +119,14 @@ curl -X POST https://your-worker.workers.dev/mcp \
119
119
 
120
120
  ### Built-in Meta-Tools
121
121
 
122
- The relay always exposes three meta-tools regardless of registration mode:
122
+ The relay always exposes these meta-tools regardless of registration mode:
123
123
 
124
124
  | Tool | Purpose |
125
125
  |------|---------|
126
126
  | `unifi_tool_index` | List all available UniFi tools with optional category or search filter |
127
127
  | `unifi_execute` | Execute any UniFi tool by name; use `__location` to target a specific site |
128
128
  | `unifi_batch` | Execute multiple UniFi tools in a single request |
129
+ | `unifi_location_timeline` | Query a unified event timeline across connected locations and products |
129
130
 
130
131
  ---
131
132
 
@@ -207,4 +208,4 @@ Read-only operations (tools with `readOnlyHint: true`) are automatically fanned
207
208
 
208
209
  ## Related
209
210
 
210
- - [unifi-mcp](https://github.com/sirkirby/unifi-mcp) — UniFi MCP server and `unifi-mcp-relay` client that connects to this relay worker
211
+ - [unifi-mcp](https://github.com/sirkirby/unifi-mcp) — source repository for this worker, the UniFi MCP servers, and the `unifi-mcp-relay` client
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unifi-mcp-worker",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "CLI to deploy and manage the UniFi MCP Cloudflare Worker relay",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,7 @@
32
32
  "license": "MIT",
33
33
  "repository": {
34
34
  "type": "git",
35
- "url": "https://github.com/sirkirby/unifi-mcp-worker.git"
35
+ "url": "https://github.com/sirkirby/unifi-mcp.git",
36
+ "directory": "apps/worker"
36
37
  }
37
38
  }
@@ -8,31 +8,32 @@
8
8
  "name": "unifi-mcp-worker-source",
9
9
  "version": "1.0.0",
10
10
  "devDependencies": {
11
- "@cloudflare/workers-types": "^4.20250313.0",
11
+ "@cloudflare/workers-types": "^4.20260515.1",
12
+ "@types/node": "^22.19.19",
12
13
  "typescript": "^5.7.0",
13
14
  "vitest": "^3.0.0",
14
- "wrangler": "^4.0.0"
15
+ "wrangler": "^4.92.0"
15
16
  }
16
17
  },
17
18
  "node_modules/@cloudflare/kv-asset-handler": {
18
- "version": "0.4.2",
19
- "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz",
20
- "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==",
19
+ "version": "0.5.0",
20
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz",
21
+ "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==",
21
22
  "dev": true,
22
23
  "license": "MIT OR Apache-2.0",
23
24
  "engines": {
24
- "node": ">=18.0.0"
25
+ "node": ">=22.0.0"
25
26
  }
26
27
  },
27
28
  "node_modules/@cloudflare/unenv-preset": {
28
- "version": "2.16.0",
29
- "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.0.tgz",
30
- "integrity": "sha512-8ovsRpwzPoEqPUzoErAYVv8l3FMZNeBVQfJTvtzP4AgLSRGZISRfuChFxHWUQd3n6cnrwkuTGxT+2cGo8EsyYg==",
29
+ "version": "2.16.1",
30
+ "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz",
31
+ "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==",
31
32
  "dev": true,
32
33
  "license": "MIT OR Apache-2.0",
33
34
  "peerDependencies": {
34
35
  "unenv": "2.0.0-rc.24",
35
- "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0"
36
+ "workerd": ">1.20260305.0 <2.0.0-0"
36
37
  },
37
38
  "peerDependenciesMeta": {
38
39
  "workerd": {
@@ -41,9 +42,9 @@
41
42
  }
42
43
  },
43
44
  "node_modules/@cloudflare/workerd-darwin-64": {
44
- "version": "1.20260317.1",
45
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260317.1.tgz",
46
- "integrity": "sha512-8hjh3sPMwY8M/zedq3/sXoA2Q4BedlGufn3KOOleIG+5a4ReQKLlUah140D7J6zlKmYZAFMJ4tWC7hCuI/s79g==",
45
+ "version": "1.20260515.1",
46
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260515.1.tgz",
47
+ "integrity": "sha512-Wtw44el2pNbzixvTkWdfeBDTrQwQbJRz7/JUvPKV27I0pQWXbhNJPpM8cstq/pbrU5AGcA/HjFH6yPMRTIRKig==",
47
48
  "cpu": [
48
49
  "x64"
49
50
  ],
@@ -58,9 +59,9 @@
58
59
  }
59
60
  },
60
61
  "node_modules/@cloudflare/workerd-darwin-arm64": {
61
- "version": "1.20260317.1",
62
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260317.1.tgz",
63
- "integrity": "sha512-M/MnNyvO5HMgoIdr3QHjdCj2T1ki9gt0vIUnxYxBu9ISXS/jgtMl6chUVPJ7zHYBn9MyYr8ByeN6frjYxj0MGg==",
62
+ "version": "1.20260515.1",
63
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260515.1.tgz",
64
+ "integrity": "sha512-X8EqkZej6FfmhF9AVAQ3FhyQRr9acS4RcDunMU2YiuxKHF1IU8zzH3vY30/POaG+rUu9vGDp/VgUl49VPenHJQ==",
64
65
  "cpu": [
65
66
  "arm64"
66
67
  ],
@@ -75,9 +76,9 @@
75
76
  }
76
77
  },
77
78
  "node_modules/@cloudflare/workerd-linux-64": {
78
- "version": "1.20260317.1",
79
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260317.1.tgz",
80
- "integrity": "sha512-1ltuEjkRcS3fsVF7CxsKlWiRmzq2ZqMfqDN0qUOgbUwkpXsLVJsXmoblaLf5OP00ELlcgF0QsN0p2xPEua4Uug==",
79
+ "version": "1.20260515.1",
80
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260515.1.tgz",
81
+ "integrity": "sha512-CDC89QxQ7Y7t7RG1Jd9vj/qolE1sQRkI2OSEuV5BMJi0vW/gV4OVG6xjpdK3b1OYnSWDzF7NpvlR5Yg86q7k4g==",
81
82
  "cpu": [
82
83
  "x64"
83
84
  ],
@@ -92,9 +93,9 @@
92
93
  }
93
94
  },
94
95
  "node_modules/@cloudflare/workerd-linux-arm64": {
95
- "version": "1.20260317.1",
96
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260317.1.tgz",
97
- "integrity": "sha512-3QrNnPF1xlaNwkHpasvRvAMidOvQs2NhXQmALJrEfpIJ/IDL2la8g499yXp3eqhG3hVMCB07XVY149GTs42Xtw==",
96
+ "version": "1.20260515.1",
97
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260515.1.tgz",
98
+ "integrity": "sha512-WxbW/PToYES4fvHXzsr/5qOiETQs/Z9iZ0mjSZAiEwq5cMLZemzGN0COx+uFb9OvQwzh6Pg159qPFnw3+i9FuA==",
98
99
  "cpu": [
99
100
  "arm64"
100
101
  ],
@@ -109,9 +110,9 @@
109
110
  }
110
111
  },
111
112
  "node_modules/@cloudflare/workerd-windows-64": {
112
- "version": "1.20260317.1",
113
- "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260317.1.tgz",
114
- "integrity": "sha512-MfZTz+7LfuIpMGTa3RLXHX8Z/pnycZLItn94WRdHr8LPVet+C5/1Nzei399w/jr3+kzT4pDKk26JF/tlI5elpQ==",
113
+ "version": "1.20260515.1",
114
+ "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260515.1.tgz",
115
+ "integrity": "sha512-WmV/iv+MHjYsvkcMVzpM2B5/mf06UUkdpVhZrtMfV9graWjBGPYFvE/eab8748RPVGKh1Xe1vXofLzDSwc08lA==",
115
116
  "cpu": [
116
117
  "x64"
117
118
  ],
@@ -126,9 +127,9 @@
126
127
  }
127
128
  },
128
129
  "node_modules/@cloudflare/workers-types": {
129
- "version": "4.20260317.1",
130
- "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260317.1.tgz",
131
- "integrity": "sha512-+G4eVwyCpm8Au1ex8vQBCuA9wnwqetz4tPNRoB/53qvktERWBRMQnrtvC1k584yRE3emMThtuY0gWshvSJ++PQ==",
130
+ "version": "4.20260515.1",
131
+ "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260515.1.tgz",
132
+ "integrity": "sha512-ruz+9tcG2iIKq5mXU2F00lL6KF5d4QfbAk7fNgvvqf5BelxDXaieyZmSnvA4sQBuemUstt4AEDN9CmJKmfCsDw==",
132
133
  "dev": true,
133
134
  "license": "MIT OR Apache-2.0"
134
135
  },
@@ -146,9 +147,9 @@
146
147
  }
147
148
  },
148
149
  "node_modules/@emnapi/runtime": {
149
- "version": "1.9.1",
150
- "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz",
151
- "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==",
150
+ "version": "1.10.0",
151
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
152
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
152
153
  "dev": true,
153
154
  "license": "MIT",
154
155
  "optional": true,
@@ -696,9 +697,6 @@
696
697
  "arm"
697
698
  ],
698
699
  "dev": true,
699
- "libc": [
700
- "glibc"
701
- ],
702
700
  "license": "LGPL-3.0-or-later",
703
701
  "optional": true,
704
702
  "os": [
@@ -716,9 +714,6 @@
716
714
  "arm64"
717
715
  ],
718
716
  "dev": true,
719
- "libc": [
720
- "glibc"
721
- ],
722
717
  "license": "LGPL-3.0-or-later",
723
718
  "optional": true,
724
719
  "os": [
@@ -736,9 +731,6 @@
736
731
  "ppc64"
737
732
  ],
738
733
  "dev": true,
739
- "libc": [
740
- "glibc"
741
- ],
742
734
  "license": "LGPL-3.0-or-later",
743
735
  "optional": true,
744
736
  "os": [
@@ -756,9 +748,6 @@
756
748
  "riscv64"
757
749
  ],
758
750
  "dev": true,
759
- "libc": [
760
- "glibc"
761
- ],
762
751
  "license": "LGPL-3.0-or-later",
763
752
  "optional": true,
764
753
  "os": [
@@ -776,9 +765,6 @@
776
765
  "s390x"
777
766
  ],
778
767
  "dev": true,
779
- "libc": [
780
- "glibc"
781
- ],
782
768
  "license": "LGPL-3.0-or-later",
783
769
  "optional": true,
784
770
  "os": [
@@ -796,9 +782,6 @@
796
782
  "x64"
797
783
  ],
798
784
  "dev": true,
799
- "libc": [
800
- "glibc"
801
- ],
802
785
  "license": "LGPL-3.0-or-later",
803
786
  "optional": true,
804
787
  "os": [
@@ -816,9 +799,6 @@
816
799
  "arm64"
817
800
  ],
818
801
  "dev": true,
819
- "libc": [
820
- "musl"
821
- ],
822
802
  "license": "LGPL-3.0-or-later",
823
803
  "optional": true,
824
804
  "os": [
@@ -836,9 +816,6 @@
836
816
  "x64"
837
817
  ],
838
818
  "dev": true,
839
- "libc": [
840
- "musl"
841
- ],
842
819
  "license": "LGPL-3.0-or-later",
843
820
  "optional": true,
844
821
  "os": [
@@ -856,9 +833,6 @@
856
833
  "arm"
857
834
  ],
858
835
  "dev": true,
859
- "libc": [
860
- "glibc"
861
- ],
862
836
  "license": "Apache-2.0",
863
837
  "optional": true,
864
838
  "os": [
@@ -882,9 +856,6 @@
882
856
  "arm64"
883
857
  ],
884
858
  "dev": true,
885
- "libc": [
886
- "glibc"
887
- ],
888
859
  "license": "Apache-2.0",
889
860
  "optional": true,
890
861
  "os": [
@@ -908,9 +879,6 @@
908
879
  "ppc64"
909
880
  ],
910
881
  "dev": true,
911
- "libc": [
912
- "glibc"
913
- ],
914
882
  "license": "Apache-2.0",
915
883
  "optional": true,
916
884
  "os": [
@@ -934,9 +902,6 @@
934
902
  "riscv64"
935
903
  ],
936
904
  "dev": true,
937
- "libc": [
938
- "glibc"
939
- ],
940
905
  "license": "Apache-2.0",
941
906
  "optional": true,
942
907
  "os": [
@@ -960,9 +925,6 @@
960
925
  "s390x"
961
926
  ],
962
927
  "dev": true,
963
- "libc": [
964
- "glibc"
965
- ],
966
928
  "license": "Apache-2.0",
967
929
  "optional": true,
968
930
  "os": [
@@ -986,9 +948,6 @@
986
948
  "x64"
987
949
  ],
988
950
  "dev": true,
989
- "libc": [
990
- "glibc"
991
- ],
992
951
  "license": "Apache-2.0",
993
952
  "optional": true,
994
953
  "os": [
@@ -1012,9 +971,6 @@
1012
971
  "arm64"
1013
972
  ],
1014
973
  "dev": true,
1015
- "libc": [
1016
- "musl"
1017
- ],
1018
974
  "license": "Apache-2.0",
1019
975
  "optional": true,
1020
976
  "os": [
@@ -1038,9 +994,6 @@
1038
994
  "x64"
1039
995
  ],
1040
996
  "dev": true,
1041
- "libc": [
1042
- "musl"
1043
- ],
1044
997
  "license": "Apache-2.0",
1045
998
  "optional": true,
1046
999
  "os": [
@@ -1285,9 +1238,6 @@
1285
1238
  "arm"
1286
1239
  ],
1287
1240
  "dev": true,
1288
- "libc": [
1289
- "glibc"
1290
- ],
1291
1241
  "license": "MIT",
1292
1242
  "optional": true,
1293
1243
  "os": [
@@ -1302,9 +1252,6 @@
1302
1252
  "arm"
1303
1253
  ],
1304
1254
  "dev": true,
1305
- "libc": [
1306
- "musl"
1307
- ],
1308
1255
  "license": "MIT",
1309
1256
  "optional": true,
1310
1257
  "os": [
@@ -1319,9 +1266,6 @@
1319
1266
  "arm64"
1320
1267
  ],
1321
1268
  "dev": true,
1322
- "libc": [
1323
- "glibc"
1324
- ],
1325
1269
  "license": "MIT",
1326
1270
  "optional": true,
1327
1271
  "os": [
@@ -1336,9 +1280,6 @@
1336
1280
  "arm64"
1337
1281
  ],
1338
1282
  "dev": true,
1339
- "libc": [
1340
- "musl"
1341
- ],
1342
1283
  "license": "MIT",
1343
1284
  "optional": true,
1344
1285
  "os": [
@@ -1353,9 +1294,6 @@
1353
1294
  "loong64"
1354
1295
  ],
1355
1296
  "dev": true,
1356
- "libc": [
1357
- "glibc"
1358
- ],
1359
1297
  "license": "MIT",
1360
1298
  "optional": true,
1361
1299
  "os": [
@@ -1370,9 +1308,6 @@
1370
1308
  "loong64"
1371
1309
  ],
1372
1310
  "dev": true,
1373
- "libc": [
1374
- "musl"
1375
- ],
1376
1311
  "license": "MIT",
1377
1312
  "optional": true,
1378
1313
  "os": [
@@ -1387,9 +1322,6 @@
1387
1322
  "ppc64"
1388
1323
  ],
1389
1324
  "dev": true,
1390
- "libc": [
1391
- "glibc"
1392
- ],
1393
1325
  "license": "MIT",
1394
1326
  "optional": true,
1395
1327
  "os": [
@@ -1404,9 +1336,6 @@
1404
1336
  "ppc64"
1405
1337
  ],
1406
1338
  "dev": true,
1407
- "libc": [
1408
- "musl"
1409
- ],
1410
1339
  "license": "MIT",
1411
1340
  "optional": true,
1412
1341
  "os": [
@@ -1421,9 +1350,6 @@
1421
1350
  "riscv64"
1422
1351
  ],
1423
1352
  "dev": true,
1424
- "libc": [
1425
- "glibc"
1426
- ],
1427
1353
  "license": "MIT",
1428
1354
  "optional": true,
1429
1355
  "os": [
@@ -1438,9 +1364,6 @@
1438
1364
  "riscv64"
1439
1365
  ],
1440
1366
  "dev": true,
1441
- "libc": [
1442
- "musl"
1443
- ],
1444
1367
  "license": "MIT",
1445
1368
  "optional": true,
1446
1369
  "os": [
@@ -1455,9 +1378,6 @@
1455
1378
  "s390x"
1456
1379
  ],
1457
1380
  "dev": true,
1458
- "libc": [
1459
- "glibc"
1460
- ],
1461
1381
  "license": "MIT",
1462
1382
  "optional": true,
1463
1383
  "os": [
@@ -1472,9 +1392,6 @@
1472
1392
  "x64"
1473
1393
  ],
1474
1394
  "dev": true,
1475
- "libc": [
1476
- "glibc"
1477
- ],
1478
1395
  "license": "MIT",
1479
1396
  "optional": true,
1480
1397
  "os": [
@@ -1489,9 +1406,6 @@
1489
1406
  "x64"
1490
1407
  ],
1491
1408
  "dev": true,
1492
- "libc": [
1493
- "musl"
1494
- ],
1495
1409
  "license": "MIT",
1496
1410
  "optional": true,
1497
1411
  "os": [
@@ -1627,6 +1541,16 @@
1627
1541
  "dev": true,
1628
1542
  "license": "MIT"
1629
1543
  },
1544
+ "node_modules/@types/node": {
1545
+ "version": "22.19.19",
1546
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz",
1547
+ "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==",
1548
+ "dev": true,
1549
+ "license": "MIT",
1550
+ "dependencies": {
1551
+ "undici-types": "~6.21.0"
1552
+ }
1553
+ },
1630
1554
  "node_modules/@vitest/expect": {
1631
1555
  "version": "3.2.4",
1632
1556
  "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
@@ -1995,16 +1919,16 @@
1995
1919
  }
1996
1920
  },
1997
1921
  "node_modules/miniflare": {
1998
- "version": "4.20260317.1",
1999
- "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260317.1.tgz",
2000
- "integrity": "sha512-A3csI1HXEIfqe3oscgpoRMHdYlkReQKPH/g5JE53vFSjoM6YIAOGAzyDNeYffwd9oQkPWDj9xER8+vpxei8klA==",
1922
+ "version": "4.20260515.0",
1923
+ "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260515.0.tgz",
1924
+ "integrity": "sha512-2j0oQWizk1Eu4Cm8tDX7Z+Nsjd0nebIj1TQcQ+Oy1QKeo0Ay9+bdn8wfLAtOj9znDCybDCUlnS1+nYvKXEdfNg==",
2001
1925
  "dev": true,
2002
1926
  "license": "MIT",
2003
1927
  "dependencies": {
2004
1928
  "@cspotcode/source-map-support": "0.8.1",
2005
1929
  "sharp": "^0.34.5",
2006
- "undici": "7.24.4",
2007
- "workerd": "1.20260317.1",
1930
+ "undici": "7.24.8",
1931
+ "workerd": "1.20260515.1",
2008
1932
  "ws": "8.18.0",
2009
1933
  "youch": "4.1.0-beta.10"
2010
1934
  },
@@ -2012,7 +1936,7 @@
2012
1936
  "miniflare": "bootstrap.js"
2013
1937
  },
2014
1938
  "engines": {
2015
- "node": ">=18.0.0"
1939
+ "node": ">=22.0.0"
2016
1940
  }
2017
1941
  },
2018
1942
  "node_modules/ms": {
@@ -2160,9 +2084,9 @@
2160
2084
  }
2161
2085
  },
2162
2086
  "node_modules/semver": {
2163
- "version": "7.7.4",
2164
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
2165
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
2087
+ "version": "7.8.0",
2088
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
2089
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
2166
2090
  "dev": true,
2167
2091
  "license": "ISC",
2168
2092
  "bin": {
@@ -2358,15 +2282,22 @@
2358
2282
  }
2359
2283
  },
2360
2284
  "node_modules/undici": {
2361
- "version": "7.24.4",
2362
- "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz",
2363
- "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==",
2285
+ "version": "7.24.8",
2286
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.8.tgz",
2287
+ "integrity": "sha512-6KQ/+QxK49Z/p3HO6E5ZCZWNnCasyZLa5ExaVYyvPxUwKtbCPMKELJOqh7EqOle0t9cH/7d2TaaTRRa6Nhs4YQ==",
2364
2288
  "dev": true,
2365
2289
  "license": "MIT",
2366
2290
  "engines": {
2367
2291
  "node": ">=20.18.1"
2368
2292
  }
2369
2293
  },
2294
+ "node_modules/undici-types": {
2295
+ "version": "6.21.0",
2296
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
2297
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
2298
+ "dev": true,
2299
+ "license": "MIT"
2300
+ },
2370
2301
  "node_modules/unenv": {
2371
2302
  "version": "2.0.0-rc.24",
2372
2303
  "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
@@ -2566,9 +2497,9 @@
2566
2497
  }
2567
2498
  },
2568
2499
  "node_modules/workerd": {
2569
- "version": "1.20260317.1",
2570
- "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260317.1.tgz",
2571
- "integrity": "sha512-ZuEq1OdrJBS+NV+L5HMYPCzVn49a2O60slQiiLpG44jqtlOo+S167fWC76kEXteXLLLydeuRrluRel7WdOUa4g==",
2500
+ "version": "1.20260515.1",
2501
+ "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260515.1.tgz",
2502
+ "integrity": "sha512-MjKOJLcvU45xXedQowvuiHtJTxu4WTHYQeIlF7YmjuqhiI6dImTFxWCEoRQHiskztxuVSNEmdO7/0UfDu6OMnQ==",
2572
2503
  "dev": true,
2573
2504
  "hasInstallScript": true,
2574
2505
  "license": "Apache-2.0",
@@ -2579,41 +2510,41 @@
2579
2510
  "node": ">=16"
2580
2511
  },
2581
2512
  "optionalDependencies": {
2582
- "@cloudflare/workerd-darwin-64": "1.20260317.1",
2583
- "@cloudflare/workerd-darwin-arm64": "1.20260317.1",
2584
- "@cloudflare/workerd-linux-64": "1.20260317.1",
2585
- "@cloudflare/workerd-linux-arm64": "1.20260317.1",
2586
- "@cloudflare/workerd-windows-64": "1.20260317.1"
2513
+ "@cloudflare/workerd-darwin-64": "1.20260515.1",
2514
+ "@cloudflare/workerd-darwin-arm64": "1.20260515.1",
2515
+ "@cloudflare/workerd-linux-64": "1.20260515.1",
2516
+ "@cloudflare/workerd-linux-arm64": "1.20260515.1",
2517
+ "@cloudflare/workerd-windows-64": "1.20260515.1"
2587
2518
  }
2588
2519
  },
2589
2520
  "node_modules/wrangler": {
2590
- "version": "4.76.0",
2591
- "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.76.0.tgz",
2592
- "integrity": "sha512-Wan+CU5a0tu4HIxGOrzjNbkmxCT27HUmzrMj6kc7aoAnjSLv50Ggcn2Ant7wNQrD6xW3g31phKupZJgTZ8wZfQ==",
2521
+ "version": "4.92.0",
2522
+ "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.92.0.tgz",
2523
+ "integrity": "sha512-/DKpQHPxkuZbQsO9dFW2700VTD/4DSZMHjy92fO/frNoDRi/zQsFCAd2ONCV6TGqcUoXcP3D8Bo2gj/L4M0qQQ==",
2593
2524
  "dev": true,
2594
2525
  "license": "MIT OR Apache-2.0",
2595
2526
  "dependencies": {
2596
- "@cloudflare/kv-asset-handler": "0.4.2",
2597
- "@cloudflare/unenv-preset": "2.16.0",
2527
+ "@cloudflare/kv-asset-handler": "0.5.0",
2528
+ "@cloudflare/unenv-preset": "2.16.1",
2598
2529
  "blake3-wasm": "2.1.5",
2599
2530
  "esbuild": "0.27.3",
2600
- "miniflare": "4.20260317.1",
2531
+ "miniflare": "4.20260515.0",
2601
2532
  "path-to-regexp": "6.3.0",
2602
2533
  "unenv": "2.0.0-rc.24",
2603
- "workerd": "1.20260317.1"
2534
+ "workerd": "1.20260515.1"
2604
2535
  },
2605
2536
  "bin": {
2606
2537
  "wrangler": "bin/wrangler.js",
2607
2538
  "wrangler2": "bin/wrangler.js"
2608
2539
  },
2609
2540
  "engines": {
2610
- "node": ">=20.0.0"
2541
+ "node": ">=22.0.0"
2611
2542
  },
2612
2543
  "optionalDependencies": {
2613
2544
  "fsevents": "~2.3.2"
2614
2545
  },
2615
2546
  "peerDependencies": {
2616
- "@cloudflare/workers-types": "^4.20260317.1"
2547
+ "@cloudflare/workers-types": "^4.20260515.1"
2617
2548
  },
2618
2549
  "peerDependenciesMeta": {
2619
2550
  "@cloudflare/workers-types": {
@@ -10,9 +10,10 @@
10
10
  "typecheck": "tsc --noEmit"
11
11
  },
12
12
  "devDependencies": {
13
- "@cloudflare/workers-types": "^4.20250313.0",
13
+ "@cloudflare/workers-types": "^4.20260515.1",
14
+ "@types/node": "^22.19.19",
14
15
  "typescript": "^5.7.0",
15
16
  "vitest": "^3.0.0",
16
- "wrangler": "^4.0.0"
17
+ "wrangler": "^4.92.0"
17
18
  }
18
19
  }
@@ -1,5 +1,6 @@
1
1
  // src/mcp-handler.ts
2
2
  import type { JsonRpcRequest, JsonRpcResponse, ToolInfo, AggregatedResponse } from "./types";
3
+ import { PROJECT_WEBSITE_URL, RELAY_SERVER_ICONS } from "./types";
3
4
 
4
5
  /** Interface that the Durable Object will implement */
5
6
  export interface RelayStub {
@@ -26,7 +27,12 @@ export async function handleMcpRequest(
26
27
  if (method === "initialize") {
27
28
  return jsonRpcResult(id, {
28
29
  protocolVersion: "2025-03-26",
29
- serverInfo: { name: "unifi-mcp-relay", version: "1.0.0" },
30
+ serverInfo: {
31
+ name: "unifi-mcp-relay",
32
+ version: "1.0.0",
33
+ websiteUrl: PROJECT_WEBSITE_URL,
34
+ icons: RELAY_SERVER_ICONS,
35
+ },
30
36
  capabilities: { tools: {} },
31
37
  });
32
38
  }
@@ -3,6 +3,7 @@ import { DurableObject } from "cloudflare:workers";
3
3
  import type { RelayStub } from "./mcp-handler";
4
4
  import { handleMcpRequest } from "./mcp-handler";
5
5
  import { hashToken, generateToken, extractBearerToken } from "./auth";
6
+ import { toolInputSchema, toolServerOrigin } from "./tool-info";
6
7
  import type {
7
8
  Env,
8
9
  ToolInfo,
@@ -29,6 +30,7 @@ const MAX_LOCATION_NAME_LENGTH = 128;
29
30
 
30
31
  const META_TOOL_INDEX: ToolInfo = {
31
32
  name: "unifi_tool_index",
33
+ title: "UniFi Tool Index",
32
34
  description:
33
35
  "Discover available UniFi tools. Returns names and descriptions by default. " +
34
36
  "Use 'category' to filter by area (e.g. clients, firewall, devices), " +
@@ -64,6 +66,7 @@ const META_TOOL_INDEX: ToolInfo = {
64
66
 
65
67
  const META_TOOL_EXECUTE: ToolInfo = {
66
68
  name: "unifi_execute",
69
+ title: "UniFi Execute",
67
70
  description:
68
71
  "Execute a UniFi tool by name. Use unifi_tool_index to discover available tools first. " +
69
72
  "Pass the tool name and its arguments.",
@@ -93,6 +96,7 @@ const META_TOOL_EXECUTE: ToolInfo = {
93
96
 
94
97
  const META_TOOL_BATCH: ToolInfo = {
95
98
  name: "unifi_batch",
99
+ title: "UniFi Batch",
96
100
  description:
97
101
  "Execute multiple UniFi tools in a single request. Each call is an object with " +
98
102
  "'tool' and 'arguments'. Results are returned in order.",
@@ -125,6 +129,7 @@ const META_TOOL_BATCH: ToolInfo = {
125
129
 
126
130
  const META_TOOL_LOCATION_TIMELINE: ToolInfo = {
127
131
  name: "unifi_location_timeline",
132
+ title: "UniFi Location Timeline",
128
133
  description:
129
134
  "Query events across all connected UniFi products (Network, Protect, Access) " +
130
135
  "and return a unified, time-sorted timeline. Correlates network events, camera " +
@@ -204,6 +209,7 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
204
209
  CREATE TABLE IF NOT EXISTS location_tools (
205
210
  location_id TEXT NOT NULL,
206
211
  tool_name TEXT NOT NULL,
212
+ title TEXT,
207
213
  description TEXT NOT NULL DEFAULT '',
208
214
  input_schema TEXT,
209
215
  annotations TEXT,
@@ -212,6 +218,15 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
212
218
  FOREIGN KEY (location_id) REFERENCES locations(location_id)
213
219
  );
214
220
  `);
221
+ this.ensureLocationToolsTitleColumn();
222
+ }
223
+
224
+ private ensureLocationToolsTitleColumn(): void {
225
+ const columns = this.ctx.storage.sql.exec(`PRAGMA table_info(location_tools)`).toArray();
226
+ const hasTitle = columns.some((column) => column.name === "title");
227
+ if (!hasTitle) {
228
+ this.ctx.storage.sql.exec(`ALTER TABLE location_tools ADD COLUMN title TEXT`);
229
+ }
215
230
  }
216
231
 
217
232
  // -------------------------------------------------------------------------
@@ -237,7 +252,7 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
237
252
 
238
253
  // Load all tools grouped by location
239
254
  const rows = this.ctx.storage.sql.exec(
240
- `SELECT lt.location_id, lt.tool_name, lt.description, lt.input_schema, lt.annotations, lt.server_origin
255
+ `SELECT lt.location_id, lt.tool_name, lt.title, lt.description, lt.input_schema, lt.annotations, lt.server_origin
241
256
  FROM location_tools lt
242
257
  JOIN locations l ON lt.location_id = l.location_id`,
243
258
  ).toArray();
@@ -249,6 +264,9 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
249
264
  description: (row.description as string) || "",
250
265
  };
251
266
 
267
+ if (row.title) {
268
+ tool.title = row.title as string;
269
+ }
252
270
  if (row.input_schema) {
253
271
  try {
254
272
  tool.inputSchema = JSON.parse(row.input_schema as string);
@@ -594,14 +612,15 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
594
612
 
595
613
  for (const tool of msg.tools) {
596
614
  this.ctx.storage.sql.exec(
597
- `INSERT INTO location_tools (location_id, tool_name, description, input_schema, annotations, server_origin)
598
- VALUES (?, ?, ?, ?, ?, ?)`,
615
+ `INSERT INTO location_tools (location_id, tool_name, title, description, input_schema, annotations, server_origin)
616
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
599
617
  locationId,
600
618
  tool.name,
619
+ tool.title || null,
601
620
  tool.description || "",
602
- tool.inputSchema ? JSON.stringify(tool.inputSchema) : null,
621
+ toolInputSchema(tool) ? JSON.stringify(toolInputSchema(tool)) : null,
603
622
  tool.annotations ? JSON.stringify(tool.annotations) : null,
604
- tool.serverOrigin || null,
623
+ toolServerOrigin(tool) || null,
605
624
  );
606
625
  }
607
626
 
@@ -670,14 +689,15 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
670
689
 
671
690
  for (const tool of msg.tools) {
672
691
  this.ctx.storage.sql.exec(
673
- `INSERT INTO location_tools (location_id, tool_name, description, input_schema, annotations, server_origin)
674
- VALUES (?, ?, ?, ?, ?, ?)`,
692
+ `INSERT INTO location_tools (location_id, tool_name, title, description, input_schema, annotations, server_origin)
693
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
675
694
  locationId,
676
695
  tool.name,
696
+ tool.title || null,
677
697
  tool.description || "",
678
- tool.inputSchema ? JSON.stringify(tool.inputSchema) : null,
698
+ toolInputSchema(tool) ? JSON.stringify(toolInputSchema(tool)) : null,
679
699
  tool.annotations ? JSON.stringify(tool.annotations) : null,
680
- tool.serverOrigin || null,
700
+ toolServerOrigin(tool) || null,
681
701
  );
682
702
  }
683
703
 
@@ -757,6 +777,7 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
757
777
  // Build tool list with location metadata
758
778
  const toolEntries: Array<{
759
779
  name: string;
780
+ title?: string;
760
781
  description: string;
761
782
  locations: string[];
762
783
  annotations?: ToolAnnotations;
@@ -774,6 +795,9 @@ export class RelayObject extends DurableObject<Env> implements RelayStub {
774
795
  locations: this.toolToLocations.get(tool.name) || [locationId],
775
796
  annotations: tool.annotations,
776
797
  };
798
+ if (tool.title) {
799
+ entry.title = tool.title;
800
+ }
777
801
  if (includeSchemas && tool.inputSchema) {
778
802
  entry.inputSchema = tool.inputSchema;
779
803
  }
@@ -0,0 +1,9 @@
1
+ import type { ToolInfo } from "./types";
2
+
3
+ export function toolInputSchema(tool: ToolInfo): Record<string, unknown> | undefined {
4
+ return tool.inputSchema ?? tool.input_schema;
5
+ }
6
+
7
+ export function toolServerOrigin(tool: ToolInfo): string | undefined {
8
+ return tool.serverOrigin ?? tool.server_origin;
9
+ }
@@ -9,6 +9,24 @@ export const PROTOCOL_VERSION = 1;
9
9
  export const TOOL_CALL_TIMEOUT_MS = 30_000;
10
10
  export const HEARTBEAT_INTERVAL_MS = 30_000;
11
11
  export const HEARTBEAT_ACK_TIMEOUT_MS = 10_000;
12
+ export const PROJECT_WEBSITE_URL = "https://github.com/sirkirby/unifi-mcp";
13
+
14
+ export interface IconInfo {
15
+ src: string;
16
+ mimeType?: string;
17
+ sizes?: string[];
18
+ }
19
+
20
+ const RELAY_ICON_SRC =
21
+ "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20192%20192%22%3E%3Crect%20width%3D%22192%22%20height%3D%22192%22%20rx%3D%2238%22%20fill%3D%22%23111827%22%2F%3E%3Cpath%20d%3D%22M54%2096h84M96%2054v84%22%20stroke%3D%22%2338bdf8%22%20stroke-width%3D%2214%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2254%22%20cy%3D%2296%22%20r%3D%2218%22%20fill%3D%22%2322c55e%22%2F%3E%3Ccircle%20cx%3D%22138%22%20cy%3D%2296%22%20r%3D%2218%22%20fill%3D%22%2322c55e%22%2F%3E%3Ccircle%20cx%3D%2296%22%20cy%3D%2254%22%20r%3D%2218%22%20fill%3D%22%2322c55e%22%2F%3E%3Ccircle%20cx%3D%2296%22%20cy%3D%22138%22%20r%3D%2218%22%20fill%3D%22%2322c55e%22%2F%3E%3C%2Fsvg%3E";
22
+
23
+ export const RELAY_SERVER_ICONS: IconInfo[] = [
24
+ {
25
+ src: RELAY_ICON_SRC,
26
+ mimeType: "image/svg+xml",
27
+ sizes: ["192x192"],
28
+ },
29
+ ];
12
30
 
13
31
  // ---------------------------------------------------------------------------
14
32
  // Environment (Cloudflare bindings)
@@ -34,10 +52,13 @@ export interface ToolAnnotations {
34
52
 
35
53
  export interface ToolInfo {
36
54
  name: string;
55
+ title?: string;
37
56
  description: string;
38
57
  inputSchema?: Record<string, unknown>;
58
+ input_schema?: Record<string, unknown>;
39
59
  annotations?: ToolAnnotations;
40
60
  serverOrigin?: string;
61
+ server_origin?: string;
41
62
  }
42
63
 
43
64
  // ---------------------------------------------------------------------------