@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.d.cts
CHANGED
|
@@ -4,6 +4,8 @@ interface RemoteStoreConfig {
|
|
|
4
4
|
readonly stateDir: string;
|
|
5
5
|
readonly stateSecret: string;
|
|
6
6
|
readonly publicUrl: URL;
|
|
7
|
+
/** Separate public-plugin approvals from the existing root callback. */
|
|
8
|
+
readonly approvalPath?: string;
|
|
7
9
|
readonly nodeHost: string;
|
|
8
10
|
readonly openkeyHost: string;
|
|
9
11
|
readonly approvalTtlSeconds: number;
|
package/dist/http.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ interface RemoteStoreConfig {
|
|
|
4
4
|
readonly stateDir: string;
|
|
5
5
|
readonly stateSecret: string;
|
|
6
6
|
readonly publicUrl: URL;
|
|
7
|
+
/** Separate public-plugin approvals from the existing root callback. */
|
|
8
|
+
readonly approvalPath?: string;
|
|
7
9
|
readonly nodeHost: string;
|
|
8
10
|
readonly openkeyHost: string;
|
|
9
11
|
readonly approvalTtlSeconds: number;
|
package/dist/http.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/http.ts
|
|
2
|
+
import { join as join3 } from "path";
|
|
2
3
|
import {
|
|
3
4
|
McpServer as McpServer2,
|
|
4
5
|
createMcpHandler,
|
|
@@ -352,7 +353,7 @@ var RemoteTenantStore = class {
|
|
|
352
353
|
async approvalRedirect(state) {
|
|
353
354
|
const pending = await this.#readPending(state, false);
|
|
354
355
|
const tenant = await this.#readTenant(pending.tenantId);
|
|
355
|
-
const callback = new URL("/connect/callback
|
|
356
|
+
const callback = new URL(`${this.#config.approvalPath ?? "/connect"}/callback`, this.#config.publicUrl);
|
|
356
357
|
callback.searchParams.set("state", state);
|
|
357
358
|
const params = new URLSearchParams({
|
|
358
359
|
did: tenant.sessionDid,
|
|
@@ -771,7 +772,7 @@ var RemoteTenantStore = class {
|
|
|
771
772
|
await rename(`${path}.processing`, path);
|
|
772
773
|
}
|
|
773
774
|
#connectUrl(pending) {
|
|
774
|
-
const url = new URL("/connect", this.#config.publicUrl);
|
|
775
|
+
const url = new URL(this.#config.approvalPath ?? "/connect", this.#config.publicUrl);
|
|
775
776
|
url.searchParams.set("state", `${pending.tenantId}.${pending.nonce}.${this.#signState(pending.tenantId, pending.nonce)}`);
|
|
776
777
|
return url.toString();
|
|
777
778
|
}
|
|
@@ -936,7 +937,7 @@ import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
|
936
937
|
import { createRequire } from "module";
|
|
937
938
|
import { join as join2 } from "path";
|
|
938
939
|
import { fromJsonSchema } from "@modelcontextprotocol/server";
|
|
939
|
-
import {
|
|
940
|
+
import { AjvJsonSchemaValidator } from "@modelcontextprotocol/server/validators/ajv";
|
|
940
941
|
import { invokeOperation as invokeOperation2 } from "@tinycloud/operations";
|
|
941
942
|
|
|
942
943
|
// src/results.ts
|
|
@@ -950,7 +951,7 @@ function toMcpToolResult(result, bindings = [], options = {}) {
|
|
|
950
951
|
let serialized;
|
|
951
952
|
if (options.surface === "hosted") {
|
|
952
953
|
serialized = JSON.stringify(canonical);
|
|
953
|
-
if (options.readOnly === true && serialized.length > 1e5) {
|
|
954
|
+
if ((options.readOnly === true || options.operationId === "tinycloud.apps.context" || options.operationId === "tinycloud.apps.query") && serialized.length > 1e5) {
|
|
954
955
|
const sql = options.operationId?.startsWith("tinycloud.sql.") || options.operationId === "tinycloud.apps.query";
|
|
955
956
|
canonical = {
|
|
956
957
|
status: "error",
|
|
@@ -1004,6 +1005,44 @@ function resultSummary(status) {
|
|
|
1004
1005
|
}
|
|
1005
1006
|
}
|
|
1006
1007
|
|
|
1008
|
+
// src/schemas.ts
|
|
1009
|
+
var DRAFT_7 = "http://json-schema.org/draft-07/schema#";
|
|
1010
|
+
var DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema";
|
|
1011
|
+
var schemaMaps = /* @__PURE__ */ new Set(["properties", "patternProperties", "definitions", "$defs"]);
|
|
1012
|
+
var schemaArrays = /* @__PURE__ */ new Set(["allOf", "anyOf", "oneOf"]);
|
|
1013
|
+
var schemaValues = /* @__PURE__ */ new Set([
|
|
1014
|
+
"additionalProperties",
|
|
1015
|
+
"items",
|
|
1016
|
+
"contains",
|
|
1017
|
+
"propertyNames",
|
|
1018
|
+
"not",
|
|
1019
|
+
"if",
|
|
1020
|
+
"then",
|
|
1021
|
+
"else"
|
|
1022
|
+
]);
|
|
1023
|
+
function toMcpJsonSchema(schema) {
|
|
1024
|
+
if (typeof schema === "boolean") return schema;
|
|
1025
|
+
if (Array.isArray(schema.items) || "additionalItems" in schema || "dependencies" in schema || "$ref" in schema && Object.keys(schema).some((key) => key !== "$ref")) {
|
|
1026
|
+
throw new Error("The operations schema needs a semantic migration to JSON Schema 2020-12.");
|
|
1027
|
+
}
|
|
1028
|
+
const projected = {};
|
|
1029
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
1030
|
+
if (key === "$schema") {
|
|
1031
|
+
if (value !== DRAFT_7) throw new Error(`Unsupported operations schema dialect: ${String(value)}.`);
|
|
1032
|
+
projected[key] = DRAFT_2020_12;
|
|
1033
|
+
} else if (schemaMaps.has(key)) {
|
|
1034
|
+
projected[key] = Object.fromEntries(Object.entries(value).map(([name, child]) => [name, toMcpJsonSchema(child)]));
|
|
1035
|
+
} else if (schemaArrays.has(key)) {
|
|
1036
|
+
projected[key] = value.map(toMcpJsonSchema);
|
|
1037
|
+
} else if (schemaValues.has(key)) {
|
|
1038
|
+
projected[key] = toMcpJsonSchema(value);
|
|
1039
|
+
} else {
|
|
1040
|
+
projected[key] = value;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return projected;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1007
1046
|
// src/tools.ts
|
|
1008
1047
|
function invocationTargetForMcp(selection) {
|
|
1009
1048
|
return {
|
|
@@ -1021,9 +1060,9 @@ var generatedCatalog = packageRequire(
|
|
|
1021
1060
|
var stableErrorCodes = Object.fromEntries(
|
|
1022
1061
|
generatedCatalog.stableErrors.map((code) => [code, true])
|
|
1023
1062
|
);
|
|
1024
|
-
var
|
|
1063
|
+
var PRIVATE_SURFACES = ["local", "hosted"];
|
|
1025
1064
|
function bindingSurfaces(binding) {
|
|
1026
|
-
return binding.surfaces ??
|
|
1065
|
+
return binding.surfaces ?? PRIVATE_SURFACES;
|
|
1027
1066
|
}
|
|
1028
1067
|
var TOOL_BINDINGS = [
|
|
1029
1068
|
{
|
|
@@ -1207,11 +1246,11 @@ var TOOL_BINDINGS = [
|
|
|
1207
1246
|
name: "tinycloud_apps_context",
|
|
1208
1247
|
operationId: "tinycloud.apps.context",
|
|
1209
1248
|
operationVersion: 1,
|
|
1210
|
-
readOnlyHint:
|
|
1249
|
+
readOnlyHint: false,
|
|
1211
1250
|
idempotentHint: true,
|
|
1212
|
-
destructiveHint:
|
|
1213
|
-
openWorldHint:
|
|
1214
|
-
surfaces: ["hosted"]
|
|
1251
|
+
destructiveHint: true,
|
|
1252
|
+
openWorldHint: false,
|
|
1253
|
+
surfaces: ["hosted", "public"]
|
|
1215
1254
|
},
|
|
1216
1255
|
{
|
|
1217
1256
|
name: "tinycloud_apps_read",
|
|
@@ -1220,8 +1259,8 @@ var TOOL_BINDINGS = [
|
|
|
1220
1259
|
readOnlyHint: true,
|
|
1221
1260
|
idempotentHint: true,
|
|
1222
1261
|
destructiveHint: false,
|
|
1223
|
-
openWorldHint:
|
|
1224
|
-
surfaces: ["hosted"]
|
|
1262
|
+
openWorldHint: false,
|
|
1263
|
+
surfaces: ["hosted", "public"]
|
|
1225
1264
|
},
|
|
1226
1265
|
{
|
|
1227
1266
|
name: "tinycloud_apps_write",
|
|
@@ -1230,34 +1269,34 @@ var TOOL_BINDINGS = [
|
|
|
1230
1269
|
readOnlyHint: false,
|
|
1231
1270
|
idempotentHint: false,
|
|
1232
1271
|
destructiveHint: true,
|
|
1233
|
-
openWorldHint:
|
|
1234
|
-
surfaces: ["hosted"]
|
|
1272
|
+
openWorldHint: false,
|
|
1273
|
+
surfaces: ["hosted", "public"]
|
|
1235
1274
|
},
|
|
1236
1275
|
{
|
|
1237
1276
|
name: "tinycloud_apps_query",
|
|
1238
1277
|
operationId: "tinycloud.apps.query",
|
|
1239
1278
|
operationVersion: 1,
|
|
1240
|
-
readOnlyHint:
|
|
1279
|
+
readOnlyHint: false,
|
|
1241
1280
|
idempotentHint: true,
|
|
1242
|
-
destructiveHint:
|
|
1243
|
-
openWorldHint:
|
|
1244
|
-
surfaces: ["hosted"]
|
|
1281
|
+
destructiveHint: true,
|
|
1282
|
+
openWorldHint: false,
|
|
1283
|
+
surfaces: ["hosted", "public"]
|
|
1245
1284
|
}
|
|
1246
1285
|
];
|
|
1286
|
+
var definitions = new Map(generatedCatalog.operations.map((operation) => [
|
|
1287
|
+
`${operation.id}@${operation.version}`,
|
|
1288
|
+
{
|
|
1289
|
+
...operation,
|
|
1290
|
+
input: toMcpJsonSchema(operation.input),
|
|
1291
|
+
result: toMcpJsonSchema(operation.result)
|
|
1292
|
+
}
|
|
1293
|
+
]));
|
|
1247
1294
|
function createJsonSchemaValidator() {
|
|
1248
|
-
|
|
1249
|
-
addFormats(ajv);
|
|
1250
|
-
return new AjvJsonSchemaValidator(ajv);
|
|
1295
|
+
return new AjvJsonSchemaValidator();
|
|
1251
1296
|
}
|
|
1252
1297
|
function registerTinyCloudTools(server, selection, validator) {
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
`${operation.id}@${operation.version}`,
|
|
1256
|
-
operation
|
|
1257
|
-
])
|
|
1258
|
-
);
|
|
1259
|
-
for (const binding of TOOL_BINDINGS) {
|
|
1260
|
-
if (!bindingSurfaces(binding).includes(selection.surface)) continue;
|
|
1298
|
+
const bindings = TOOL_BINDINGS.filter((binding) => bindingSurfaces(binding).includes(selection.surface));
|
|
1299
|
+
for (const binding of bindings) {
|
|
1261
1300
|
const operation = definitions.get(`${binding.operationId}@${binding.operationVersion}`);
|
|
1262
1301
|
if (operation === void 0) {
|
|
1263
1302
|
throw new Error(`Generated operations catalog is missing ${binding.operationId}@${binding.operationVersion}.`);
|
|
@@ -1303,15 +1342,15 @@ function registerTinyCloudTools(server, selection, validator) {
|
|
|
1303
1342
|
operationVersion: binding.operationVersion,
|
|
1304
1343
|
input
|
|
1305
1344
|
});
|
|
1306
|
-
const response = toMcpToolResult(projected,
|
|
1307
|
-
surface: selection.surface,
|
|
1345
|
+
const response = toMcpToolResult(projected, bindings, {
|
|
1346
|
+
surface: selection.surface === "local" ? "local" : "hosted",
|
|
1308
1347
|
readOnly: binding.readOnlyHint,
|
|
1309
1348
|
operationId: binding.operationId
|
|
1310
1349
|
});
|
|
1311
1350
|
code = outcomeCode(response.structuredContent);
|
|
1312
1351
|
return response;
|
|
1313
1352
|
} finally {
|
|
1314
|
-
if (selection.surface
|
|
1353
|
+
if (selection.surface !== "local") {
|
|
1315
1354
|
logToolCall(binding.name, code, startedAt, metrics.replayedGrants);
|
|
1316
1355
|
}
|
|
1317
1356
|
}
|
|
@@ -1334,7 +1373,7 @@ function outcomeCode(result) {
|
|
|
1334
1373
|
// package.json
|
|
1335
1374
|
var package_default = {
|
|
1336
1375
|
name: "@tinycloud/mcp",
|
|
1337
|
-
version: "0.
|
|
1376
|
+
version: "0.8.0-beta.3",
|
|
1338
1377
|
description: "TinyCloud delegated operations MCP server",
|
|
1339
1378
|
keywords: [
|
|
1340
1379
|
"tinycloud",
|
|
@@ -1405,9 +1444,9 @@ var package_default = {
|
|
|
1405
1444
|
dependencies: {
|
|
1406
1445
|
"@modelcontextprotocol/node": "2.0.0-beta.5",
|
|
1407
1446
|
"@modelcontextprotocol/server": "2.0.0-beta.5",
|
|
1408
|
-
"@tinycloud/node-sdk": "3.6.0-beta.
|
|
1447
|
+
"@tinycloud/node-sdk": "3.6.0-beta.3",
|
|
1409
1448
|
"@tinycloud/node-sdk-wasm": "1.7.8",
|
|
1410
|
-
"@tinycloud/operations": "0.7.4-beta.
|
|
1449
|
+
"@tinycloud/operations": "0.7.4-beta.3",
|
|
1411
1450
|
jose: "6.2.4"
|
|
1412
1451
|
},
|
|
1413
1452
|
devDependencies: {
|
|
@@ -1433,6 +1472,29 @@ var MCP_SERVER_NAME = "tinycloud-mcp";
|
|
|
1433
1472
|
var REQUIRED_SCOPE = "tinycloud:mcp";
|
|
1434
1473
|
function createHostedMcpApp(config) {
|
|
1435
1474
|
const resourceUrl = canonicalResourceUrl(config.publicUrl);
|
|
1475
|
+
const pluginUrl = new URL("./chatgpt/mcp", resourceUrl);
|
|
1476
|
+
const hosted = createHostedSurface(config, resourceUrl, "hosted");
|
|
1477
|
+
const plugin = createHostedSurface({
|
|
1478
|
+
...config,
|
|
1479
|
+
stateDir: join3(config.stateDir, "chatgpt"),
|
|
1480
|
+
approvalPath: new URL("./connect", pluginUrl).pathname
|
|
1481
|
+
}, pluginUrl, "public");
|
|
1482
|
+
const pluginPaths = {
|
|
1483
|
+
[pluginUrl.pathname]: true,
|
|
1484
|
+
[new URL("./connect", pluginUrl).pathname]: true,
|
|
1485
|
+
[new URL("./connect/callback", pluginUrl).pathname]: true,
|
|
1486
|
+
[new URL(getOAuthProtectedResourceMetadataUrl(pluginUrl)).pathname]: true
|
|
1487
|
+
};
|
|
1488
|
+
return {
|
|
1489
|
+
fetch: (request) => (pluginPaths[new URL(request.url).pathname] === true ? plugin : hosted).fetch(request),
|
|
1490
|
+
close: async () => {
|
|
1491
|
+
await Promise.all([hosted.close(), plugin.close()]);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
function createHostedSurface(config, resourceUrl, surface) {
|
|
1496
|
+
const connectPath = config.approvalPath ?? "/connect";
|
|
1497
|
+
const callbackPath = `${connectPath}/callback`;
|
|
1436
1498
|
const issuer = String(config.oauthMetadata.issuer);
|
|
1437
1499
|
const jwksUri = String(config.oauthMetadata.jwks_uri);
|
|
1438
1500
|
const verifier = createOpenKeyTokenVerifier({
|
|
@@ -1457,11 +1519,11 @@ function createHostedMcpApp(config) {
|
|
|
1457
1519
|
{ name: MCP_SERVER_NAME, version: MCP_VERSION },
|
|
1458
1520
|
{
|
|
1459
1521
|
jsonSchemaValidator: validator,
|
|
1460
|
-
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."
|
|
1522
|
+
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."
|
|
1461
1523
|
}
|
|
1462
1524
|
);
|
|
1463
1525
|
registerTinyCloudTools(server, {
|
|
1464
|
-
surface
|
|
1526
|
+
surface,
|
|
1465
1527
|
profile: "agent",
|
|
1466
1528
|
explicitProfile: true,
|
|
1467
1529
|
allowOwnerProfile: false,
|
|
@@ -1469,7 +1531,7 @@ function createHostedMcpApp(config) {
|
|
|
1469
1531
|
beforeOperation: () => store.validateTenant(subject, ownerDids),
|
|
1470
1532
|
transformOperationResult: (result, invocation) => store.decorateAuthorityResult(subject, ownerDids, result, invocation)
|
|
1471
1533
|
}, validator);
|
|
1472
|
-
registerConnectTool(server, validator, store, identity);
|
|
1534
|
+
registerConnectTool(server, validator, store, identity, surface);
|
|
1473
1535
|
return server;
|
|
1474
1536
|
}, {
|
|
1475
1537
|
legacy: "stateless",
|
|
@@ -1480,7 +1542,7 @@ function createHostedMcpApp(config) {
|
|
|
1480
1542
|
resourceServerUrl: resourceUrl,
|
|
1481
1543
|
serviceDocumentationUrl: new URL("https://docs.tinycloud.xyz/cli/mcp"),
|
|
1482
1544
|
scopesSupported: [REQUIRED_SCOPE],
|
|
1483
|
-
resourceName: "TinyCloud hosted MCP"
|
|
1545
|
+
resourceName: surface === "public" ? "TinyCloud personal records" : "TinyCloud hosted MCP"
|
|
1484
1546
|
};
|
|
1485
1547
|
const allowedHosts = [resourceUrl.hostname];
|
|
1486
1548
|
return {
|
|
@@ -1493,16 +1555,32 @@ function createHostedMcpApp(config) {
|
|
|
1493
1555
|
}
|
|
1494
1556
|
const hostFailure = hostHeaderValidationResponse(request, allowedHosts);
|
|
1495
1557
|
if (hostFailure !== void 0) return hostFailure;
|
|
1496
|
-
if (url.pathname ===
|
|
1558
|
+
if (url.pathname === connectPath) {
|
|
1497
1559
|
if (request.method !== "GET") return methodNotAllowed("GET");
|
|
1498
1560
|
try {
|
|
1499
1561
|
const destination = await store.approvalRedirect(requiredState(url));
|
|
1500
1562
|
return Response.redirect(destination, 302);
|
|
1501
1563
|
} catch {
|
|
1564
|
+
if (request.headers.get("accept")?.includes("text/html")) {
|
|
1565
|
+
return new Response(
|
|
1566
|
+
'<!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>',
|
|
1567
|
+
{
|
|
1568
|
+
status: 400,
|
|
1569
|
+
headers: {
|
|
1570
|
+
"content-type": "text/html; charset=utf-8",
|
|
1571
|
+
"cache-control": "no-store",
|
|
1572
|
+
"content-security-policy": "default-src 'none'; base-uri 'none'; frame-ancestors 'none'",
|
|
1573
|
+
"referrer-policy": "no-referrer",
|
|
1574
|
+
"x-content-type-options": "nosniff",
|
|
1575
|
+
vary: "Accept"
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1502
1580
|
return json({ error: "The approval link is invalid or expired." }, 400);
|
|
1503
1581
|
}
|
|
1504
1582
|
}
|
|
1505
|
-
if (url.pathname ===
|
|
1583
|
+
if (url.pathname === callbackPath) {
|
|
1506
1584
|
if (request.method === "OPTIONS") return callbackCors(new Response(null, { status: 204 }), config.openkeyHost);
|
|
1507
1585
|
if (request.method !== "POST") return methodNotAllowed("POST");
|
|
1508
1586
|
const originFailure2 = validateCallbackOrigin(request, config.openkeyHost);
|
|
@@ -1542,17 +1620,17 @@ function createHostedMcpApp(config) {
|
|
|
1542
1620
|
close: () => handler.close()
|
|
1543
1621
|
};
|
|
1544
1622
|
}
|
|
1545
|
-
function registerConnectTool(server, validator, store, identity) {
|
|
1623
|
+
function registerConnectTool(server, validator, store, identity, surface) {
|
|
1546
1624
|
const inputSchema = fromJsonSchema2({ type: "object", properties: {}, additionalProperties: false }, validator);
|
|
1547
1625
|
const outputSchema = fromJsonSchema2({
|
|
1548
1626
|
type: "object",
|
|
1549
1627
|
properties: {
|
|
1550
1628
|
connected: { type: "boolean" },
|
|
1551
|
-
sessionDid: { type: "string" },
|
|
1629
|
+
...surface === "hosted" ? { sessionDid: { type: "string" } } : {},
|
|
1552
1630
|
approvalUrl: { type: "string", format: "uri" },
|
|
1553
1631
|
expiresAt: { type: "string", format: "date-time" }
|
|
1554
1632
|
},
|
|
1555
|
-
required: ["connected", "sessionDid"],
|
|
1633
|
+
required: surface === "hosted" ? ["connected", "sessionDid"] : ["connected"],
|
|
1556
1634
|
additionalProperties: false
|
|
1557
1635
|
}, validator);
|
|
1558
1636
|
server.registerTool(
|
|
@@ -1566,7 +1644,7 @@ function registerConnectTool(server, validator, store, identity) {
|
|
|
1566
1644
|
readOnlyHint: false,
|
|
1567
1645
|
idempotentHint: true,
|
|
1568
1646
|
destructiveHint: false,
|
|
1569
|
-
openWorldHint:
|
|
1647
|
+
openWorldHint: false
|
|
1570
1648
|
}
|
|
1571
1649
|
},
|
|
1572
1650
|
async () => {
|
|
@@ -1575,12 +1653,17 @@ function registerConnectTool(server, validator, store, identity) {
|
|
|
1575
1653
|
try {
|
|
1576
1654
|
const status = await store.connectStatus(identity.subject, identity.ownerDids);
|
|
1577
1655
|
code = status.connected ? "ok" : "authority_required";
|
|
1656
|
+
const visibleStatus = surface === "hosted" ? status : {
|
|
1657
|
+
connected: status.connected,
|
|
1658
|
+
...status.approvalUrl === void 0 ? {} : { approvalUrl: status.approvalUrl },
|
|
1659
|
+
...status.expiresAt === void 0 ? {} : { expiresAt: status.expiresAt }
|
|
1660
|
+
};
|
|
1578
1661
|
return {
|
|
1579
1662
|
content: [{
|
|
1580
1663
|
type: "text",
|
|
1581
1664
|
text: status.connected ? "TinyCloud is connected." : `TinyCloud approval is required. Open ${status.approvalUrl}, then call this tool again. This link expires at ${status.expiresAt}.`
|
|
1582
1665
|
}],
|
|
1583
|
-
structuredContent:
|
|
1666
|
+
structuredContent: visibleStatus
|
|
1584
1667
|
};
|
|
1585
1668
|
} finally {
|
|
1586
1669
|
logToolCall("tinycloud_connect", code, startedAt, 0);
|