@topolo/mcp 0.4.7 → 0.4.9
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/dist/dispatch.js +17 -0
- package/dist/index.js +187 -136
- package/package.json +13 -13
package/dist/dispatch.js
CHANGED
|
@@ -91,6 +91,8 @@ var TOOLS = [
|
|
|
91
91
|
effectiveUrl: resolveCatalogServiceUrl(entry, { serviceKey: id }),
|
|
92
92
|
surfaceKind: entry.surfaceKind,
|
|
93
93
|
launchable: entry.launchable,
|
|
94
|
+
apiKeyResource: entry.apiKeyResource,
|
|
95
|
+
apiKeyResources: [...entry.apiKeyResources],
|
|
94
96
|
permissions: [...entry.permissions]
|
|
95
97
|
};
|
|
96
98
|
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
@@ -284,6 +286,14 @@ var TOOLS = [
|
|
|
284
286
|
additionalProperties: { type: "string" },
|
|
285
287
|
description: "Query string parameters as string values."
|
|
286
288
|
},
|
|
289
|
+
resourceType: {
|
|
290
|
+
type: "string",
|
|
291
|
+
description: "Optional workspace resource alias from topolo_list_services apiKeyResources. Aliases are app-defined, e.g. brand, mailbox, venue, merchant, or any other cataloged alias."
|
|
292
|
+
},
|
|
293
|
+
resourceId: {
|
|
294
|
+
type: "string",
|
|
295
|
+
description: "Resource id for resourceType. Required when resourceType is provided."
|
|
296
|
+
},
|
|
287
297
|
confirm: {
|
|
288
298
|
type: "boolean",
|
|
289
299
|
description: "Required for non-GET methods. Explicit human-in-the-loop acknowledgement for writes."
|
|
@@ -310,12 +320,19 @@ var TOOLS = [
|
|
|
310
320
|
const normalisedQuery = query && typeof query === "object" && !Array.isArray(query) ? Object.fromEntries(
|
|
311
321
|
Object.entries(query).map(([k, v]) => [k, String(v)])
|
|
312
322
|
) : void 0;
|
|
323
|
+
const resourceType = typeof args["resourceType"] === "string" ? args["resourceType"].trim() : "";
|
|
324
|
+
const resourceId = typeof args["resourceId"] === "string" ? args["resourceId"].trim() : "";
|
|
325
|
+
if (resourceType && !resourceId || !resourceType && resourceId) {
|
|
326
|
+
throw new Error("resourceType and resourceId must be provided together.");
|
|
327
|
+
}
|
|
328
|
+
const resource = resourceType && resourceId ? { resourceType, resourceId } : void 0;
|
|
313
329
|
return topolo.client.request({
|
|
314
330
|
service: service.trim(),
|
|
315
331
|
method,
|
|
316
332
|
path,
|
|
317
333
|
body: args["body"],
|
|
318
334
|
...normalisedQuery ? { query: normalisedQuery } : {},
|
|
335
|
+
...resource ? { resource } : {},
|
|
319
336
|
confirm: Boolean(args["confirm"])
|
|
320
337
|
});
|
|
321
338
|
}
|
package/dist/index.js
CHANGED
|
@@ -59,54 +59,53 @@ var TopoloHttpError = class extends TopoloSdkError {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
var SERVICES = {
|
|
62
|
-
agent: "https://agent
|
|
62
|
+
agent: "https://agent.topolo.app",
|
|
63
63
|
auth: "https://auth.topolo.app",
|
|
64
64
|
backup: "https://backup.topolo.app",
|
|
65
65
|
books: "https://books.topolo.app",
|
|
66
66
|
bugfix: "https://bugfix.topolo.app",
|
|
67
|
-
bytes: "https://bytes
|
|
67
|
+
bytes: "https://bytes.topolo.app",
|
|
68
68
|
calendar: "https://calendar.topolo.app",
|
|
69
69
|
capacity: "https://capacity.topolo.app",
|
|
70
70
|
chat: "https://chat.topolo.app",
|
|
71
|
-
commerce: "https://commerce
|
|
71
|
+
commerce: "https://commerce.topolo.app",
|
|
72
72
|
compose: "https://compose.topolo.app",
|
|
73
73
|
consent: "https://consent.topolo.app",
|
|
74
|
-
crm: "https://crm
|
|
74
|
+
crm: "https://crm.topolo.app",
|
|
75
75
|
developers: "https://developers.topolo.app",
|
|
76
76
|
director: "https://director.topolo.app",
|
|
77
|
-
feed: "https://feed
|
|
77
|
+
feed: "https://feed.topolo.app",
|
|
78
78
|
flow: "https://flow.topolo.app",
|
|
79
|
-
forecast: "https://forecast
|
|
79
|
+
forecast: "https://forecast.topolo.app",
|
|
80
80
|
forms: "https://forms.topolo.app",
|
|
81
81
|
home: "https://home.topolo.app",
|
|
82
82
|
insights: "https://insights.topolo.app",
|
|
83
83
|
inventory: "https://inventory.topolo.app",
|
|
84
|
-
learn: "https://learn
|
|
84
|
+
learn: "https://learn.topolo.app",
|
|
85
85
|
localize: "https://localize.topolo.app",
|
|
86
|
-
mail: "https://mail
|
|
87
|
-
mdm: "https://mdm
|
|
86
|
+
mail: "https://mail.topolo.app",
|
|
87
|
+
mdm: "https://mdm.topolo.app",
|
|
88
88
|
messages: "https://messages.topolo.app",
|
|
89
|
-
nexus: "https://nexus
|
|
89
|
+
nexus: "https://nexus.topolo.app",
|
|
90
90
|
notify: "https://notify.topolo.app",
|
|
91
91
|
observability_watch: "https://observability-watch.topolo.app",
|
|
92
|
-
one: "https://
|
|
92
|
+
one: "https://www.topolo.app",
|
|
93
93
|
p2p: "https://p2p.topolo.app",
|
|
94
94
|
pay: "https://pay.topolo.app",
|
|
95
95
|
people: "https://people.topolo.app",
|
|
96
|
-
pulse: "https://pulse.topolo.app",
|
|
97
96
|
"quro.api": "https://api.ol0.me",
|
|
98
97
|
"quro.redirect": "https://ol0.me",
|
|
99
|
-
roadmapper: "https://roadmapper
|
|
98
|
+
roadmapper: "https://roadmapper.topolo.app",
|
|
100
99
|
sign: "https://sign.topolo.app",
|
|
101
|
-
social_studio: "https://studio
|
|
102
|
-
socialize: "https://socialize
|
|
100
|
+
social_studio: "https://studio.topolo.app",
|
|
101
|
+
socialize: "https://socialize.topolo.app",
|
|
103
102
|
spaces: "https://spaces.topolo.app",
|
|
104
103
|
status: "https://status.topolo.app",
|
|
105
104
|
success: "https://success.topolo.app",
|
|
106
105
|
support: "https://support.topolo.app",
|
|
107
106
|
survey: "https://survey.topolo.app",
|
|
108
107
|
voice: "https://voice.topolo.app",
|
|
109
|
-
web: "https://web
|
|
108
|
+
web: "https://web.topolo.app"
|
|
110
109
|
};
|
|
111
110
|
var APPLICATIONS = {
|
|
112
111
|
"admin": {
|
|
@@ -155,17 +154,15 @@ var APPLICATIONS = {
|
|
|
155
154
|
"agent.topolo.app"
|
|
156
155
|
],
|
|
157
156
|
"routes": [],
|
|
158
|
-
"serviceId":
|
|
157
|
+
"serviceId": "agent"
|
|
159
158
|
},
|
|
160
159
|
{
|
|
161
160
|
"name": "topolo-agent-api",
|
|
162
161
|
"kind": "worker",
|
|
163
|
-
"apiUrl":
|
|
164
|
-
"domains": [
|
|
165
|
-
"agent-api.topolo.app"
|
|
166
|
-
],
|
|
162
|
+
"apiUrl": null,
|
|
163
|
+
"domains": [],
|
|
167
164
|
"routes": [],
|
|
168
|
-
"serviceId":
|
|
165
|
+
"serviceId": null
|
|
169
166
|
}
|
|
170
167
|
]
|
|
171
168
|
},
|
|
@@ -285,17 +282,15 @@ var APPLICATIONS = {
|
|
|
285
282
|
"bytes.topolo.app"
|
|
286
283
|
],
|
|
287
284
|
"routes": [],
|
|
288
|
-
"serviceId":
|
|
285
|
+
"serviceId": "bytes"
|
|
289
286
|
},
|
|
290
287
|
{
|
|
291
288
|
"name": "topolo-bytes-api",
|
|
292
289
|
"kind": "worker",
|
|
293
|
-
"apiUrl":
|
|
294
|
-
"domains": [
|
|
295
|
-
"bytes-api.topolo.app"
|
|
296
|
-
],
|
|
290
|
+
"apiUrl": null,
|
|
291
|
+
"domains": [],
|
|
297
292
|
"routes": [],
|
|
298
|
-
"serviceId":
|
|
293
|
+
"serviceId": null
|
|
299
294
|
}
|
|
300
295
|
]
|
|
301
296
|
},
|
|
@@ -394,12 +389,10 @@ var APPLICATIONS = {
|
|
|
394
389
|
{
|
|
395
390
|
"name": "topolo-commerce-api",
|
|
396
391
|
"kind": "worker",
|
|
397
|
-
"apiUrl":
|
|
398
|
-
"domains": [
|
|
399
|
-
"commerce-api.topolo.app"
|
|
400
|
-
],
|
|
392
|
+
"apiUrl": null,
|
|
393
|
+
"domains": [],
|
|
401
394
|
"routes": [],
|
|
402
|
-
"serviceId":
|
|
395
|
+
"serviceId": null
|
|
403
396
|
},
|
|
404
397
|
{
|
|
405
398
|
"name": "topolo-commerce-guest-web",
|
|
@@ -419,7 +412,7 @@ var APPLICATIONS = {
|
|
|
419
412
|
"commerce.topolo.app"
|
|
420
413
|
],
|
|
421
414
|
"routes": [],
|
|
422
|
-
"serviceId":
|
|
415
|
+
"serviceId": "commerce"
|
|
423
416
|
},
|
|
424
417
|
{
|
|
425
418
|
"name": "topolo-commerce-station-web",
|
|
@@ -506,12 +499,10 @@ var APPLICATIONS = {
|
|
|
506
499
|
{
|
|
507
500
|
"name": "topolo-crm-api",
|
|
508
501
|
"kind": "worker",
|
|
509
|
-
"apiUrl":
|
|
510
|
-
"domains": [
|
|
511
|
-
"crm-api.topolo.app"
|
|
512
|
-
],
|
|
502
|
+
"apiUrl": null,
|
|
503
|
+
"domains": [],
|
|
513
504
|
"routes": [],
|
|
514
|
-
"serviceId":
|
|
505
|
+
"serviceId": null
|
|
515
506
|
},
|
|
516
507
|
{
|
|
517
508
|
"name": "topolo-crm-app",
|
|
@@ -521,7 +512,7 @@ var APPLICATIONS = {
|
|
|
521
512
|
"crm.topolo.app"
|
|
522
513
|
],
|
|
523
514
|
"routes": [],
|
|
524
|
-
"serviceId":
|
|
515
|
+
"serviceId": "crm"
|
|
525
516
|
}
|
|
526
517
|
]
|
|
527
518
|
},
|
|
@@ -649,7 +640,7 @@ var APPLICATIONS = {
|
|
|
649
640
|
"feed-api.topolo.app"
|
|
650
641
|
],
|
|
651
642
|
"routes": [],
|
|
652
|
-
"serviceId":
|
|
643
|
+
"serviceId": null
|
|
653
644
|
},
|
|
654
645
|
{
|
|
655
646
|
"name": "topolo-feed-web",
|
|
@@ -659,7 +650,7 @@ var APPLICATIONS = {
|
|
|
659
650
|
"feed.topolo.app"
|
|
660
651
|
],
|
|
661
652
|
"routes": [],
|
|
662
|
-
"serviceId":
|
|
653
|
+
"serviceId": "feed"
|
|
663
654
|
}
|
|
664
655
|
]
|
|
665
656
|
},
|
|
@@ -711,17 +702,15 @@ var APPLICATIONS = {
|
|
|
711
702
|
"forecast.topolo.app"
|
|
712
703
|
],
|
|
713
704
|
"routes": [],
|
|
714
|
-
"serviceId":
|
|
705
|
+
"serviceId": "forecast"
|
|
715
706
|
},
|
|
716
707
|
{
|
|
717
708
|
"name": "topolo-forecast-api",
|
|
718
709
|
"kind": "worker",
|
|
719
|
-
"apiUrl":
|
|
720
|
-
"domains": [
|
|
721
|
-
"forecast-api.topolo.app"
|
|
722
|
-
],
|
|
710
|
+
"apiUrl": null,
|
|
711
|
+
"domains": [],
|
|
723
712
|
"routes": [],
|
|
724
|
-
"serviceId":
|
|
713
|
+
"serviceId": null
|
|
725
714
|
}
|
|
726
715
|
]
|
|
727
716
|
},
|
|
@@ -863,17 +852,15 @@ var APPLICATIONS = {
|
|
|
863
852
|
"learn.topolo.app"
|
|
864
853
|
],
|
|
865
854
|
"routes": [],
|
|
866
|
-
"serviceId":
|
|
855
|
+
"serviceId": "learn"
|
|
867
856
|
},
|
|
868
857
|
{
|
|
869
858
|
"name": "topolo-learn-api",
|
|
870
859
|
"kind": "worker",
|
|
871
|
-
"apiUrl":
|
|
872
|
-
"domains": [
|
|
873
|
-
"learn-api.topolo.app"
|
|
874
|
-
],
|
|
860
|
+
"apiUrl": null,
|
|
861
|
+
"domains": [],
|
|
875
862
|
"routes": [],
|
|
876
|
-
"serviceId":
|
|
863
|
+
"serviceId": null
|
|
877
864
|
}
|
|
878
865
|
]
|
|
879
866
|
},
|
|
@@ -919,17 +906,15 @@ var APPLICATIONS = {
|
|
|
919
906
|
"mail.topolo.app"
|
|
920
907
|
],
|
|
921
908
|
"routes": [],
|
|
922
|
-
"serviceId":
|
|
909
|
+
"serviceId": "mail"
|
|
923
910
|
},
|
|
924
911
|
{
|
|
925
912
|
"name": "topolo-mail-api",
|
|
926
913
|
"kind": "worker",
|
|
927
|
-
"apiUrl":
|
|
928
|
-
"domains": [
|
|
929
|
-
"mail-api.topolo.app"
|
|
930
|
-
],
|
|
914
|
+
"apiUrl": null,
|
|
915
|
+
"domains": [],
|
|
931
916
|
"routes": [],
|
|
932
|
-
"serviceId":
|
|
917
|
+
"serviceId": null
|
|
933
918
|
}
|
|
934
919
|
]
|
|
935
920
|
},
|
|
@@ -946,12 +931,10 @@ var APPLICATIONS = {
|
|
|
946
931
|
{
|
|
947
932
|
"name": "topolo-mdm-api",
|
|
948
933
|
"kind": "worker",
|
|
949
|
-
"apiUrl":
|
|
950
|
-
"domains": [
|
|
951
|
-
"mdm-api.topolo.app"
|
|
952
|
-
],
|
|
934
|
+
"apiUrl": null,
|
|
935
|
+
"domains": [],
|
|
953
936
|
"routes": [],
|
|
954
|
-
"serviceId":
|
|
937
|
+
"serviceId": null
|
|
955
938
|
},
|
|
956
939
|
{
|
|
957
940
|
"name": "topolo-mdm-console",
|
|
@@ -961,7 +944,7 @@ var APPLICATIONS = {
|
|
|
961
944
|
"mdm.topolo.app"
|
|
962
945
|
],
|
|
963
946
|
"routes": [],
|
|
964
|
-
"serviceId":
|
|
947
|
+
"serviceId": "mdm"
|
|
965
948
|
}
|
|
966
949
|
]
|
|
967
950
|
},
|
|
@@ -1026,9 +1009,9 @@ var APPLICATIONS = {
|
|
|
1026
1009
|
{
|
|
1027
1010
|
"name": "topolo-nexus-gateway",
|
|
1028
1011
|
"kind": "worker",
|
|
1029
|
-
"apiUrl": "https://nexus
|
|
1012
|
+
"apiUrl": "https://nexus.topolo.app",
|
|
1030
1013
|
"domains": [
|
|
1031
|
-
"nexus
|
|
1014
|
+
"nexus.topolo.app"
|
|
1032
1015
|
],
|
|
1033
1016
|
"routes": [],
|
|
1034
1017
|
"serviceId": "nexus"
|
|
@@ -1094,20 +1077,23 @@ var APPLICATIONS = {
|
|
|
1094
1077
|
{
|
|
1095
1078
|
"name": "topolo-one",
|
|
1096
1079
|
"kind": "worker",
|
|
1097
|
-
"apiUrl":
|
|
1098
|
-
"domains": [
|
|
1099
|
-
|
|
1080
|
+
"apiUrl": "https://one.topolo.app",
|
|
1081
|
+
"domains": [
|
|
1082
|
+
"one.topolo.app"
|
|
1083
|
+
],
|
|
1084
|
+
"routes": [
|
|
1085
|
+
"one.topolo.app/*"
|
|
1086
|
+
],
|
|
1100
1087
|
"serviceId": null
|
|
1101
1088
|
},
|
|
1102
1089
|
{
|
|
1103
1090
|
"name": "topolo-one-api",
|
|
1104
1091
|
"kind": "worker",
|
|
1105
|
-
"apiUrl": "https://
|
|
1092
|
+
"apiUrl": "https://www.topolo.app",
|
|
1106
1093
|
"domains": [
|
|
1107
|
-
"
|
|
1094
|
+
"www.topolo.app"
|
|
1108
1095
|
],
|
|
1109
1096
|
"routes": [
|
|
1110
|
-
"one.topolo.app/*",
|
|
1111
1097
|
"www.topolo.app/*"
|
|
1112
1098
|
],
|
|
1113
1099
|
"serviceId": "one"
|
|
@@ -1217,36 +1203,6 @@ var APPLICATIONS = {
|
|
|
1217
1203
|
}
|
|
1218
1204
|
]
|
|
1219
1205
|
},
|
|
1220
|
-
"pulse": {
|
|
1221
|
-
"id": "pulse",
|
|
1222
|
-
"appDir": "TopoloPulse",
|
|
1223
|
-
"name": "topolo-pulse",
|
|
1224
|
-
"packageName": "topolo-pulse",
|
|
1225
|
-
"productionUrl": "https://pulse.topolo.app",
|
|
1226
|
-
"services": [
|
|
1227
|
-
"pulse"
|
|
1228
|
-
],
|
|
1229
|
-
"deployTargets": [
|
|
1230
|
-
{
|
|
1231
|
-
"name": "topolo-pulse",
|
|
1232
|
-
"kind": "worker",
|
|
1233
|
-
"apiUrl": "https://pulse.topolo.app",
|
|
1234
|
-
"domains": [
|
|
1235
|
-
"pulse.topolo.app"
|
|
1236
|
-
],
|
|
1237
|
-
"routes": [],
|
|
1238
|
-
"serviceId": "pulse"
|
|
1239
|
-
},
|
|
1240
|
-
{
|
|
1241
|
-
"name": "topolo-pulse-api",
|
|
1242
|
-
"kind": "worker",
|
|
1243
|
-
"apiUrl": null,
|
|
1244
|
-
"domains": [],
|
|
1245
|
-
"routes": [],
|
|
1246
|
-
"serviceId": null
|
|
1247
|
-
}
|
|
1248
|
-
]
|
|
1249
|
-
},
|
|
1250
1206
|
"quro": {
|
|
1251
1207
|
"id": "quro",
|
|
1252
1208
|
"appDir": "TopoloQuro",
|
|
@@ -1312,17 +1268,15 @@ var APPLICATIONS = {
|
|
|
1312
1268
|
"roadmapper.topolo.app"
|
|
1313
1269
|
],
|
|
1314
1270
|
"routes": [],
|
|
1315
|
-
"serviceId":
|
|
1271
|
+
"serviceId": "roadmapper"
|
|
1316
1272
|
},
|
|
1317
1273
|
{
|
|
1318
1274
|
"name": "topolo-roadmapper-api",
|
|
1319
1275
|
"kind": "worker",
|
|
1320
|
-
"apiUrl":
|
|
1321
|
-
"domains": [
|
|
1322
|
-
"roadmapper-api.topolo.app"
|
|
1323
|
-
],
|
|
1276
|
+
"apiUrl": null,
|
|
1277
|
+
"domains": [],
|
|
1324
1278
|
"routes": [],
|
|
1325
|
-
"serviceId":
|
|
1279
|
+
"serviceId": null
|
|
1326
1280
|
}
|
|
1327
1281
|
]
|
|
1328
1282
|
},
|
|
@@ -1374,17 +1328,15 @@ var APPLICATIONS = {
|
|
|
1374
1328
|
"studio.topolo.app"
|
|
1375
1329
|
],
|
|
1376
1330
|
"routes": [],
|
|
1377
|
-
"serviceId":
|
|
1331
|
+
"serviceId": "social_studio"
|
|
1378
1332
|
},
|
|
1379
1333
|
{
|
|
1380
1334
|
"name": "topolo-social-studio-api",
|
|
1381
1335
|
"kind": "worker",
|
|
1382
|
-
"apiUrl":
|
|
1383
|
-
"domains": [
|
|
1384
|
-
"studio-api.topolo.app"
|
|
1385
|
-
],
|
|
1336
|
+
"apiUrl": null,
|
|
1337
|
+
"domains": [],
|
|
1386
1338
|
"routes": [],
|
|
1387
|
-
"serviceId":
|
|
1339
|
+
"serviceId": null
|
|
1388
1340
|
},
|
|
1389
1341
|
{
|
|
1390
1342
|
"name": "topolo-social-studio-queue",
|
|
@@ -1414,7 +1366,7 @@ var APPLICATIONS = {
|
|
|
1414
1366
|
"socialize.topolo.app"
|
|
1415
1367
|
],
|
|
1416
1368
|
"routes": [],
|
|
1417
|
-
"serviceId":
|
|
1369
|
+
"serviceId": "socialize"
|
|
1418
1370
|
},
|
|
1419
1371
|
{
|
|
1420
1372
|
"name": "topolo-socialize-api",
|
|
@@ -1424,7 +1376,7 @@ var APPLICATIONS = {
|
|
|
1424
1376
|
"socialize-api.topolo.app"
|
|
1425
1377
|
],
|
|
1426
1378
|
"routes": [],
|
|
1427
|
-
"serviceId":
|
|
1379
|
+
"serviceId": null
|
|
1428
1380
|
},
|
|
1429
1381
|
{
|
|
1430
1382
|
"name": "topolo-socialize-scheduler",
|
|
@@ -1625,12 +1577,10 @@ var APPLICATIONS = {
|
|
|
1625
1577
|
{
|
|
1626
1578
|
"name": "topolo-web-api",
|
|
1627
1579
|
"kind": "worker",
|
|
1628
|
-
"apiUrl":
|
|
1629
|
-
"domains": [
|
|
1630
|
-
"web-api.topolo.app"
|
|
1631
|
-
],
|
|
1580
|
+
"apiUrl": null,
|
|
1581
|
+
"domains": [],
|
|
1632
1582
|
"routes": [],
|
|
1633
|
-
"serviceId":
|
|
1583
|
+
"serviceId": null
|
|
1634
1584
|
},
|
|
1635
1585
|
{
|
|
1636
1586
|
"name": "topolo-web-runtime",
|
|
@@ -1653,12 +1603,12 @@ var APPLICATIONS = {
|
|
|
1653
1603
|
"web.topolo.app"
|
|
1654
1604
|
],
|
|
1655
1605
|
"routes": [],
|
|
1656
|
-
"serviceId":
|
|
1606
|
+
"serviceId": "web"
|
|
1657
1607
|
}
|
|
1658
1608
|
]
|
|
1659
1609
|
}
|
|
1660
1610
|
};
|
|
1661
|
-
var APPLICATION_REQUIREMENTS_VERSION = "2026-
|
|
1611
|
+
var APPLICATION_REQUIREMENTS_VERSION = "2026-06-07.1";
|
|
1662
1612
|
var APPLICATION_REQUIREMENTS = [
|
|
1663
1613
|
{
|
|
1664
1614
|
id: "platform-metadata",
|
|
@@ -1714,16 +1664,20 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1714
1664
|
summary: "Browser applications should feel like one platform and should not create isolated navigation or account surfaces.",
|
|
1715
1665
|
appliesTo: ["browser"],
|
|
1716
1666
|
evidence: [
|
|
1717
|
-
"@topolo/
|
|
1718
|
-
"
|
|
1719
|
-
"Account menu and sign-out behavior use TopoloAppShell or TopoloAccountMenu",
|
|
1667
|
+
"@topolo-io/app-shell is used for the platform shell where the app has authenticated UI",
|
|
1668
|
+
"@topolo-io/app-launcher keeps the shared launcher/app switcher reachable from authenticated app chrome",
|
|
1669
|
+
"Account menu and sign-out behavior use TopoloAppShell or the ui-kit TopoloAccountMenu primitive",
|
|
1670
|
+
"Repeated app body surfaces use shared TopoloAppLayout primitives instead of local stat cards, empty states, or status badges",
|
|
1671
|
+
"Local preview supports deterministic visual QA fixtures for overview, list, detail, settings, and empty/loading states",
|
|
1720
1672
|
"Authenticated app body content stays inside the viewport on mobile and desktop widths"
|
|
1721
1673
|
],
|
|
1722
1674
|
implementation: [
|
|
1723
|
-
"Use TopoloAppShell for authenticated app layouts",
|
|
1724
|
-
"Use TopoloAccountMenu when a partial-shell surface still needs account chrome",
|
|
1675
|
+
"Use @topolo-io/app-shell TopoloAppShell for authenticated app layouts",
|
|
1676
|
+
"Use the @topolo-io/ui-kit TopoloAccountMenu primitive when a partial-shell surface still needs account chrome",
|
|
1725
1677
|
"Pass app-specific account actions as additive menu items instead of forking dropdowns",
|
|
1726
1678
|
"Use shared design tokens and platform UI primitives before creating local equivalents",
|
|
1679
|
+
"Use TopoloAppMetricCard, TopoloAppEmptyState, TopoloAppStatusBadge, TopoloAppGrid, and TopoloAppSection for repeated app body patterns",
|
|
1680
|
+
"Keep visual QA fixtures available through visualQa=1 or __devpreview=1 so screenshot checks do not depend on live API state",
|
|
1727
1681
|
"Keep mobile and desktop shell behavior aligned with the platform UI kit",
|
|
1728
1682
|
"Constrain app-owned workspace wrappers with min-width: 0, width: auto, and viewport-aware max-width so shell padding cannot create page-level horizontal overflow"
|
|
1729
1683
|
]
|
|
@@ -1802,11 +1756,13 @@ var APPLICATION_REQUIREMENTS = [
|
|
|
1802
1756
|
evidence: [
|
|
1803
1757
|
"The app-owned API exposes GET /api/widget",
|
|
1804
1758
|
"The endpoint returns TopoloWidgetApiResponse from @topolo/sdk",
|
|
1759
|
+
"Every returned widget includes snapshot.summary with app-owned operational prose",
|
|
1805
1760
|
"The endpoint derives organization/user context from the app auth boundary"
|
|
1806
1761
|
],
|
|
1807
1762
|
implementation: [
|
|
1808
1763
|
"Import createTopoloWidgetResponse from @topolo/sdk in the app backend",
|
|
1809
1764
|
"Return native app metrics or action widgets instead of generic launch-card fallbacks",
|
|
1765
|
+
"Populate snapshot.summary in the producing app for every widget instead of synthesizing summaries in TopoloOne",
|
|
1810
1766
|
"Add a route-level test that validates the response with validateTopoloWidgetResponse"
|
|
1811
1767
|
]
|
|
1812
1768
|
},
|
|
@@ -2099,6 +2055,8 @@ function firstString(...values) {
|
|
|
2099
2055
|
var WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
2100
2056
|
var TOPOLO_ACTION_ID_HEADER = "X-Topolo-Action-Id";
|
|
2101
2057
|
var TOPOLO_ACTION_NAME_HEADER = "X-Topolo-Action-Name";
|
|
2058
|
+
var TOPOLO_RESOURCE_TYPE_HEADER = "X-Topolo-Resource-Type";
|
|
2059
|
+
var TOPOLO_RESOURCE_ID_HEADER = "X-Topolo-Resource-ID";
|
|
2102
2060
|
var POSITIVE_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
2103
2061
|
var NEGATIVE_CACHE_TTL_MS = 60 * 1e3;
|
|
2104
2062
|
var CATALOG_CACHE_TTL_MS = 60 * 1e3;
|
|
@@ -2177,6 +2135,18 @@ var TopoloClient = class _TopoloClient {
|
|
|
2177
2135
|
if (opts.headers) {
|
|
2178
2136
|
for (const [k, v] of Object.entries(opts.headers)) headers.set(k, v);
|
|
2179
2137
|
}
|
|
2138
|
+
if (opts.resource) {
|
|
2139
|
+
const resourceType = opts.resource.resourceType.trim();
|
|
2140
|
+
const resourceId = opts.resource.resourceId.trim();
|
|
2141
|
+
if (!resourceType || !resourceId) {
|
|
2142
|
+
throw new TopoloSdkError(
|
|
2143
|
+
"invalid_resource_context",
|
|
2144
|
+
"Both resource.resourceType and resource.resourceId are required when resource context is provided."
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
headers.set(TOPOLO_RESOURCE_TYPE_HEADER, resourceType);
|
|
2148
|
+
headers.set(TOPOLO_RESOURCE_ID_HEADER, resourceId);
|
|
2149
|
+
}
|
|
2180
2150
|
const controller = new AbortController();
|
|
2181
2151
|
const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
2182
2152
|
const signal = opts.signal ? mergeSignals(opts.signal, controller.signal) : controller.signal;
|
|
@@ -2248,10 +2218,14 @@ var TopoloClient = class _TopoloClient {
|
|
|
2248
2218
|
if (!serviceKey) {
|
|
2249
2219
|
throw new TopoloSdkError("unknown_service", "service is required");
|
|
2250
2220
|
}
|
|
2251
|
-
if (serviceKey === "auth") {
|
|
2221
|
+
if (serviceKey === "auth" || serviceKey === "developers") {
|
|
2252
2222
|
const overrideUrl = resolveConfiguredServiceUrl(serviceKey, this.serviceUrls);
|
|
2253
2223
|
if (overrideUrl) return { serviceKey, baseUrl: overrideUrl };
|
|
2254
|
-
|
|
2224
|
+
if (serviceKey === "developers") {
|
|
2225
|
+
const derived = deriveDevelopersFromAuth(resolveConfiguredServiceUrl("auth", this.serviceUrls));
|
|
2226
|
+
if (derived) return { serviceKey, baseUrl: derived };
|
|
2227
|
+
}
|
|
2228
|
+
return { serviceKey, baseUrl: DEFAULT_SERVICE_URLS[serviceKey] };
|
|
2255
2229
|
}
|
|
2256
2230
|
const live = await this.resolveLiveCallableService(serviceKey);
|
|
2257
2231
|
if (live) {
|
|
@@ -2291,7 +2265,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2291
2265
|
if (!normalized) return null;
|
|
2292
2266
|
const configuredServiceId = resolveConfiguredServiceId(normalized, this.serviceIds);
|
|
2293
2267
|
if (configuredServiceId) return configuredServiceId;
|
|
2294
|
-
const authBase = resolveServiceUrl("
|
|
2268
|
+
const authBase = resolveServiceUrl("developers", this.serviceUrls);
|
|
2295
2269
|
const cacheKey = `${authBase}|${normalized}`;
|
|
2296
2270
|
const now = Date.now();
|
|
2297
2271
|
const cached = _TopoloClient.serviceIdCache.get(cacheKey);
|
|
@@ -2345,7 +2319,7 @@ var TopoloClient = class _TopoloClient {
|
|
|
2345
2319
|
if (this.serviceCatalogCache && this.serviceCatalogCache.expiresAt > now) {
|
|
2346
2320
|
return this.serviceCatalogCache.entries;
|
|
2347
2321
|
}
|
|
2348
|
-
const res = await this.request({ service: "
|
|
2322
|
+
const res = await this.request({ service: "developers", method: "GET", path: "/api/services/catalog" });
|
|
2349
2323
|
const raw = res.data?.services ?? res.services;
|
|
2350
2324
|
if (!Array.isArray(raw)) {
|
|
2351
2325
|
throw new TopoloSdkError(
|
|
@@ -2359,6 +2333,11 @@ var TopoloClient = class _TopoloClient {
|
|
|
2359
2333
|
const serviceId = typeof s.service_id === "string" ? s.service_id : typeof s.id === "string" ? s.id : null;
|
|
2360
2334
|
if (!serviceId) continue;
|
|
2361
2335
|
const permissions = Array.isArray(s.granted_permissions) ? s.granted_permissions.filter((permission) => typeof permission === "string" && permission.trim().length > 0) : [];
|
|
2336
|
+
const catalogApiKeyResources = normalizeApiKeyResourceMetadataList(
|
|
2337
|
+
s.api_key_resources ?? s.apiKeyResources
|
|
2338
|
+
);
|
|
2339
|
+
const apiKeyResource = normalizeApiKeyResourceMetadata(s.api_key_resource ?? s.apiKeyResource) ?? catalogApiKeyResources[0] ?? null;
|
|
2340
|
+
const apiKeyResources = catalogApiKeyResources.length > 0 ? catalogApiKeyResources : apiKeyResource ? [apiKeyResource] : [];
|
|
2362
2341
|
entries.push({
|
|
2363
2342
|
serviceId,
|
|
2364
2343
|
slug: typeof s.app_slug === "string" ? s.app_slug : null,
|
|
@@ -2369,7 +2348,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
2369
2348
|
status: typeof s.status === "string" ? s.status : null,
|
|
2370
2349
|
surfaceKind: typeof s.surface_kind === "string" ? s.surface_kind : null,
|
|
2371
2350
|
launchable: s.launchable === true,
|
|
2372
|
-
permissions
|
|
2351
|
+
permissions,
|
|
2352
|
+
apiKeyResource,
|
|
2353
|
+
apiKeyResources
|
|
2373
2354
|
});
|
|
2374
2355
|
}
|
|
2375
2356
|
this.serviceCatalogCache = {
|
|
@@ -2455,7 +2436,9 @@ var TopoloClient = class _TopoloClient {
|
|
|
2455
2436
|
status: "bundled",
|
|
2456
2437
|
surfaceKind: "application",
|
|
2457
2438
|
launchable: Boolean(app.productionUrl),
|
|
2458
|
-
permissions: []
|
|
2439
|
+
permissions: [],
|
|
2440
|
+
apiKeyResource: null,
|
|
2441
|
+
apiKeyResources: []
|
|
2459
2442
|
}));
|
|
2460
2443
|
}
|
|
2461
2444
|
/**
|
|
@@ -2504,6 +2487,46 @@ function resolveConfiguredServiceId(slug, serviceIds) {
|
|
|
2504
2487
|
}
|
|
2505
2488
|
return null;
|
|
2506
2489
|
}
|
|
2490
|
+
function normalizeApiKeyResourceMetadata(input) {
|
|
2491
|
+
if (!isRecord(input)) return null;
|
|
2492
|
+
const resourceType = readString(input.resourceType ?? input.resource_type);
|
|
2493
|
+
const label = readString(input.label);
|
|
2494
|
+
const emptyLabel = readString(input.emptyLabel ?? input.empty_label);
|
|
2495
|
+
const resourceConcept = readString(input.resourceConcept ?? input.resource_concept);
|
|
2496
|
+
const canonicalResourceType = readString(input.canonicalResourceType ?? input.canonical_resource_type);
|
|
2497
|
+
const defaultEntitlement = readString(input.defaultEntitlement ?? input.default_entitlement);
|
|
2498
|
+
const exceptionPolicy = readString(input.exceptionPolicy ?? input.exception_policy);
|
|
2499
|
+
if (!resourceType || !label || !emptyLabel || resourceConcept !== "workspace" || canonicalResourceType !== "workspace" || defaultEntitlement !== "enterprise" || exceptionPolicy !== "app_or_organization") {
|
|
2500
|
+
return null;
|
|
2501
|
+
}
|
|
2502
|
+
return {
|
|
2503
|
+
resourceType,
|
|
2504
|
+
label,
|
|
2505
|
+
emptyLabel,
|
|
2506
|
+
resourceConcept,
|
|
2507
|
+
canonicalResourceType,
|
|
2508
|
+
defaultEntitlement,
|
|
2509
|
+
exceptionPolicy
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
function normalizeApiKeyResourceMetadataList(input) {
|
|
2513
|
+
if (!Array.isArray(input)) return [];
|
|
2514
|
+
const resources = [];
|
|
2515
|
+
const seenTypes = /* @__PURE__ */ new Set();
|
|
2516
|
+
for (const item of input) {
|
|
2517
|
+
const resource = normalizeApiKeyResourceMetadata(item);
|
|
2518
|
+
if (!resource || seenTypes.has(resource.resourceType)) continue;
|
|
2519
|
+
seenTypes.add(resource.resourceType);
|
|
2520
|
+
resources.push(resource);
|
|
2521
|
+
}
|
|
2522
|
+
return resources;
|
|
2523
|
+
}
|
|
2524
|
+
function readString(value) {
|
|
2525
|
+
return typeof value === "string" ? value.trim() : "";
|
|
2526
|
+
}
|
|
2527
|
+
function isRecord(value) {
|
|
2528
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2529
|
+
}
|
|
2507
2530
|
function resolveConfiguredServiceUrl(slug, serviceUrls) {
|
|
2508
2531
|
for (const serviceKey of serviceKeyCandidates2(slug)) {
|
|
2509
2532
|
const configured = serviceUrls?.[serviceKey];
|
|
@@ -2527,6 +2550,17 @@ function serviceKeyCandidates2(slug) {
|
|
|
2527
2550
|
function normalizeLookupKey(value) {
|
|
2528
2551
|
return String(value || "").trim().toLowerCase().replace(/\s+/g, "-");
|
|
2529
2552
|
}
|
|
2553
|
+
function deriveDevelopersFromAuth(authUrl) {
|
|
2554
|
+
if (!authUrl) return null;
|
|
2555
|
+
try {
|
|
2556
|
+
const url = new URL(authUrl);
|
|
2557
|
+
if (!/^auth\./i.test(url.hostname)) return null;
|
|
2558
|
+
url.hostname = url.hostname.replace(/^auth\./i, "developers.");
|
|
2559
|
+
return url.origin;
|
|
2560
|
+
} catch {
|
|
2561
|
+
return null;
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2530
2564
|
function catalogEntryMatches(entry, needle) {
|
|
2531
2565
|
return catalogEntryLookupKeys(entry).includes(needle);
|
|
2532
2566
|
}
|
|
@@ -2838,6 +2872,8 @@ var TOOLS = [
|
|
|
2838
2872
|
effectiveUrl: resolveCatalogServiceUrl(entry, { serviceKey: id }),
|
|
2839
2873
|
surfaceKind: entry.surfaceKind,
|
|
2840
2874
|
launchable: entry.launchable,
|
|
2875
|
+
apiKeyResource: entry.apiKeyResource,
|
|
2876
|
+
apiKeyResources: [...entry.apiKeyResources],
|
|
2841
2877
|
permissions: [...entry.permissions]
|
|
2842
2878
|
};
|
|
2843
2879
|
}).sort((left, right) => left.id.localeCompare(right.id));
|
|
@@ -3031,6 +3067,14 @@ var TOOLS = [
|
|
|
3031
3067
|
additionalProperties: { type: "string" },
|
|
3032
3068
|
description: "Query string parameters as string values."
|
|
3033
3069
|
},
|
|
3070
|
+
resourceType: {
|
|
3071
|
+
type: "string",
|
|
3072
|
+
description: "Optional workspace resource alias from topolo_list_services apiKeyResources. Aliases are app-defined, e.g. brand, mailbox, venue, merchant, or any other cataloged alias."
|
|
3073
|
+
},
|
|
3074
|
+
resourceId: {
|
|
3075
|
+
type: "string",
|
|
3076
|
+
description: "Resource id for resourceType. Required when resourceType is provided."
|
|
3077
|
+
},
|
|
3034
3078
|
confirm: {
|
|
3035
3079
|
type: "boolean",
|
|
3036
3080
|
description: "Required for non-GET methods. Explicit human-in-the-loop acknowledgement for writes."
|
|
@@ -3057,12 +3101,19 @@ var TOOLS = [
|
|
|
3057
3101
|
const normalisedQuery = query && typeof query === "object" && !Array.isArray(query) ? Object.fromEntries(
|
|
3058
3102
|
Object.entries(query).map(([k, v]) => [k, String(v)])
|
|
3059
3103
|
) : void 0;
|
|
3104
|
+
const resourceType = typeof args["resourceType"] === "string" ? args["resourceType"].trim() : "";
|
|
3105
|
+
const resourceId = typeof args["resourceId"] === "string" ? args["resourceId"].trim() : "";
|
|
3106
|
+
if (resourceType && !resourceId || !resourceType && resourceId) {
|
|
3107
|
+
throw new Error("resourceType and resourceId must be provided together.");
|
|
3108
|
+
}
|
|
3109
|
+
const resource = resourceType && resourceId ? { resourceType, resourceId } : void 0;
|
|
3060
3110
|
return topolo.client.request({
|
|
3061
3111
|
service: service.trim(),
|
|
3062
3112
|
method,
|
|
3063
3113
|
path,
|
|
3064
3114
|
body: args["body"],
|
|
3065
3115
|
...normalisedQuery ? { query: normalisedQuery } : {},
|
|
3116
|
+
...resource ? { resource } : {},
|
|
3066
3117
|
confirm: Boolean(args["confirm"])
|
|
3067
3118
|
});
|
|
3068
3119
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topolo/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,27 +15,27 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
|
-
"scripts": {
|
|
19
|
-
"build": "tsup",
|
|
20
|
-
"dev": "tsup --watch",
|
|
21
|
-
"typecheck": "tsc --noEmit",
|
|
22
|
-
"start": "node dist/index.js",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest",
|
|
25
|
-
"coverage": "vitest run --coverage"
|
|
26
|
-
},
|
|
27
18
|
"dependencies": {
|
|
28
19
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
29
20
|
},
|
|
30
21
|
"devDependencies": {
|
|
31
|
-
"@topolo/sdk": "workspace:*",
|
|
32
22
|
"@types/node": "^20.12.0",
|
|
33
23
|
"@vitest/coverage-v8": "^2.1.0",
|
|
34
24
|
"tsup": "^8.0.0",
|
|
35
25
|
"typescript": "^5.4.0",
|
|
36
|
-
"vitest": "^2.1.0"
|
|
26
|
+
"vitest": "^2.1.0",
|
|
27
|
+
"@topolo/sdk": "0.4.9"
|
|
37
28
|
},
|
|
38
29
|
"engines": {
|
|
39
30
|
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"dev": "tsup --watch",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"start": "node dist/index.js",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"coverage": "vitest run --coverage"
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|