mcp-google-multi 6.0.0-alpha.2 → 6.0.0-alpha.21
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 +5 -3
- package/dist/api-probe.d.ts +18 -0
- package/dist/api-probe.js +68 -0
- package/dist/arg-normalize.d.ts +19 -0
- package/dist/arg-normalize.js +90 -0
- package/dist/auth.js +15 -72
- package/dist/client.js +3 -1
- package/dist/discover.js +35 -14
- package/dist/discovery-client.d.ts +8 -1
- package/dist/discovery-client.js +67 -15
- package/dist/doctor.d.ts +12 -0
- package/dist/doctor.js +98 -15
- package/dist/http-transport.d.ts +3 -0
- package/dist/http-transport.js +2 -1
- package/dist/index.js +4 -1
- package/dist/oauth-consent.d.ts +25 -10
- package/dist/oauth-consent.js +85 -39
- package/dist/registry.d.ts +12 -0
- package/dist/registry.js +61 -3
- package/dist/scope-catalog.d.ts +1 -0
- package/dist/scope-catalog.js +17 -1
- package/dist/services.js +3 -1
- package/dist/tools/_errors.js +69 -5
- package/dist/tools/_local-files.d.ts +3 -0
- package/dist/tools/_local-files.js +34 -0
- package/dist/tools/account-wizard.d.ts +10 -0
- package/dist/tools/account-wizard.js +52 -19
- package/dist/tools/analytics.d.ts +18 -0
- package/dist/tools/analytics.js +279 -0
- package/dist/tools/drive.d.ts +2 -1
- package/dist/tools/drive.js +75 -33
- package/dist/tools/generated/_shared.d.ts +6 -0
- package/dist/tools/generated/_shared.js +11 -1
- package/dist/tools/generated/admin.js +160 -29
- package/dist/tools/generated/analytics.d.ts +2 -0
- package/dist/tools/generated/analytics.js +981 -0
- package/dist/tools/generated/chat.js +39 -12
- package/dist/tools/generated/classroom.js +56 -14
- package/dist/tools/generated/cloudidentity.js +18 -10
- package/dist/tools/generated/cloudsearch.js +4 -3
- package/dist/tools/generated/contacts.js +13 -4
- package/dist/tools/generated/drive.js +15 -6
- package/dist/tools/generated/drivelabels.js +33 -5
- package/dist/tools/generated/forms.js +1 -1
- package/dist/tools/generated/gmail.js +39 -12
- package/dist/tools/generated/index.js +2 -0
- package/dist/tools/generated/keep.js +3 -2
- package/dist/tools/generated/licensing.js +20 -4
- package/dist/tools/generated/meet.js +1 -1
- package/dist/tools/generated/reseller.js +8 -2
- package/dist/tools/generated/script.js +13 -3
- package/dist/tools/generated/searchconsole.js +4 -2
- package/dist/tools/generated/sheets.js +2 -1
- package/dist/tools/generated/tasks.js +7 -1
- package/dist/tools/generated/vault.js +18 -9
- package/dist/tools/generated/workspaceevents.js +3 -2
- package/dist/tools/gmail.js +3 -3
- package/dist/tools/google-api.d.ts +4 -1
- package/dist/tools/google-api.js +59 -15
- package/package.json +22 -17
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// GENERATED by scripts/gen-tools.ts — do not edit. Regenerate: npm run gen:tools
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { coerceJson } from '../_coerce.js';
|
|
4
3
|
import { accountField, registerGeneratedTool } from './_shared.js';
|
|
5
4
|
export function registerLicensingGeneratedTools(registry) {
|
|
6
5
|
// Interned method scope sets (shared across tools; see scope-observability).
|
|
@@ -44,11 +43,12 @@ export function registerLicensingGeneratedTools(registry) {
|
|
|
44
43
|
method: { id: "licensing.licenseAssignments.insert", httpMethod: "POST", path: "apps/licensing/v1/product/{productId}/sku/{skuId}/user", baseUrl: "https://licensing.googleapis.com/", requiredParams: ["productId", "skuId"], scopes: S_licensing_v1[0] },
|
|
45
44
|
params: [{ "field": "productId", "api": "productId", "location": "path" }, { "field": "skuId", "api": "skuId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
46
45
|
hasBody: true,
|
|
46
|
+
bodyParams: [{ "field": "userId", "api": "userId" }],
|
|
47
47
|
shape: {
|
|
48
48
|
account: accountField(),
|
|
49
49
|
productId: z.string().describe("A product's unique identifier. For more information about products in this version of the API, see Products and SKUs."),
|
|
50
50
|
skuId: z.string().describe("A product SKU's unique identifier. For more information about available SKUs in this version of the API, see Products and SKUs."),
|
|
51
|
-
|
|
51
|
+
userId: z.string().describe("Email id of the user"),
|
|
52
52
|
fields: z.string().optional().describe('Response field mask.'),
|
|
53
53
|
},
|
|
54
54
|
});
|
|
@@ -92,12 +92,20 @@ export function registerLicensingGeneratedTools(registry) {
|
|
|
92
92
|
method: { id: "licensing.licenseAssignments.patch", httpMethod: "PATCH", path: "apps/licensing/v1/product/{productId}/sku/{skuId}/user/{userId}", baseUrl: "https://licensing.googleapis.com/", requiredParams: ["productId", "skuId", "userId"], scopes: S_licensing_v1[0] },
|
|
93
93
|
params: [{ "field": "productId", "api": "productId", "location": "path" }, { "field": "skuId", "api": "skuId", "location": "path" }, { "field": "userId", "api": "userId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
94
94
|
hasBody: true,
|
|
95
|
+
bodyParams: [{ "field": "etags", "api": "etags" }, { "field": "kind", "api": "kind" }, { "field": "productId_", "api": "productId" }, { "field": "productName", "api": "productName" }, { "field": "selfLink", "api": "selfLink" }, { "field": "skuId_", "api": "skuId" }, { "field": "skuName", "api": "skuName" }, { "field": "userId_", "api": "userId" }],
|
|
95
96
|
shape: {
|
|
96
97
|
account: accountField(),
|
|
97
98
|
productId: z.string().describe("A product's unique identifier. For more information about products in this version of the API, see Products and SKUs."),
|
|
98
99
|
skuId: z.string().describe("A product SKU's unique identifier. For more information about available SKUs in this version of the API, see Products and SKUs."),
|
|
99
100
|
userId: z.string().describe("The user's current primary email address. If the user's email address changes, use the new email address in your API requests. Since a `userId` is subject to change, do not use a `userId` value as a k"),
|
|
100
|
-
|
|
101
|
+
etags: z.string().describe("ETag of the resource.").optional(),
|
|
102
|
+
kind: z.string().describe("Identifies the resource as a LicenseAssignment, which is `licensing#licenseAssignment`.").optional(),
|
|
103
|
+
productId_: z.string().describe("A product's unique identifier. For more information about products in this version of the API, see Product and SKU IDs.").optional(),
|
|
104
|
+
productName: z.string().describe("Display Name of the product.").optional(),
|
|
105
|
+
selfLink: z.string().describe("Link to this page.").optional(),
|
|
106
|
+
skuId_: z.string().describe("A product SKU's unique identifier. For more information about available SKUs in this version of the API, see Products and SKUs.").optional(),
|
|
107
|
+
skuName: z.string().describe("Display Name of the sku of the product.").optional(),
|
|
108
|
+
userId_: z.string().describe("The user's current primary email address. If the user's email address changes, use the new email address in your API requests. Since a `userId` is subject to change, do not use a `userId` value as a k").optional(),
|
|
101
109
|
fields: z.string().optional().describe('Response field mask.'),
|
|
102
110
|
},
|
|
103
111
|
});
|
|
@@ -108,12 +116,20 @@ export function registerLicensingGeneratedTools(registry) {
|
|
|
108
116
|
method: { id: "licensing.licenseAssignments.update", httpMethod: "PUT", path: "apps/licensing/v1/product/{productId}/sku/{skuId}/user/{userId}", baseUrl: "https://licensing.googleapis.com/", requiredParams: ["productId", "skuId", "userId"], scopes: S_licensing_v1[0] },
|
|
109
117
|
params: [{ "field": "productId", "api": "productId", "location": "path" }, { "field": "skuId", "api": "skuId", "location": "path" }, { "field": "userId", "api": "userId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
110
118
|
hasBody: true,
|
|
119
|
+
bodyParams: [{ "field": "productId_", "api": "productId" }, { "field": "skuId_", "api": "skuId" }, { "field": "userId_", "api": "userId" }, { "field": "etags", "api": "etags" }, { "field": "kind", "api": "kind" }, { "field": "productName", "api": "productName" }, { "field": "selfLink", "api": "selfLink" }, { "field": "skuName", "api": "skuName" }],
|
|
111
120
|
shape: {
|
|
112
121
|
account: accountField(),
|
|
113
122
|
productId: z.string().describe("A product's unique identifier. For more information about products in this version of the API, see Products and SKUs."),
|
|
114
123
|
skuId: z.string().describe("A product SKU's unique identifier. For more information about available SKUs in this version of the API, see Products and SKUs."),
|
|
115
124
|
userId: z.string().describe("The user's current primary email address. If the user's email address changes, use the new email address in your API requests. Since a `userId` is subject to change, do not use a `userId` value as a k"),
|
|
116
|
-
|
|
125
|
+
productId_: z.string().describe("A product's unique identifier. For more information about products in this version of the API, see Product and SKU IDs."),
|
|
126
|
+
skuId_: z.string().describe("A product SKU's unique identifier. For more information about available SKUs in this version of the API, see Products and SKUs."),
|
|
127
|
+
userId_: z.string().describe("The user's current primary email address. If the user's email address changes, use the new email address in your API requests. Since a `userId` is subject to change, do not use a `userId` value as a k"),
|
|
128
|
+
etags: z.string().describe("ETag of the resource.").optional(),
|
|
129
|
+
kind: z.string().describe("Identifies the resource as a LicenseAssignment, which is `licensing#licenseAssignment`.").optional(),
|
|
130
|
+
productName: z.string().describe("Display Name of the product.").optional(),
|
|
131
|
+
selfLink: z.string().describe("Link to this page.").optional(),
|
|
132
|
+
skuName: z.string().describe("Display Name of the sku of the product.").optional(),
|
|
117
133
|
fields: z.string().optional().describe('Response field mask.'),
|
|
118
134
|
},
|
|
119
135
|
});
|
|
@@ -155,10 +155,10 @@ export function registerMeetGeneratedTools(registry) {
|
|
|
155
155
|
method: { id: "meet.spaces.endActiveConference", httpMethod: "POST", path: "v2/{+name}:endActiveConference", baseUrl: "https://meet.googleapis.com/", requiredParams: ["name"], scopes: S_meet_v2[1] },
|
|
156
156
|
params: [{ "field": "name", "api": "name", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
157
157
|
hasBody: true,
|
|
158
|
+
bodyParams: [],
|
|
158
159
|
shape: {
|
|
159
160
|
account: accountField(),
|
|
160
161
|
name: z.string().describe("Required. Resource name of the space. Format: `spaces/{space}`. `{space}` is the resource identifier for the space. It's a unique, server-generated ID and is case sensitive. For example, `jQCFfuBOdN5z"),
|
|
161
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("EndActiveConferenceRequest JSON request body."),
|
|
162
162
|
fields: z.string().optional().describe('Response field mask.'),
|
|
163
163
|
},
|
|
164
164
|
});
|
|
@@ -137,11 +137,13 @@ export function registerResellerGeneratedTools(registry) {
|
|
|
137
137
|
method: { id: "reseller.subscriptions.changeRenewalSettings", httpMethod: "POST", path: "apps/reseller/v1/customers/{customerId}/subscriptions/{subscriptionId}/changeRenewalSettings", baseUrl: "https://reseller.googleapis.com/", requiredParams: ["customerId", "subscriptionId"], scopes: S_reseller_v1[1] },
|
|
138
138
|
params: [{ "field": "customerId", "api": "customerId", "location": "path" }, { "field": "subscriptionId", "api": "subscriptionId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
139
139
|
hasBody: true,
|
|
140
|
+
bodyParams: [{ "field": "kind", "api": "kind" }, { "field": "renewalType", "api": "renewalType" }],
|
|
140
141
|
shape: {
|
|
141
142
|
account: accountField(),
|
|
142
143
|
customerId: z.string().describe("This can be either the customer's primary domain name or the customer's unique identifier. If the domain name for a customer changes, the old domain name cannot be used to access the customer, but the"),
|
|
143
144
|
subscriptionId: z.string().describe("This is a required property. The `subscriptionId` is the subscription identifier and is unique for each customer. Since a `subscriptionId` changes when a subscription is updated, we recommend to not u"),
|
|
144
|
-
|
|
145
|
+
kind: z.string().describe("Identifies the resource as a subscription renewal setting. Value: `subscriptions#renewalSettings`").optional(),
|
|
146
|
+
renewalType: z.string().describe("Renewal settings for the annual commitment plan. For more detailed information, see renewal options in the administrator help center. When renewing a subscription, the `renewalType` is a required prop").optional(),
|
|
145
147
|
fields: z.string().optional().describe('Response field mask.'),
|
|
146
148
|
},
|
|
147
149
|
});
|
|
@@ -152,11 +154,15 @@ export function registerResellerGeneratedTools(registry) {
|
|
|
152
154
|
method: { id: "reseller.subscriptions.changeSeats", httpMethod: "POST", path: "apps/reseller/v1/customers/{customerId}/subscriptions/{subscriptionId}/changeSeats", baseUrl: "https://reseller.googleapis.com/", requiredParams: ["customerId", "subscriptionId"], scopes: S_reseller_v1[1] },
|
|
153
155
|
params: [{ "field": "customerId", "api": "customerId", "location": "path" }, { "field": "subscriptionId", "api": "subscriptionId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
154
156
|
hasBody: true,
|
|
157
|
+
bodyParams: [{ "field": "kind", "api": "kind" }, { "field": "licensedNumberOfSeats", "api": "licensedNumberOfSeats" }, { "field": "maximumNumberOfSeats", "api": "maximumNumberOfSeats" }, { "field": "numberOfSeats", "api": "numberOfSeats" }],
|
|
155
158
|
shape: {
|
|
156
159
|
account: accountField(),
|
|
157
160
|
customerId: z.string().describe("This can be either the customer's primary domain name or the customer's unique identifier. If the domain name for a customer changes, the old domain name cannot be used to access the customer, but the"),
|
|
158
161
|
subscriptionId: z.string().describe("This is a required property. The `subscriptionId` is the subscription identifier and is unique for each customer. Since a `subscriptionId` changes when a subscription is updated, we recommend to not u"),
|
|
159
|
-
|
|
162
|
+
kind: z.string().describe("Identifies the resource as a subscription seat setting. Value: `subscriptions#seats`").optional(),
|
|
163
|
+
licensedNumberOfSeats: z.number().describe("Read-only field containing the current number of users that are assigned a license for the product defined in `skuId`. This field's value is equivalent to the numerical count of users returned by the ").optional(),
|
|
164
|
+
maximumNumberOfSeats: z.number().describe("This is a required property and is exclusive to subscriptions with `FLEXIBLE` or `TRIAL` plans. This property sets the maximum number of licensed users allowed on a subscription. This quantity can be ").optional(),
|
|
165
|
+
numberOfSeats: z.number().describe("This is a required property and is exclusive to subscriptions with `ANNUAL_MONTHLY_PAY` and `ANNUAL_YEARLY_PAY` plans. This property sets the maximum number of licenses assignable to users on a subscr").optional(),
|
|
160
166
|
fields: z.string().optional().describe('Response field mask.'),
|
|
161
167
|
},
|
|
162
168
|
});
|
|
@@ -65,9 +65,11 @@ export function registerScriptGeneratedTools(registry) {
|
|
|
65
65
|
method: { id: "script.projects.create", httpMethod: "POST", path: "v1/projects", baseUrl: "https://script.googleapis.com/", requiredParams: [], scopes: S_script_v1[1] },
|
|
66
66
|
params: [{ "field": "fields", "api": "fields", "location": "query" }],
|
|
67
67
|
hasBody: true,
|
|
68
|
+
bodyParams: [{ "field": "parentId", "api": "parentId" }, { "field": "title", "api": "title" }],
|
|
68
69
|
shape: {
|
|
69
70
|
account: accountField(),
|
|
70
|
-
|
|
71
|
+
parentId: z.string().describe("The Drive ID of a parent file that the created script project is bound to. This is usually the ID of a Google Doc, Google Sheet, Google Form, or Google Slides file. If not set, a standalone script pro").optional(),
|
|
72
|
+
title: z.string().describe("The title for the project.").optional(),
|
|
71
73
|
fields: z.string().optional().describe('Response field mask.'),
|
|
72
74
|
},
|
|
73
75
|
});
|
|
@@ -78,10 +80,14 @@ export function registerScriptGeneratedTools(registry) {
|
|
|
78
80
|
method: { id: "script.projects.deployments.create", httpMethod: "POST", path: "v1/projects/{scriptId}/deployments", baseUrl: "https://script.googleapis.com/", requiredParams: ["scriptId"], scopes: S_script_v1[2] },
|
|
79
81
|
params: [{ "field": "scriptId", "api": "scriptId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
80
82
|
hasBody: true,
|
|
83
|
+
bodyParams: [{ "field": "description", "api": "description" }, { "field": "manifestFileName", "api": "manifestFileName" }, { "field": "scriptId_", "api": "scriptId" }, { "field": "versionNumber", "api": "versionNumber" }],
|
|
81
84
|
shape: {
|
|
82
85
|
account: accountField(),
|
|
83
86
|
scriptId: z.string().describe("The script project's Drive ID."),
|
|
84
|
-
|
|
87
|
+
description: z.string().describe("The description for this deployment.").optional(),
|
|
88
|
+
manifestFileName: z.string().describe("The manifest file name for this deployment.").optional(),
|
|
89
|
+
scriptId_: z.string().describe("The script project's Drive ID.").optional(),
|
|
90
|
+
versionNumber: z.number().describe("The version number on which this deployment is based.").optional(),
|
|
85
91
|
fields: z.string().optional().describe('Response field mask.'),
|
|
86
92
|
},
|
|
87
93
|
});
|
|
@@ -206,10 +212,14 @@ export function registerScriptGeneratedTools(registry) {
|
|
|
206
212
|
method: { id: "script.projects.versions.create", httpMethod: "POST", path: "v1/projects/{scriptId}/versions", baseUrl: "https://script.googleapis.com/", requiredParams: ["scriptId"], scopes: S_script_v1[1] },
|
|
207
213
|
params: [{ "field": "scriptId", "api": "scriptId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
208
214
|
hasBody: true,
|
|
215
|
+
bodyParams: [{ "field": "createTime", "api": "createTime" }, { "field": "description", "api": "description" }, { "field": "scriptId_", "api": "scriptId" }, { "field": "versionNumber", "api": "versionNumber" }],
|
|
209
216
|
shape: {
|
|
210
217
|
account: accountField(),
|
|
211
218
|
scriptId: z.string().describe("The script project's Drive ID."),
|
|
212
|
-
|
|
219
|
+
createTime: z.string().describe("When the version was created.").optional(),
|
|
220
|
+
description: z.string().describe("The description for this version.").optional(),
|
|
221
|
+
scriptId_: z.string().describe("The script project's Drive ID.").optional(),
|
|
222
|
+
versionNumber: z.number().describe("The incremental ID that is created by Apps Script when a version is created. This is system assigned number and is immutable once created.").optional(),
|
|
213
223
|
fields: z.string().optional().describe('Response field mask.'),
|
|
214
224
|
},
|
|
215
225
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GENERATED by scripts/gen-tools.ts — do not edit. Regenerate: npm run gen:tools
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { coerceBoolean } from '../_coerce.js';
|
|
4
4
|
import { accountField, registerGeneratedTool } from './_shared.js';
|
|
5
5
|
export function registerSearchconsoleGeneratedTools(registry) {
|
|
6
6
|
registerGeneratedTool(registry, {
|
|
@@ -10,9 +10,11 @@ export function registerSearchconsoleGeneratedTools(registry) {
|
|
|
10
10
|
method: { id: "searchconsole.urlTestingTools.mobileFriendlyTest.run", httpMethod: "POST", path: "v1/urlTestingTools/mobileFriendlyTest:run", baseUrl: "https://searchconsole.googleapis.com/", requiredParams: [] },
|
|
11
11
|
params: [{ "field": "fields", "api": "fields", "location": "query" }],
|
|
12
12
|
hasBody: true,
|
|
13
|
+
bodyParams: [{ "field": "requestScreenshot", "api": "requestScreenshot" }, { "field": "url", "api": "url" }],
|
|
13
14
|
shape: {
|
|
14
15
|
account: accountField(),
|
|
15
|
-
|
|
16
|
+
requestScreenshot: coerceBoolean.describe("Whether or not screenshot is requested. Default is false.").optional(),
|
|
17
|
+
url: z.string().describe("URL for inspection.").optional(),
|
|
16
18
|
fields: z.string().optional().describe('Response field mask.'),
|
|
17
19
|
},
|
|
18
20
|
});
|
|
@@ -56,11 +56,12 @@ export function registerSheetsGeneratedTools(registry) {
|
|
|
56
56
|
method: { id: "sheets.spreadsheets.sheets.copyTo", httpMethod: "POST", path: "v4/spreadsheets/{spreadsheetId}/sheets/{sheetId}:copyTo", baseUrl: "https://sheets.googleapis.com/", requiredParams: ["spreadsheetId", "sheetId"], scopes: S_sheets_v4[0] },
|
|
57
57
|
params: [{ "field": "sheetId", "api": "sheetId", "location": "path" }, { "field": "spreadsheetId", "api": "spreadsheetId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
58
58
|
hasBody: true,
|
|
59
|
+
bodyParams: [{ "field": "destinationSpreadsheetId", "api": "destinationSpreadsheetId" }],
|
|
59
60
|
shape: {
|
|
60
61
|
account: accountField(),
|
|
61
62
|
sheetId: z.number().describe("The ID of the sheet to copy."),
|
|
62
63
|
spreadsheetId: z.string().describe("The ID of the spreadsheet containing the sheet to copy."),
|
|
63
|
-
|
|
64
|
+
destinationSpreadsheetId: z.string().describe("The ID of the spreadsheet to copy the sheet to.").optional(),
|
|
64
65
|
fields: z.string().optional().describe('Response field mask.'),
|
|
65
66
|
},
|
|
66
67
|
});
|
|
@@ -14,10 +14,16 @@ export function registerTasksGeneratedTools(registry) {
|
|
|
14
14
|
method: { id: "tasks.tasklists.update", httpMethod: "PUT", path: "tasks/v1/users/@me/lists/{tasklist}", baseUrl: "https://tasks.googleapis.com/", requiredParams: ["tasklist"], scopes: S_tasks_v1[0] },
|
|
15
15
|
params: [{ "field": "tasklist", "api": "tasklist", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
16
16
|
hasBody: true,
|
|
17
|
+
bodyParams: [{ "field": "etag", "api": "etag" }, { "field": "id", "api": "id" }, { "field": "kind", "api": "kind" }, { "field": "selfLink", "api": "selfLink" }, { "field": "title", "api": "title" }, { "field": "updated", "api": "updated" }],
|
|
17
18
|
shape: {
|
|
18
19
|
account: accountField(),
|
|
19
20
|
tasklist: z.string().describe("Task list identifier."),
|
|
20
|
-
|
|
21
|
+
etag: z.string().describe("ETag of the resource.").optional(),
|
|
22
|
+
id: z.string().describe("Task list identifier.").optional(),
|
|
23
|
+
kind: z.string().describe("Output only. Type of the resource. This is always \"tasks#taskList\".").optional(),
|
|
24
|
+
selfLink: z.string().describe("Output only. URL pointing to this task list. Used to retrieve, update, or delete this task list.").optional(),
|
|
25
|
+
title: z.string().describe("Title of the task list. Maximum length allowed: 1024 characters.").optional(),
|
|
26
|
+
updated: z.string().describe("Output only. Last modification time of the task list (as a RFC 3339 timestamp).").optional(),
|
|
21
27
|
fields: z.string().optional().describe('Response field mask.'),
|
|
22
28
|
},
|
|
23
29
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// GENERATED by scripts/gen-tools.ts — do not edit. Regenerate: npm run gen:tools
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { coerceBoolean, coerceJson } from '../_coerce.js';
|
|
3
|
+
import { coerceArray, coerceBoolean, coerceJson } from '../_coerce.js';
|
|
4
4
|
import { accountField, registerGeneratedTool } from './_shared.js';
|
|
5
5
|
export function registerVaultGeneratedTools(registry) {
|
|
6
6
|
// Interned method scope sets (shared across tools; see scope-observability).
|
|
@@ -29,10 +29,10 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
29
29
|
method: { id: "vault.matters.close", httpMethod: "POST", path: "v1/matters/{matterId}:close", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId"], scopes: S_vault_v1[0] },
|
|
30
30
|
params: [{ "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
31
31
|
hasBody: true,
|
|
32
|
+
bodyParams: [],
|
|
32
33
|
shape: {
|
|
33
34
|
account: accountField(),
|
|
34
35
|
matterId: z.string().describe("The matter ID."),
|
|
35
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("CloseMatterRequest JSON request body."),
|
|
36
36
|
fields: z.string().optional().describe('Response field mask.'),
|
|
37
37
|
},
|
|
38
38
|
});
|
|
@@ -154,11 +154,16 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
154
154
|
method: { id: "vault.matters.holds.accounts.create", httpMethod: "POST", path: "v1/matters/{matterId}/holds/{holdId}/accounts", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId", "holdId"], scopes: S_vault_v1[0] },
|
|
155
155
|
params: [{ "field": "holdId", "api": "holdId", "location": "path" }, { "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
156
156
|
hasBody: true,
|
|
157
|
+
bodyParams: [{ "field": "accountId", "api": "accountId" }, { "field": "email", "api": "email" }, { "field": "firstName", "api": "firstName" }, { "field": "holdTime", "api": "holdTime" }, { "field": "lastName", "api": "lastName" }],
|
|
157
158
|
shape: {
|
|
158
159
|
account: accountField(),
|
|
159
160
|
holdId: z.string().describe("The hold ID."),
|
|
160
161
|
matterId: z.string().describe("The matter ID."),
|
|
161
|
-
|
|
162
|
+
accountId: z.string().describe("The account ID, as provided by the [Admin SDK](https://developers.google.com/admin-sdk/).").optional(),
|
|
163
|
+
email: z.string().describe("The primary email address of the account. If used as an input, this takes precedence over **accountId**.").optional(),
|
|
164
|
+
firstName: z.string().describe("Output only. The first name of the account holder.").optional(),
|
|
165
|
+
holdTime: z.string().describe("Output only. When the account was put on hold.").optional(),
|
|
166
|
+
lastName: z.string().describe("Output only. The last name of the account holder.").optional(),
|
|
162
167
|
fields: z.string().optional().describe('Response field mask.'),
|
|
163
168
|
},
|
|
164
169
|
});
|
|
@@ -198,11 +203,13 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
198
203
|
method: { id: "vault.matters.holds.addHeldAccounts", httpMethod: "POST", path: "v1/matters/{matterId}/holds/{holdId}:addHeldAccounts", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId", "holdId"], scopes: S_vault_v1[0] },
|
|
199
204
|
params: [{ "field": "holdId", "api": "holdId", "location": "path" }, { "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
200
205
|
hasBody: true,
|
|
206
|
+
bodyParams: [{ "field": "accountIds", "api": "accountIds" }, { "field": "emails", "api": "emails" }],
|
|
201
207
|
shape: {
|
|
202
208
|
account: accountField(),
|
|
203
209
|
holdId: z.string().describe("The hold ID."),
|
|
204
210
|
matterId: z.string().describe("The matter ID."),
|
|
205
|
-
|
|
211
|
+
accountIds: coerceArray(z.string()).describe("A comma-separated list of the account IDs of the accounts to add to the hold. Specify either **emails** or **account_ids**, but not both.").optional(),
|
|
212
|
+
emails: coerceArray(z.string()).describe("A comma-separated list of the emails of the accounts to add to the hold. Specify either **emails** or **account_ids**, but not both.").optional(),
|
|
206
213
|
fields: z.string().optional().describe('Response field mask.'),
|
|
207
214
|
},
|
|
208
215
|
});
|
|
@@ -272,11 +279,12 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
272
279
|
method: { id: "vault.matters.holds.removeHeldAccounts", httpMethod: "POST", path: "v1/matters/{matterId}/holds/{holdId}:removeHeldAccounts", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId", "holdId"], scopes: S_vault_v1[0] },
|
|
273
280
|
params: [{ "field": "holdId", "api": "holdId", "location": "path" }, { "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
274
281
|
hasBody: true,
|
|
282
|
+
bodyParams: [{ "field": "accountIds", "api": "accountIds" }],
|
|
275
283
|
shape: {
|
|
276
284
|
account: accountField(),
|
|
277
285
|
holdId: z.string().describe("The hold ID."),
|
|
278
286
|
matterId: z.string().describe("The matter ID."),
|
|
279
|
-
|
|
287
|
+
accountIds: coerceArray(z.string()).describe("The account IDs of the accounts to remove from the hold.").optional(),
|
|
280
288
|
fields: z.string().optional().describe('Response field mask.'),
|
|
281
289
|
},
|
|
282
290
|
});
|
|
@@ -318,10 +326,11 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
318
326
|
method: { id: "vault.matters.removePermissions", httpMethod: "POST", path: "v1/matters/{matterId}:removePermissions", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId"], scopes: S_vault_v1[0] },
|
|
319
327
|
params: [{ "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
320
328
|
hasBody: true,
|
|
329
|
+
bodyParams: [{ "field": "accountId", "api": "accountId" }],
|
|
321
330
|
shape: {
|
|
322
331
|
account: accountField(),
|
|
323
332
|
matterId: z.string().describe("The matter ID."),
|
|
324
|
-
|
|
333
|
+
accountId: z.string().describe("The account ID.").optional(),
|
|
325
334
|
fields: z.string().optional().describe('Response field mask.'),
|
|
326
335
|
},
|
|
327
336
|
});
|
|
@@ -332,10 +341,10 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
332
341
|
method: { id: "vault.matters.reopen", httpMethod: "POST", path: "v1/matters/{matterId}:reopen", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId"], scopes: S_vault_v1[0] },
|
|
333
342
|
params: [{ "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
334
343
|
hasBody: true,
|
|
344
|
+
bodyParams: [],
|
|
335
345
|
shape: {
|
|
336
346
|
account: accountField(),
|
|
337
347
|
matterId: z.string().describe("The matter ID."),
|
|
338
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("ReopenMatterRequest JSON request body."),
|
|
339
348
|
fields: z.string().optional().describe('Response field mask.'),
|
|
340
349
|
},
|
|
341
350
|
});
|
|
@@ -403,10 +412,10 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
403
412
|
method: { id: "vault.matters.undelete", httpMethod: "POST", path: "v1/matters/{matterId}:undelete", baseUrl: "https://vault.googleapis.com/", requiredParams: ["matterId"], scopes: S_vault_v1[0] },
|
|
404
413
|
params: [{ "field": "matterId", "api": "matterId", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
405
414
|
hasBody: true,
|
|
415
|
+
bodyParams: [],
|
|
406
416
|
shape: {
|
|
407
417
|
account: accountField(),
|
|
408
418
|
matterId: z.string().describe("The matter ID."),
|
|
409
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("UndeleteMatterRequest JSON request body."),
|
|
410
419
|
fields: z.string().optional().describe('Response field mask.'),
|
|
411
420
|
},
|
|
412
421
|
});
|
|
@@ -431,10 +440,10 @@ export function registerVaultGeneratedTools(registry) {
|
|
|
431
440
|
method: { id: "vault.operations.cancel", httpMethod: "POST", path: "v1/{+name}:cancel", baseUrl: "https://vault.googleapis.com/", requiredParams: ["name"], scopes: S_vault_v1[0] },
|
|
432
441
|
params: [{ "field": "name", "api": "name", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
433
442
|
hasBody: true,
|
|
443
|
+
bodyParams: [],
|
|
434
444
|
shape: {
|
|
435
445
|
account: accountField(),
|
|
436
446
|
name: z.string().describe("The name of the operation resource to be cancelled."),
|
|
437
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("CancelOperationRequest JSON request body."),
|
|
438
447
|
fields: z.string().optional().describe('Response field mask.'),
|
|
439
448
|
},
|
|
440
449
|
});
|
|
@@ -115,10 +115,10 @@ export function registerWorkspaceeventsGeneratedTools(registry) {
|
|
|
115
115
|
method: { id: "workspaceevents.subscriptions.reactivate", httpMethod: "POST", path: "v1/{+name}:reactivate", baseUrl: "https://workspaceevents.googleapis.com/", requiredParams: ["name"], scopes: S_workspaceevents_v1[1] },
|
|
116
116
|
params: [{ "field": "name", "api": "name", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
117
117
|
hasBody: true,
|
|
118
|
+
bodyParams: [],
|
|
118
119
|
shape: {
|
|
119
120
|
account: accountField(),
|
|
120
121
|
name: z.string().describe("Required. Resource name of the subscription. Format: `subscriptions/{subscription}`"),
|
|
121
|
-
body: coerceJson(z.record(z.string(), z.unknown())).describe("ReactivateSubscriptionRequest JSON request body."),
|
|
122
122
|
fields: z.string().optional().describe('Response field mask.'),
|
|
123
123
|
},
|
|
124
124
|
});
|
|
@@ -129,10 +129,11 @@ export function registerWorkspaceeventsGeneratedTools(registry) {
|
|
|
129
129
|
method: { id: "workspaceevents.tasks.cancel", httpMethod: "POST", path: "v1/{+name}:cancel", baseUrl: "https://workspaceevents.googleapis.com/", requiredParams: ["name"] },
|
|
130
130
|
params: [{ "field": "name", "api": "name", "location": "path" }, { "field": "fields", "api": "fields", "location": "query" }],
|
|
131
131
|
hasBody: true,
|
|
132
|
+
bodyParams: [{ "field": "tenant", "api": "tenant" }],
|
|
132
133
|
shape: {
|
|
133
134
|
account: accountField(),
|
|
134
135
|
name: z.string().describe("The resource name of the task to cancel. Format: tasks/{task_id}"),
|
|
135
|
-
|
|
136
|
+
tenant: z.string().describe("Optional tenant, provided as a path parameter. Experimental, might still change for 1.0 release.").optional(),
|
|
136
137
|
fields: z.string().optional().describe('Response field mask.'),
|
|
137
138
|
},
|
|
138
139
|
});
|
package/dist/tools/gmail.js
CHANGED
|
@@ -5,6 +5,7 @@ import { accountAliasSchema } from '../accounts.js';
|
|
|
5
5
|
import { getClient } from '../client.js';
|
|
6
6
|
import { handleGoogleApiError, mapGoogleError } from './_errors.js';
|
|
7
7
|
import { buildReplyHeaders, composeRaw, renderMarkdown, htmlToMarkdown, HeaderInjectionError } from './gmail-mime.js';
|
|
8
|
+
import { prepareLocalDest } from './_local-files.js';
|
|
8
9
|
import addressparser from 'nodemailer/lib/addressparser/index.js';
|
|
9
10
|
import { lookup as lookupMime } from 'mime-types';
|
|
10
11
|
import { configDir } from '../config-file.js';
|
|
@@ -664,7 +665,7 @@ export function registerGmailTools(server) {
|
|
|
664
665
|
messageId: z.string().describe('The Gmail message ID'),
|
|
665
666
|
attachmentId: z.string().describe('The attachment ID from gmail_read response'),
|
|
666
667
|
filename: z.string().describe('Filename to save as (e.g. report.xlsx)'),
|
|
667
|
-
savePath: z.string().describe('Absolute
|
|
668
|
+
savePath: z.string().describe('Absolute DIRECTORY path to save into (created if missing, on the machine running the server), e.g. /home/user/Downloads; the file name comes from `filename`'),
|
|
668
669
|
},
|
|
669
670
|
}, async ({ account, messageId, attachmentId, filename, savePath }) => {
|
|
670
671
|
try {
|
|
@@ -679,8 +680,7 @@ export function registerGmailTools(server) {
|
|
|
679
680
|
if (!data)
|
|
680
681
|
throw new Error('No attachment data returned');
|
|
681
682
|
const buffer = Buffer.from(data, 'base64url');
|
|
682
|
-
|
|
683
|
-
const fullPath = path.join(savePath, path.basename(filename));
|
|
683
|
+
const fullPath = prepareLocalDest(savePath, filename);
|
|
684
684
|
await fs.promises.writeFile(fullPath, buffer, { mode: 0o600 });
|
|
685
685
|
return {
|
|
686
686
|
content: [{ type: 'text', text: `Saved to ${fullPath} (${buffer.length} bytes)` }],
|
|
@@ -2,9 +2,12 @@ import type { ToolRegistry } from '../registry.js';
|
|
|
2
2
|
import { type Policy } from '../write-control.js';
|
|
3
3
|
import { getClient } from '../client.js';
|
|
4
4
|
import { type Toolsets } from '../toolsets.js';
|
|
5
|
-
import { type DiscoveryDeps } from '../discovery-client.js';
|
|
5
|
+
import { type DiscoveryDeps, type DiscoveryMethod } from '../discovery-client.js';
|
|
6
6
|
export interface EscapeDeps extends DiscoveryDeps {
|
|
7
7
|
getClientFn?: typeof getClient;
|
|
8
8
|
toolsets?: Toolsets;
|
|
9
9
|
}
|
|
10
|
+
/** Up to three closest known ids for the unknown_method did-you-mean hint;
|
|
11
|
+
* bounded distance so unrelated ids never masquerade as suggestions. */
|
|
12
|
+
export declare function nearestMethodIds(methodId: string, index: DiscoveryMethod[]): string[];
|
|
10
13
|
export declare function registerEscapeTools(registry: ToolRegistry, policy: Policy, deps?: EscapeDeps): void;
|
package/dist/tools/google-api.js
CHANGED
|
@@ -4,8 +4,9 @@ import { accountAliasSchema } from '../accounts.js';
|
|
|
4
4
|
import { getClient } from '../client.js';
|
|
5
5
|
import { coerceJson } from './_coerce.js';
|
|
6
6
|
import { getToolsets, toolsetEnabled } from '../toolsets.js';
|
|
7
|
+
import { editDistance } from '../scope-catalog.js';
|
|
7
8
|
import { executeApiMethod, jsonResult } from '../executor.js';
|
|
8
|
-
import {
|
|
9
|
+
import { SUPPORTED_APIS, resolveApiAliases, cudFromMethod, loadMethodIndex, searchMethods, } from '../discovery-client.js';
|
|
9
10
|
const accountEnum = accountAliasSchema.optional();
|
|
10
11
|
// Policy/toolset namespace for each API alias must match the NAMED tools' service
|
|
11
12
|
// names, or user deny globs and GOOGLE_TOOLSETS silently miss escape-hatch calls.
|
|
@@ -28,7 +29,20 @@ const SERVICE_FOR_ALIAS = {
|
|
|
28
29
|
admin_reports: 'admin',
|
|
29
30
|
admin_datatransfer: 'admin',
|
|
30
31
|
groupssettings: 'groupssettings',
|
|
32
|
+
analyticsadmin: 'analytics',
|
|
33
|
+
analyticsdata: 'analytics',
|
|
31
34
|
};
|
|
35
|
+
/** Up to three closest known ids for the unknown_method did-you-mean hint;
|
|
36
|
+
* bounded distance so unrelated ids never masquerade as suggestions. */
|
|
37
|
+
export function nearestMethodIds(methodId, index) {
|
|
38
|
+
const maxDist = Math.max(3, Math.floor(methodId.length / 3));
|
|
39
|
+
return index
|
|
40
|
+
.map((m) => ({ id: m.id, d: editDistance(methodId.toLowerCase(), m.id.toLowerCase()) }))
|
|
41
|
+
.filter((x) => x.d <= maxDist)
|
|
42
|
+
.sort((a, b) => a.d - b.d)
|
|
43
|
+
.slice(0, 3)
|
|
44
|
+
.map((x) => x.id);
|
|
45
|
+
}
|
|
32
46
|
function describeMethod(m) {
|
|
33
47
|
return {
|
|
34
48
|
api: m.api,
|
|
@@ -47,7 +61,7 @@ export function registerEscapeTools(registry, policy, deps = {}) {
|
|
|
47
61
|
const apiEnabled = (alias) => {
|
|
48
62
|
return toolsetEnabled(toolsets, serviceForAlias(alias));
|
|
49
63
|
};
|
|
50
|
-
const enabledApis = Object.keys(
|
|
64
|
+
const enabledApis = Object.keys(SUPPORTED_APIS).filter(apiEnabled);
|
|
51
65
|
const apiList = enabledApis.join(', ');
|
|
52
66
|
const toolsetDisabled = (alias) => jsonResult({
|
|
53
67
|
error: 'toolset_disabled',
|
|
@@ -66,12 +80,20 @@ export function registerEscapeTools(registry, policy, deps = {}) {
|
|
|
66
80
|
},
|
|
67
81
|
annotations: { openWorldHint: true },
|
|
68
82
|
}, async ({ query, api, maxResults }) => {
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
// Alias resolution: "analytics" fans out to both GA4 Discovery APIs
|
|
84
|
+
// instead of dead-ending on unknown_api.
|
|
85
|
+
let requested = null;
|
|
86
|
+
if (api) {
|
|
87
|
+
requested = resolveApiAliases(api);
|
|
88
|
+
if (!requested) {
|
|
89
|
+
return jsonResult({ error: 'unknown_api', message: `Unknown api "${api}".`, hint: `Known APIs: ${apiList}`, retriable: false }, true);
|
|
90
|
+
}
|
|
91
|
+
const enabled = requested.filter(apiEnabled);
|
|
92
|
+
if (enabled.length === 0)
|
|
93
|
+
return toolsetDisabled(requested[0]);
|
|
94
|
+
requested = enabled;
|
|
71
95
|
}
|
|
72
|
-
|
|
73
|
-
return toolsetDisabled(api);
|
|
74
|
-
const apis = api ? [api] : enabledApis;
|
|
96
|
+
const apis = requested ?? enabledApis;
|
|
75
97
|
const unavailable = [];
|
|
76
98
|
const indexes = await Promise.all(apis.map(async (a) => {
|
|
77
99
|
try {
|
|
@@ -84,6 +106,9 @@ export function registerEscapeTools(registry, policy, deps = {}) {
|
|
|
84
106
|
}));
|
|
85
107
|
const matches = searchMethods(indexes.flat(), query, maxResults ?? 10);
|
|
86
108
|
return jsonResult({
|
|
109
|
+
// Teach the resolved keys whenever the input wasn't already one, so the
|
|
110
|
+
// follow-up google_api_call uses a real key.
|
|
111
|
+
...(requested && (requested.length > 1 || requested[0] !== api) ? { resolvedApi: requested } : {}),
|
|
87
112
|
methods: matches.map(describeMethod),
|
|
88
113
|
...(unavailable.length > 0 ? { unavailableApis: unavailable } : {}),
|
|
89
114
|
next: 'Invoke with google_api_call({account, api, methodId, pathParams, queryParams, body}).',
|
|
@@ -115,30 +140,49 @@ export function registerEscapeTools(registry, policy, deps = {}) {
|
|
|
115
140
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
116
141
|
_meta: { 'anthropic/maxResultSizeChars': 100_000 },
|
|
117
142
|
}, async ({ account, api, methodId, pathParams, queryParams, body }) => {
|
|
118
|
-
|
|
143
|
+
const resolved = resolveApiAliases(api);
|
|
144
|
+
if (!resolved) {
|
|
119
145
|
return jsonResult({ error: 'unknown_api', message: `Unknown api "${api}".`, hint: `Known APIs: ${apiList}`, retriable: false, account }, true);
|
|
120
146
|
}
|
|
121
|
-
if (
|
|
122
|
-
|
|
147
|
+
if (resolved.length > 1) {
|
|
148
|
+
// A call targets exactly one Discovery doc; only search can fan out.
|
|
149
|
+
return jsonResult({ error: 'unknown_api', message: `"${api}" maps to ${resolved.length} APIs.`, hint: `Pass one of: ${resolved.join(', ')} (method ids differ per API; google_api_search({query, api: "${api}"}) finds the right one).`, retriable: false, account }, true);
|
|
150
|
+
}
|
|
151
|
+
const apiKey = resolved[0];
|
|
152
|
+
if (!apiEnabled(apiKey))
|
|
153
|
+
return toolsetDisabled(apiKey);
|
|
123
154
|
let index;
|
|
124
155
|
try {
|
|
125
|
-
index = await loadMethodIndex(
|
|
156
|
+
index = await loadMethodIndex(apiKey, deps);
|
|
126
157
|
}
|
|
127
158
|
catch (err) {
|
|
128
159
|
return jsonResult({ error: 'discovery_unavailable', message: err.message, retriable: true, account }, true);
|
|
129
160
|
}
|
|
130
|
-
|
|
161
|
+
let method = index.find((m) => m.id === methodId);
|
|
162
|
+
if (!method) {
|
|
163
|
+
// Some discovery docs keep a legacy id prefix (the searchconsole doc's
|
|
164
|
+
// methods are webmasters.*): when the caller prefixed with our api
|
|
165
|
+
// alias, retry under the doc's own prefix before failing.
|
|
166
|
+
const docPrefix = index[0]?.id.split('.')[0];
|
|
167
|
+
const [head, ...rest] = String(methodId).split('.');
|
|
168
|
+
if (docPrefix && (head === apiKey || head === api) && head !== docPrefix && rest.length > 0) {
|
|
169
|
+
const swapped = [docPrefix, ...rest].join('.');
|
|
170
|
+
method = index.find((m) => m.id === swapped);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
131
173
|
if (!method) {
|
|
174
|
+
const near = nearestMethodIds(String(methodId), index);
|
|
132
175
|
return jsonResult({
|
|
133
176
|
error: 'unknown_method',
|
|
134
|
-
message: `No method "${methodId}" in ${
|
|
135
|
-
hint: `
|
|
177
|
+
message: `No method "${methodId}" in ${apiKey}.`,
|
|
178
|
+
hint: `${near.length ? `Did you mean: ${near.join(', ')}? ` : ''}` +
|
|
179
|
+
`Use google_api_search({query: "...", api: "${apiKey}"}) to find the right method id.`,
|
|
136
180
|
retriable: false,
|
|
137
181
|
account,
|
|
138
182
|
}, true);
|
|
139
183
|
}
|
|
140
184
|
const cud = cudFromMethod(method);
|
|
141
|
-
const policyService = serviceForAlias(
|
|
185
|
+
const policyService = serviceForAlias(apiKey);
|
|
142
186
|
const lastSegment = method.id.split('.').pop() ?? method.id;
|
|
143
187
|
const toolRef = { name: `${policyService}_${lastSegment}`, service: policyService, cud };
|
|
144
188
|
if (cud !== 'read' && !isAllowed(toolRef, policy)) {
|