@tinycloud/mcp 0.7.4-beta.1 → 0.8.0-beta.3
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 +65 -9
- package/dist/cli.cjs +70 -32
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +71 -33
- package/dist/cli.js.map +1 -1
- package/dist/http-cli.cjs +131 -48
- package/dist/http-cli.cjs.map +1 -1
- package/dist/http-cli.js +129 -46
- package/dist/http-cli.js.map +1 -1
- package/dist/http.cjs +128 -45
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +2 -0
- package/dist/http.d.ts +2 -0
- package/dist/http.js +129 -46
- package/dist/http.js.map +1 -1
- package/dist/index.cjs +128 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +129 -46
- package/dist/index.js.map +1 -1
- package/dist/results.cjs +1 -1
- package/dist/results.cjs.map +1 -1
- package/dist/results.js +1 -1
- package/dist/results.js.map +1 -1
- package/dist/server.cjs +70 -32
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +71 -33
- package/dist/server.js.map +1 -1
- package/dist/tools.cjs +67 -29
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +3 -3
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +68 -30
- package/dist/tools.js.map +1 -1
- package/generated/mcp-facts.json +13 -6
- package/package.json +3 -3
- package/skills/tinycloud-delegated-secrets/SKILL.md +4 -4
package/dist/http-cli.cjs
CHANGED
|
@@ -24,10 +24,11 @@ __export(http_cli_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(http_cli_exports);
|
|
26
26
|
var import_node_http = require("http");
|
|
27
|
-
var
|
|
27
|
+
var import_node_path4 = require("path");
|
|
28
28
|
var import_node = require("@modelcontextprotocol/node");
|
|
29
29
|
|
|
30
30
|
// src/http.ts
|
|
31
|
+
var import_node_path3 = require("path");
|
|
31
32
|
var import_server4 = require("@modelcontextprotocol/server");
|
|
32
33
|
var import_node_sdk3 = require("@tinycloud/node-sdk");
|
|
33
34
|
|
|
@@ -373,7 +374,7 @@ var RemoteTenantStore = class {
|
|
|
373
374
|
async approvalRedirect(state) {
|
|
374
375
|
const pending = await this.#readPending(state, false);
|
|
375
376
|
const tenant = await this.#readTenant(pending.tenantId);
|
|
376
|
-
const callback = new URL("/connect/callback
|
|
377
|
+
const callback = new URL(`${this.#config.approvalPath ?? "/connect"}/callback`, this.#config.publicUrl);
|
|
377
378
|
callback.searchParams.set("state", state);
|
|
378
379
|
const params = new URLSearchParams({
|
|
379
380
|
did: tenant.sessionDid,
|
|
@@ -792,7 +793,7 @@ var RemoteTenantStore = class {
|
|
|
792
793
|
await (0, import_promises.rename)(`${path}.processing`, path);
|
|
793
794
|
}
|
|
794
795
|
#connectUrl(pending) {
|
|
795
|
-
const url = new URL("/connect", this.#config.publicUrl);
|
|
796
|
+
const url = new URL(this.#config.approvalPath ?? "/connect", this.#config.publicUrl);
|
|
796
797
|
url.searchParams.set("state", `${pending.tenantId}.${pending.nonce}.${this.#signState(pending.tenantId, pending.nonce)}`);
|
|
797
798
|
return url.toString();
|
|
798
799
|
}
|
|
@@ -971,7 +972,7 @@ function toMcpToolResult(result, bindings = [], options = {}) {
|
|
|
971
972
|
let serialized;
|
|
972
973
|
if (options.surface === "hosted") {
|
|
973
974
|
serialized = JSON.stringify(canonical);
|
|
974
|
-
if (options.readOnly === true && serialized.length > 1e5) {
|
|
975
|
+
if ((options.readOnly === true || options.operationId === "tinycloud.apps.context" || options.operationId === "tinycloud.apps.query") && serialized.length > 1e5) {
|
|
975
976
|
const sql = options.operationId?.startsWith("tinycloud.sql.") || options.operationId === "tinycloud.apps.query";
|
|
976
977
|
canonical = {
|
|
977
978
|
status: "error",
|
|
@@ -1025,6 +1026,44 @@ function resultSummary(status) {
|
|
|
1025
1026
|
}
|
|
1026
1027
|
}
|
|
1027
1028
|
|
|
1029
|
+
// src/schemas.ts
|
|
1030
|
+
var DRAFT_7 = "http://json-schema.org/draft-07/schema#";
|
|
1031
|
+
var DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema";
|
|
1032
|
+
var schemaMaps = /* @__PURE__ */ new Set(["properties", "patternProperties", "definitions", "$defs"]);
|
|
1033
|
+
var schemaArrays = /* @__PURE__ */ new Set(["allOf", "anyOf", "oneOf"]);
|
|
1034
|
+
var schemaValues = /* @__PURE__ */ new Set([
|
|
1035
|
+
"additionalProperties",
|
|
1036
|
+
"items",
|
|
1037
|
+
"contains",
|
|
1038
|
+
"propertyNames",
|
|
1039
|
+
"not",
|
|
1040
|
+
"if",
|
|
1041
|
+
"then",
|
|
1042
|
+
"else"
|
|
1043
|
+
]);
|
|
1044
|
+
function toMcpJsonSchema(schema) {
|
|
1045
|
+
if (typeof schema === "boolean") return schema;
|
|
1046
|
+
if (Array.isArray(schema.items) || "additionalItems" in schema || "dependencies" in schema || "$ref" in schema && Object.keys(schema).some((key) => key !== "$ref")) {
|
|
1047
|
+
throw new Error("The operations schema needs a semantic migration to JSON Schema 2020-12.");
|
|
1048
|
+
}
|
|
1049
|
+
const projected = {};
|
|
1050
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
1051
|
+
if (key === "$schema") {
|
|
1052
|
+
if (value !== DRAFT_7) throw new Error(`Unsupported operations schema dialect: ${String(value)}.`);
|
|
1053
|
+
projected[key] = DRAFT_2020_12;
|
|
1054
|
+
} else if (schemaMaps.has(key)) {
|
|
1055
|
+
projected[key] = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, toMcpJsonSchema(child)]));
|
|
1056
|
+
} else if (schemaArrays.has(key)) {
|
|
1057
|
+
projected[key] = value.map(toMcpJsonSchema);
|
|
1058
|
+
} else if (schemaValues.has(key)) {
|
|
1059
|
+
projected[key] = toMcpJsonSchema(value);
|
|
1060
|
+
} else {
|
|
1061
|
+
projected[key] = value;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return projected;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1028
1067
|
// src/tools.ts
|
|
1029
1068
|
var import_meta = {};
|
|
1030
1069
|
function invocationTargetForMcp(selection) {
|
|
@@ -1043,9 +1082,9 @@ var generatedCatalog = packageRequire(
|
|
|
1043
1082
|
var stableErrorCodes = Object.fromEntries(
|
|
1044
1083
|
generatedCatalog.stableErrors.map((code) => [code, true])
|
|
1045
1084
|
);
|
|
1046
|
-
var
|
|
1085
|
+
var PRIVATE_SURFACES = ["local", "hosted"];
|
|
1047
1086
|
function bindingSurfaces(binding) {
|
|
1048
|
-
return binding.surfaces ??
|
|
1087
|
+
return binding.surfaces ?? PRIVATE_SURFACES;
|
|
1049
1088
|
}
|
|
1050
1089
|
var TOOL_BINDINGS = [
|
|
1051
1090
|
{
|
|
@@ -1229,11 +1268,11 @@ var TOOL_BINDINGS = [
|
|
|
1229
1268
|
name: "tinycloud_apps_context",
|
|
1230
1269
|
operationId: "tinycloud.apps.context",
|
|
1231
1270
|
operationVersion: 1,
|
|
1232
|
-
readOnlyHint:
|
|
1271
|
+
readOnlyHint: false,
|
|
1233
1272
|
idempotentHint: true,
|
|
1234
|
-
destructiveHint:
|
|
1235
|
-
openWorldHint:
|
|
1236
|
-
surfaces: ["hosted"]
|
|
1273
|
+
destructiveHint: true,
|
|
1274
|
+
openWorldHint: false,
|
|
1275
|
+
surfaces: ["hosted", "public"]
|
|
1237
1276
|
},
|
|
1238
1277
|
{
|
|
1239
1278
|
name: "tinycloud_apps_read",
|
|
@@ -1242,8 +1281,8 @@ var TOOL_BINDINGS = [
|
|
|
1242
1281
|
readOnlyHint: true,
|
|
1243
1282
|
idempotentHint: true,
|
|
1244
1283
|
destructiveHint: false,
|
|
1245
|
-
openWorldHint:
|
|
1246
|
-
surfaces: ["hosted"]
|
|
1284
|
+
openWorldHint: false,
|
|
1285
|
+
surfaces: ["hosted", "public"]
|
|
1247
1286
|
},
|
|
1248
1287
|
{
|
|
1249
1288
|
name: "tinycloud_apps_write",
|
|
@@ -1252,34 +1291,34 @@ var TOOL_BINDINGS = [
|
|
|
1252
1291
|
readOnlyHint: false,
|
|
1253
1292
|
idempotentHint: false,
|
|
1254
1293
|
destructiveHint: true,
|
|
1255
|
-
openWorldHint:
|
|
1256
|
-
surfaces: ["hosted"]
|
|
1294
|
+
openWorldHint: false,
|
|
1295
|
+
surfaces: ["hosted", "public"]
|
|
1257
1296
|
},
|
|
1258
1297
|
{
|
|
1259
1298
|
name: "tinycloud_apps_query",
|
|
1260
1299
|
operationId: "tinycloud.apps.query",
|
|
1261
1300
|
operationVersion: 1,
|
|
1262
|
-
readOnlyHint:
|
|
1301
|
+
readOnlyHint: false,
|
|
1263
1302
|
idempotentHint: true,
|
|
1264
|
-
destructiveHint:
|
|
1265
|
-
openWorldHint:
|
|
1266
|
-
surfaces: ["hosted"]
|
|
1303
|
+
destructiveHint: true,
|
|
1304
|
+
openWorldHint: false,
|
|
1305
|
+
surfaces: ["hosted", "public"]
|
|
1267
1306
|
}
|
|
1268
1307
|
];
|
|
1308
|
+
var definitions = new Map(generatedCatalog.operations.map((operation) => [
|
|
1309
|
+
`${operation.id}@${operation.version}`,
|
|
1310
|
+
{
|
|
1311
|
+
...operation,
|
|
1312
|
+
input: toMcpJsonSchema(operation.input),
|
|
1313
|
+
result: toMcpJsonSchema(operation.result)
|
|
1314
|
+
}
|
|
1315
|
+
]));
|
|
1269
1316
|
function createJsonSchemaValidator() {
|
|
1270
|
-
|
|
1271
|
-
(0, import_ajv.addFormats)(ajv);
|
|
1272
|
-
return new import_ajv.AjvJsonSchemaValidator(ajv);
|
|
1317
|
+
return new import_ajv.AjvJsonSchemaValidator();
|
|
1273
1318
|
}
|
|
1274
1319
|
function registerTinyCloudTools(server, selection, validator) {
|
|
1275
|
-
const
|
|
1276
|
-
|
|
1277
|
-
`${operation.id}@${operation.version}`,
|
|
1278
|
-
operation
|
|
1279
|
-
])
|
|
1280
|
-
);
|
|
1281
|
-
for (const binding of TOOL_BINDINGS) {
|
|
1282
|
-
if (!bindingSurfaces(binding).includes(selection.surface)) continue;
|
|
1320
|
+
const bindings = TOOL_BINDINGS.filter((binding) => bindingSurfaces(binding).includes(selection.surface));
|
|
1321
|
+
for (const binding of bindings) {
|
|
1283
1322
|
const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);
|
|
1284
1323
|
if (operation === void 0) {
|
|
1285
1324
|
throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);
|
|
@@ -1325,15 +1364,15 @@ function registerTinyCloudTools(server, selection, validator) {
|
|
|
1325
1364
|
operationVersion: binding.operationVersion,
|
|
1326
1365
|
input
|
|
1327
1366
|
});
|
|
1328
|
-
const response = toMcpToolResult(projected,
|
|
1329
|
-
surface: selection.surface,
|
|
1367
|
+
const response = toMcpToolResult(projected, bindings, {
|
|
1368
|
+
surface: selection.surface === "local" ? "local" : "hosted",
|
|
1330
1369
|
readOnly: binding.readOnlyHint,
|
|
1331
1370
|
operationId: binding.operationId
|
|
1332
1371
|
});
|
|
1333
1372
|
code = outcomeCode(response.structuredContent);
|
|
1334
1373
|
return response;
|
|
1335
1374
|
} finally {
|
|
1336
|
-
if (selection.surface
|
|
1375
|
+
if (selection.surface !== "local") {
|
|
1337
1376
|
logToolCall(binding.name, code, startedAt, metrics.replayedGrants);
|
|
1338
1377
|
}
|
|
1339
1378
|
}
|
|
@@ -1356,7 +1395,7 @@ function outcomeCode(result) {
|
|
|
1356
1395
|
// package.json
|
|
1357
1396
|
var package_default = {
|
|
1358
1397
|
name: "@tinycloud/mcp",
|
|
1359
|
-
version: "0.
|
|
1398
|
+
version: "0.8.0-beta.3",
|
|
1360
1399
|
description: "TinyCloud delegated operations MCP server",
|
|
1361
1400
|
keywords: [
|
|
1362
1401
|
"tinycloud",
|
|
@@ -1427,9 +1466,9 @@ var package_default = {
|
|
|
1427
1466
|
dependencies: {
|
|
1428
1467
|
"@modelcontextprotocol/node": "2.0.0-beta.5",
|
|
1429
1468
|
"@modelcontextprotocol/server": "2.0.0-beta.5",
|
|
1430
|
-
"@tinycloud/node-sdk": "3.6.0-beta.
|
|
1469
|
+
"@tinycloud/node-sdk": "3.6.0-beta.3",
|
|
1431
1470
|
"@tinycloud/node-sdk-wasm": "1.7.8",
|
|
1432
|
-
"@tinycloud/operations": "0.7.4-beta.
|
|
1471
|
+
"@tinycloud/operations": "0.7.4-beta.3",
|
|
1433
1472
|
jose: "6.2.4"
|
|
1434
1473
|
},
|
|
1435
1474
|
devDependencies: {
|
|
@@ -1455,6 +1494,29 @@ var MCP_SERVER_NAME = "tinycloud-mcp";
|
|
|
1455
1494
|
var REQUIRED_SCOPE = "tinycloud:mcp";
|
|
1456
1495
|
function createHostedMcpApp(config) {
|
|
1457
1496
|
const resourceUrl = canonicalResourceUrl(config.publicUrl);
|
|
1497
|
+
const pluginUrl = new URL("./chatgpt/mcp", resourceUrl);
|
|
1498
|
+
const hosted = createHostedSurface(config, resourceUrl, "hosted");
|
|
1499
|
+
const plugin = createHostedSurface({
|
|
1500
|
+
...config,
|
|
1501
|
+
stateDir: (0, import_node_path3.join)(config.stateDir, "chatgpt"),
|
|
1502
|
+
approvalPath: new URL("./connect", pluginUrl).pathname
|
|
1503
|
+
}, pluginUrl, "public");
|
|
1504
|
+
const pluginPaths = {
|
|
1505
|
+
[pluginUrl.pathname]: true,
|
|
1506
|
+
[new URL("./connect", pluginUrl).pathname]: true,
|
|
1507
|
+
[new URL("./connect/callback", pluginUrl).pathname]: true,
|
|
1508
|
+
[new URL((0, import_server4.getOAuthProtectedResourceMetadataUrl)(pluginUrl)).pathname]: true
|
|
1509
|
+
};
|
|
1510
|
+
return {
|
|
1511
|
+
fetch: (request) => (pluginPaths[new URL(request.url).pathname] === true ? plugin : hosted).fetch(request),
|
|
1512
|
+
close: async () => {
|
|
1513
|
+
await Promise.all([hosted.close(), plugin.close()]);
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
function createHostedSurface(config, resourceUrl, surface) {
|
|
1518
|
+
const connectPath = config.approvalPath ?? "/connect";
|
|
1519
|
+
const callbackPath = `${connectPath}/callback`;
|
|
1458
1520
|
const issuer = String(config.oauthMetadata.issuer);
|
|
1459
1521
|
const jwksUri = String(config.oauthMetadata.jwks_uri);
|
|
1460
1522
|
const verifier = createOpenKeyTokenVerifier({
|
|
@@ -1479,11 +1541,11 @@ function createHostedMcpApp(config) {
|
|
|
1479
1541
|
{ name: MCP_SERVER_NAME, version: MCP_VERSION },
|
|
1480
1542
|
{
|
|
1481
1543
|
jsonSchemaValidator: validator,
|
|
1482
|
-
instructions: "Call tinycloud_connect first. If an operation returns authority_required, open approval.url, then retry that operation unchanged. For personal records such as weight, workouts, goals or todos, call tinycloud_apps_context first."
|
|
1544
|
+
instructions: surface === "public" ? "Use TinyCloud only for the user's requested task. Call tinycloud_connect first. If an operation returns authority_required, present approval.url and wait for the user's approval before retrying. If approval is declined, stop that operation. For personal records, call tinycloud_apps_context first. Never request or store passwords, API keys, authentication codes, government identifiers, payment-card data, or protected health information." : "Call tinycloud_connect first. If an operation returns authority_required, open approval.url, then retry that operation unchanged. For personal records such as weight, workouts, goals or todos, call tinycloud_apps_context first."
|
|
1483
1545
|
}
|
|
1484
1546
|
);
|
|
1485
1547
|
registerTinyCloudTools(server, {
|
|
1486
|
-
surface
|
|
1548
|
+
surface,
|
|
1487
1549
|
profile: "agent",
|
|
1488
1550
|
explicitProfile: true,
|
|
1489
1551
|
allowOwnerProfile: false,
|
|
@@ -1491,7 +1553,7 @@ function createHostedMcpApp(config) {
|
|
|
1491
1553
|
beforeOperation: () => store.validateTenant(subject, ownerDids),
|
|
1492
1554
|
transformOperationResult: (result, invocation) => store.decorateAuthorityResult(subject, ownerDids, result, invocation)
|
|
1493
1555
|
}, validator);
|
|
1494
|
-
registerConnectTool(server, validator, store, identity);
|
|
1556
|
+
registerConnectTool(server, validator, store, identity, surface);
|
|
1495
1557
|
return server;
|
|
1496
1558
|
}, {
|
|
1497
1559
|
legacy: "stateless",
|
|
@@ -1502,7 +1564,7 @@ function createHostedMcpApp(config) {
|
|
|
1502
1564
|
resourceServerUrl: resourceUrl,
|
|
1503
1565
|
serviceDocumentationUrl: new URL("https://docs.tinycloud.xyz/cli/mcp"),
|
|
1504
1566
|
scopesSupported: [REQUIRED_SCOPE],
|
|
1505
|
-
resourceName: "TinyCloud hosted MCP"
|
|
1567
|
+
resourceName: surface === "public" ? "TinyCloud personal records" : "TinyCloud hosted MCP"
|
|
1506
1568
|
};
|
|
1507
1569
|
const allowedHosts = [resourceUrl.hostname];
|
|
1508
1570
|
return {
|
|
@@ -1515,16 +1577,32 @@ function createHostedMcpApp(config) {
|
|
|
1515
1577
|
}
|
|
1516
1578
|
const hostFailure = (0, import_server4.hostHeaderValidationResponse)(request, allowedHosts);
|
|
1517
1579
|
if (hostFailure !== void 0) return hostFailure;
|
|
1518
|
-
if (url.pathname ===
|
|
1580
|
+
if (url.pathname === connectPath) {
|
|
1519
1581
|
if (request.method !== "GET") return methodNotAllowed("GET");
|
|
1520
1582
|
try {
|
|
1521
1583
|
const destination = await store.approvalRedirect(requiredState(url));
|
|
1522
1584
|
return Response.redirect(destination, 302);
|
|
1523
1585
|
} catch {
|
|
1586
|
+
if (request.headers.get("accept")?.includes("text/html")) {
|
|
1587
|
+
return new Response(
|
|
1588
|
+
'<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>TinyCloud approval unavailable</title><main><h1>This approval link is unavailable</h1><p>It may have expired or already been used. No new approval was accepted through this link.</p><p>Return to the conversation that requested access. In ChatGPT, select @TinyCloud and ask it to continue your original request. If access is still needed, it can provide a fresh approval link.</p><p>If you declined access, no further approval is required. Never paste passwords, codes or approval links into support messages.</p></main></html>',
|
|
1589
|
+
{
|
|
1590
|
+
status: 400,
|
|
1591
|
+
headers: {
|
|
1592
|
+
"content-type": "text/html; charset=utf-8",
|
|
1593
|
+
"cache-control": "no-store",
|
|
1594
|
+
"content-security-policy": "default-src 'none'; base-uri 'none'; frame-ancestors 'none'",
|
|
1595
|
+
"referrer-policy": "no-referrer",
|
|
1596
|
+
"x-content-type-options": "nosniff",
|
|
1597
|
+
vary: "Accept"
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
);
|
|
1601
|
+
}
|
|
1524
1602
|
return json({ error: "The approval link is invalid or expired." }, 400);
|
|
1525
1603
|
}
|
|
1526
1604
|
}
|
|
1527
|
-
if (url.pathname ===
|
|
1605
|
+
if (url.pathname === callbackPath) {
|
|
1528
1606
|
if (request.method === "OPTIONS") return callbackCors(new Response(null, { status: 204 }), config.openkeyHost);
|
|
1529
1607
|
if (request.method !== "POST") return methodNotAllowed("POST");
|
|
1530
1608
|
const originFailure2 = validateCallbackOrigin(request, config.openkeyHost);
|
|
@@ -1564,17 +1642,17 @@ function createHostedMcpApp(config) {
|
|
|
1564
1642
|
close: () => handler.close()
|
|
1565
1643
|
};
|
|
1566
1644
|
}
|
|
1567
|
-
function registerConnectTool(server, validator, store, identity) {
|
|
1645
|
+
function registerConnectTool(server, validator, store, identity, surface) {
|
|
1568
1646
|
const inputSchema = (0, import_server4.fromJsonSchema)({ type: "object", properties: {}, additionalProperties: false }, validator);
|
|
1569
1647
|
const outputSchema = (0, import_server4.fromJsonSchema)({
|
|
1570
1648
|
type: "object",
|
|
1571
1649
|
properties: {
|
|
1572
1650
|
connected: { type: "boolean" },
|
|
1573
|
-
sessionDid: { type: "string" },
|
|
1651
|
+
...surface === "hosted" ? { sessionDid: { type: "string" } } : {},
|
|
1574
1652
|
approvalUrl: { type: "string", format: "uri" },
|
|
1575
1653
|
expiresAt: { type: "string", format: "date-time" }
|
|
1576
1654
|
},
|
|
1577
|
-
required: ["connected", "sessionDid"],
|
|
1655
|
+
required: surface === "hosted" ? ["connected", "sessionDid"] : ["connected"],
|
|
1578
1656
|
additionalProperties: false
|
|
1579
1657
|
}, validator);
|
|
1580
1658
|
server.registerTool(
|
|
@@ -1588,7 +1666,7 @@ function registerConnectTool(server, validator, store, identity) {
|
|
|
1588
1666
|
readOnlyHint: false,
|
|
1589
1667
|
idempotentHint: true,
|
|
1590
1668
|
destructiveHint: false,
|
|
1591
|
-
openWorldHint:
|
|
1669
|
+
openWorldHint: false
|
|
1592
1670
|
}
|
|
1593
1671
|
},
|
|
1594
1672
|
async () => {
|
|
@@ -1597,12 +1675,17 @@ function registerConnectTool(server, validator, store, identity) {
|
|
|
1597
1675
|
try {
|
|
1598
1676
|
const status = await store.connectStatus(identity.subject, identity.ownerDids);
|
|
1599
1677
|
code = status.connected ? "ok" : "authority_required";
|
|
1678
|
+
const visibleStatus = surface === "hosted" ? status : {
|
|
1679
|
+
connected: status.connected,
|
|
1680
|
+
...status.approvalUrl === void 0 ? {} : { approvalUrl: status.approvalUrl },
|
|
1681
|
+
...status.expiresAt === void 0 ? {} : { expiresAt: status.expiresAt }
|
|
1682
|
+
};
|
|
1600
1683
|
return {
|
|
1601
1684
|
content: [{
|
|
1602
1685
|
type: "text",
|
|
1603
1686
|
text: status.connected ? "TinyCloud is connected." : `TinyCloud approval is required. Open ${status.approvalUrl}, then call this tool again. This link expires at ${status.expiresAt}.`
|
|
1604
1687
|
}],
|
|
1605
|
-
structuredContent:
|
|
1688
|
+
structuredContent: visibleStatus
|
|
1606
1689
|
};
|
|
1607
1690
|
} finally {
|
|
1608
1691
|
logToolCall("tinycloud_connect", code, startedAt, 0);
|
|
@@ -1715,8 +1798,8 @@ function requiredUrl(name) {
|
|
|
1715
1798
|
}
|
|
1716
1799
|
function requiredAbsolutePath(name) {
|
|
1717
1800
|
const value = requiredString(name);
|
|
1718
|
-
if (!(0,
|
|
1719
|
-
return (0,
|
|
1801
|
+
if (!(0, import_node_path4.isAbsolute)(value)) throw new Error(`${name} must be an absolute path.`);
|
|
1802
|
+
return (0, import_node_path4.resolve)(value);
|
|
1720
1803
|
}
|
|
1721
1804
|
function positiveInteger(value, fallback) {
|
|
1722
1805
|
if (value === void 0) return fallback;
|