firebase-tools 15.22.0 → 15.22.2
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/lib/apiv2.js +48 -1
- package/lib/deploy/functions/services/authEventarc.js +13 -0
- package/lib/deploy/functions/services/index.js +13 -0
- package/lib/emulator/downloadableEmulatorInfo.json +24 -24
- package/lib/env.js +10 -3
- package/lib/extensions/checkProjectBilling.js +2 -2
- package/lib/functions/events/v2.js +5 -1
- package/lib/gcp/cloudbilling.js +42 -9
- package/lib/mcp/index.js +4 -1
- package/lib/mcp/tool.js +5 -2
- package/lib/mcp/tools/apphosting/fetch_logs.js +1 -1
- package/lib/mcp/tools/apphosting/list_backends.js +1 -1
- package/lib/tsconfig.compile.tsbuildinfo +1 -1
- package/lib/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +2 -3
package/lib/apiv2.js
CHANGED
|
@@ -10,6 +10,8 @@ const proxy_agent_1 = require("proxy-agent");
|
|
|
10
10
|
const retry = require("retry");
|
|
11
11
|
const abort_controller_1 = require("abort-controller");
|
|
12
12
|
const node_fetch_1 = require("node-fetch");
|
|
13
|
+
const http = require("http");
|
|
14
|
+
const https = require("https");
|
|
13
15
|
const util_1 = require("util");
|
|
14
16
|
const auth = require("./auth");
|
|
15
17
|
const error_1 = require("./error");
|
|
@@ -59,6 +61,28 @@ function proxyURIFromEnv() {
|
|
|
59
61
|
process.env.http_proxy ||
|
|
60
62
|
undefined);
|
|
61
63
|
}
|
|
64
|
+
const httpAgentNoKeepAlive = new http.Agent({ keepAlive: false });
|
|
65
|
+
const httpsAgentNoKeepAlive = new https.Agent({ keepAlive: false });
|
|
66
|
+
function noKeepAliveAgent(parsedURL) {
|
|
67
|
+
return parsedURL.protocol === "https:" ? httpsAgentNoKeepAlive : httpAgentNoKeepAlive;
|
|
68
|
+
}
|
|
69
|
+
function isPrematureCloseError(err) {
|
|
70
|
+
for (const candidate of [err, err?.original]) {
|
|
71
|
+
if (!candidate) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const e = candidate;
|
|
75
|
+
const code = e.code || e.errno;
|
|
76
|
+
const message = typeof e.message === "string" ? e.message : "";
|
|
77
|
+
if (code === "ERR_STREAM_PREMATURE_CLOSE" ||
|
|
78
|
+
code === "ECONNRESET" ||
|
|
79
|
+
/premature close/i.test(message) ||
|
|
80
|
+
/socket hang up/i.test(message)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
62
86
|
class Client {
|
|
63
87
|
constructor(opts) {
|
|
64
88
|
this.opts = opts;
|
|
@@ -237,9 +261,17 @@ class Client {
|
|
|
237
261
|
};
|
|
238
262
|
fetchOptions.signal = signal;
|
|
239
263
|
}
|
|
240
|
-
|
|
264
|
+
let bodyReplayable = true;
|
|
265
|
+
if (typeof options.body === "string" || Buffer.isBuffer(options.body)) {
|
|
241
266
|
fetchOptions.body = options.body;
|
|
242
267
|
}
|
|
268
|
+
else if (options.body instanceof FormData) {
|
|
269
|
+
fetchOptions.body = options.body.getBuffer();
|
|
270
|
+
}
|
|
271
|
+
else if (isStream(options.body)) {
|
|
272
|
+
fetchOptions.body = options.body;
|
|
273
|
+
bodyReplayable = false;
|
|
274
|
+
}
|
|
243
275
|
else if (options.body !== undefined) {
|
|
244
276
|
fetchOptions.body = JSON.stringify(options.body);
|
|
245
277
|
}
|
|
@@ -258,6 +290,7 @@ class Client {
|
|
|
258
290
|
operationOptions.maxTimeout = options.retryMaxTimeout;
|
|
259
291
|
}
|
|
260
292
|
const operation = retry.operation(operationOptions);
|
|
293
|
+
let disabledKeepAlive = false;
|
|
261
294
|
return await new Promise((resolve, reject) => {
|
|
262
295
|
operation.attempt(async (currentAttempt) => {
|
|
263
296
|
let res;
|
|
@@ -314,6 +347,20 @@ class Client {
|
|
|
314
347
|
}
|
|
315
348
|
}
|
|
316
349
|
catch (err) {
|
|
350
|
+
if (!disabledKeepAlive &&
|
|
351
|
+
bodyReplayable &&
|
|
352
|
+
!proxyURIFromEnv() &&
|
|
353
|
+
isPrematureCloseError(err)) {
|
|
354
|
+
disabledKeepAlive = true;
|
|
355
|
+
fetchOptions.agent = noKeepAliveAgent;
|
|
356
|
+
const closeHeaders = new node_fetch_1.Headers(fetchOptions.headers);
|
|
357
|
+
closeHeaders.set("Connection", "close");
|
|
358
|
+
fetchOptions.headers = closeHeaders;
|
|
359
|
+
logger_1.logger.debug(`*** [apiv2] retrying ${fetchURL} without keep-alive after a premature close error`);
|
|
360
|
+
if (operation.retry(err instanceof Error ? err : new Error(`${err}`))) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
317
364
|
return err instanceof error_1.FirebaseError ? reject(err) : reject(new error_1.FirebaseError(`${err}`));
|
|
318
365
|
}
|
|
319
366
|
this.logResponse(res, body, options);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ensureAuthEventarcTriggerRegion = ensureAuthEventarcTriggerRegion;
|
|
4
|
+
const error_1 = require("../../../error");
|
|
5
|
+
function ensureAuthEventarcTriggerRegion(endpoint) {
|
|
6
|
+
if (!endpoint.eventTrigger.region) {
|
|
7
|
+
endpoint.eventTrigger.region = "global";
|
|
8
|
+
}
|
|
9
|
+
if (endpoint.eventTrigger.region !== "global") {
|
|
10
|
+
throw new error_1.FirebaseError("A Firebase Auth Eventarc trigger must specify 'global' trigger location");
|
|
11
|
+
}
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
}
|
|
@@ -11,6 +11,7 @@ const testLab_1 = require("./testLab");
|
|
|
11
11
|
const firestore_1 = require("./firestore");
|
|
12
12
|
const dataconnect_1 = require("./dataconnect");
|
|
13
13
|
const ailogic_1 = require("./ailogic");
|
|
14
|
+
const authEventarc_1 = require("./authEventarc");
|
|
14
15
|
const noop = () => Promise.resolve();
|
|
15
16
|
exports.noop = noop;
|
|
16
17
|
const noopProjectBindings = () => Promise.resolve([]);
|
|
@@ -108,6 +109,16 @@ const dataconnectService = {
|
|
|
108
109
|
unregisterTrigger: exports.noop,
|
|
109
110
|
getDefaultRegion: dataconnect_1.getDefaultRegion,
|
|
110
111
|
};
|
|
112
|
+
const authEventarcService = {
|
|
113
|
+
name: "autheventarc",
|
|
114
|
+
api: "eventarc.googleapis.com",
|
|
115
|
+
requiredProjectBindings: exports.noopProjectBindings,
|
|
116
|
+
ensureTriggerRegion: authEventarc_1.ensureAuthEventarcTriggerRegion,
|
|
117
|
+
validateTrigger: exports.noop,
|
|
118
|
+
registerTrigger: exports.noop,
|
|
119
|
+
unregisterTrigger: exports.noop,
|
|
120
|
+
getDefaultRegion: () => Promise.resolve(exports.DEFAULT_GLOBAL_TRIGGER_REGION),
|
|
121
|
+
};
|
|
111
122
|
const EVENT_SERVICE_MAPPING = {
|
|
112
123
|
"google.cloud.pubsub.topic.v1.messagePublished": pubSubService,
|
|
113
124
|
"google.cloud.storage.object.v1.finalized": storageService,
|
|
@@ -136,6 +147,8 @@ const EVENT_SERVICE_MAPPING = {
|
|
|
136
147
|
"google.firebase.dataconnect.connector.v1.mutationExecuted": dataconnectService,
|
|
137
148
|
"google.firebase.ailogic.v1.beforeGenerate": aiLogicService,
|
|
138
149
|
"google.firebase.ailogic.v1.afterGenerate": aiLogicService,
|
|
150
|
+
"google.firebase.auth.user.v2.created": authEventarcService,
|
|
151
|
+
"google.firebase.auth.user.v2.deleted": authEventarcService,
|
|
139
152
|
};
|
|
140
153
|
function serviceForEndpoint(endpoint) {
|
|
141
154
|
let eventType;
|
|
@@ -54,36 +54,36 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dataconnect": {
|
|
56
56
|
"darwin": {
|
|
57
|
-
"version": "3.4.
|
|
58
|
-
"expectedSize":
|
|
59
|
-
"expectedChecksum": "
|
|
60
|
-
"expectedChecksumSHA256": "
|
|
61
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.
|
|
62
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
57
|
+
"version": "3.4.14",
|
|
58
|
+
"expectedSize": 32468976,
|
|
59
|
+
"expectedChecksum": "d62fc079187a1adc2ceef7dc0e1a1e44",
|
|
60
|
+
"expectedChecksumSHA256": "4bbf0ae04ca83dcc765804549d30f94d02c7a8b6baeef5f3c52104e771627e43",
|
|
61
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-amd64-v3.4.14",
|
|
62
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.14"
|
|
63
63
|
},
|
|
64
64
|
"darwin_arm64": {
|
|
65
|
-
"version": "3.4.
|
|
66
|
-
"expectedSize":
|
|
67
|
-
"expectedChecksum": "
|
|
68
|
-
"expectedChecksumSHA256": "
|
|
69
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.
|
|
70
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
65
|
+
"version": "3.4.14",
|
|
66
|
+
"expectedSize": 30604754,
|
|
67
|
+
"expectedChecksum": "306e88ebe314eec82ae44842aa87d20e",
|
|
68
|
+
"expectedChecksumSHA256": "3eeaf0dbfd48d3d7cf761e256e8850bc6159dccc128dd59f87bbeeaaaa6a62c6",
|
|
69
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-macos-arm64-v3.4.14",
|
|
70
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.14"
|
|
71
71
|
},
|
|
72
72
|
"win32": {
|
|
73
|
-
"version": "3.4.
|
|
74
|
-
"expectedSize":
|
|
75
|
-
"expectedChecksum": "
|
|
76
|
-
"expectedChecksumSHA256": "
|
|
77
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.
|
|
78
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
73
|
+
"version": "3.4.14",
|
|
74
|
+
"expectedSize": 32509952,
|
|
75
|
+
"expectedChecksum": "c5cbd9482be394bf466d4328b975d88e",
|
|
76
|
+
"expectedChecksumSHA256": "b9f14587c5d5f87bccd093e1dddc9f5bb2a77be007201028d9ee8339e79219f0",
|
|
77
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-windows-amd64-v3.4.14",
|
|
78
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.14.exe"
|
|
79
79
|
},
|
|
80
80
|
"linux": {
|
|
81
|
-
"version": "3.4.
|
|
82
|
-
"expectedSize":
|
|
83
|
-
"expectedChecksum": "
|
|
84
|
-
"expectedChecksumSHA256": "
|
|
85
|
-
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.
|
|
86
|
-
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.
|
|
81
|
+
"version": "3.4.14",
|
|
82
|
+
"expectedSize": 31625400,
|
|
83
|
+
"expectedChecksum": "506a09ca12b61df98f705728047219dd",
|
|
84
|
+
"expectedChecksumSHA256": "257d7aa4f4dd1e4de9c9d3db9f7b7834323f0d53e658e6814a933b1ec73ca27d",
|
|
85
|
+
"remoteUrl": "https://storage.googleapis.com/firemat-preview-drop/emulator/dataconnect-emulator-linux-amd64-v3.4.14",
|
|
86
|
+
"downloadPathRelativeToCacheDir": "dataconnect-emulator-3.4.14"
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
package/lib/env.js
CHANGED
|
@@ -16,14 +16,21 @@ function isFirebaseStudio() {
|
|
|
16
16
|
}
|
|
17
17
|
let isFirebaseMcpFlag = false;
|
|
18
18
|
function isFirebaseMcp() {
|
|
19
|
-
return isFirebaseMcpFlag;
|
|
19
|
+
return isFirebaseMcpFlag || process.env.IS_FIREBASE_MCP === "true";
|
|
20
20
|
}
|
|
21
21
|
function setFirebaseMcp(value) {
|
|
22
22
|
isFirebaseMcpFlag = value;
|
|
23
|
+
if (value) {
|
|
24
|
+
process.env.IS_FIREBASE_MCP = "true";
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
delete process.env.IS_FIREBASE_MCP;
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
function detectAIAgent() {
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
const aiAgent = process.env.AI_AGENT?.trim();
|
|
32
|
+
if (aiAgent) {
|
|
33
|
+
return aiAgent;
|
|
27
34
|
}
|
|
28
35
|
if (process.env.ANTIGRAVITY_AGENT)
|
|
29
36
|
return "antigravity";
|
|
@@ -29,7 +29,7 @@ async function openBillingAccount(projectId, url, open) {
|
|
|
29
29
|
message: "Press enter when finished upgrading your project to continue setting up your extension.",
|
|
30
30
|
default: true,
|
|
31
31
|
});
|
|
32
|
-
return cloudbilling.checkBillingEnabled(projectId);
|
|
32
|
+
return cloudbilling.checkBillingEnabled(projectId, true);
|
|
33
33
|
}
|
|
34
34
|
async function chooseBillingAccount(projectId, accounts) {
|
|
35
35
|
const choices = accounts.map((m) => m.displayName);
|
|
@@ -65,7 +65,7 @@ async function setUpBillingAccount(projectId) {
|
|
|
65
65
|
return logBillingStatus(billingEnabled, projectId);
|
|
66
66
|
}
|
|
67
67
|
async function enableBilling(projectId) {
|
|
68
|
-
const billingAccounts = await cloudbilling.listBillingAccounts();
|
|
68
|
+
const billingAccounts = await cloudbilling.listBillingAccounts(projectId);
|
|
69
69
|
if (billingAccounts) {
|
|
70
70
|
const accounts = billingAccounts.filter((account) => account.open);
|
|
71
71
|
return accounts.length > 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AI_LOGIC_TRIGGERS_TO_EVENTS = exports.AI_LOGIC_EVENTS_TO_TRIGGER = exports.CONVERTABLE_EVENTS = exports.DATACONNECT_EVENT = exports.FIREALERTS_EVENT = exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
|
|
3
|
+
exports.AI_LOGIC_TRIGGERS_TO_EVENTS = exports.AI_LOGIC_EVENTS_TO_TRIGGER = exports.CONVERTABLE_EVENTS = exports.AUTH_EVENTS = exports.DATACONNECT_EVENT = exports.FIREALERTS_EVENT = exports.FIRESTORE_EVENTS = exports.TEST_LAB_EVENT = exports.REMOTE_CONFIG_EVENT = exports.DATABASE_EVENTS = exports.FIREBASE_ALERTS_PUBLISH_EVENT = exports.STORAGE_EVENTS = exports.PUBSUB_PUBLISH_EVENT = void 0;
|
|
4
4
|
const ailogic_1 = require("../../deploy/functions/services/ailogic");
|
|
5
5
|
exports.PUBSUB_PUBLISH_EVENT = "google.cloud.pubsub.topic.v1.messagePublished";
|
|
6
6
|
exports.STORAGE_EVENTS = [
|
|
@@ -30,6 +30,10 @@ exports.FIRESTORE_EVENTS = [
|
|
|
30
30
|
];
|
|
31
31
|
exports.FIREALERTS_EVENT = "google.firebase.firebasealerts.alerts.v1.published";
|
|
32
32
|
exports.DATACONNECT_EVENT = "google.firebase.dataconnect.connector.v1.mutationExecuted";
|
|
33
|
+
exports.AUTH_EVENTS = [
|
|
34
|
+
"google.firebase.auth.user.v2.created",
|
|
35
|
+
"google.firebase.auth.user.v2.deleted",
|
|
36
|
+
];
|
|
33
37
|
exports.CONVERTABLE_EVENTS = {
|
|
34
38
|
"google.cloud.firestore.document.v1.created": "google.cloud.firestore.document.v1.created.withAuthContext",
|
|
35
39
|
"google.cloud.firestore.document.v1.updated": "google.cloud.firestore.document.v1.updated.withAuthContext",
|
package/lib/gcp/cloudbilling.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isBillingEnabled = isBillingEnabled;
|
|
4
|
+
exports.clearCache = clearCache;
|
|
4
5
|
exports.checkBillingEnabled = checkBillingEnabled;
|
|
5
6
|
exports.setBillingAccount = setBillingAccount;
|
|
6
7
|
exports.listBillingAccounts = listBillingAccounts;
|
|
7
8
|
const api_1 = require("../api");
|
|
8
9
|
const apiv2_1 = require("../apiv2");
|
|
9
10
|
const utils = require("../utils");
|
|
11
|
+
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
10
12
|
const API_VERSION = "v1";
|
|
11
13
|
const client = new apiv2_1.Client({ urlPrefix: (0, api_1.cloudbillingOrigin)(), apiVersion: API_VERSION });
|
|
12
14
|
async function isBillingEnabled(setup) {
|
|
@@ -19,20 +21,51 @@ async function isBillingEnabled(setup) {
|
|
|
19
21
|
setup.isBillingEnabled = await checkBillingEnabled(setup.projectId);
|
|
20
22
|
return setup.isBillingEnabled;
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const billingEnabledCache = new Map();
|
|
25
|
+
function clearCache() {
|
|
26
|
+
billingEnabledCache.clear();
|
|
27
|
+
}
|
|
28
|
+
function checkBillingEnabled(projectId, forceRefresh = false) {
|
|
29
|
+
if (!forceRefresh) {
|
|
30
|
+
const cached = billingEnabledCache.get(projectId);
|
|
31
|
+
if (cached !== undefined) {
|
|
32
|
+
return cached;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const promise = (async () => {
|
|
36
|
+
await (0, ensureApiEnabled_1.ensure)(projectId, "cloudbilling.googleapis.com", "billing", true);
|
|
37
|
+
const res = await client.get(utils.endpoint(["projects", projectId, "billingInfo"]), {
|
|
38
|
+
retries: 3,
|
|
39
|
+
retryCodes: [429, 500, 503],
|
|
40
|
+
headers: { "x-goog-user-project": projectId },
|
|
41
|
+
});
|
|
42
|
+
return res.body.billingEnabled;
|
|
43
|
+
})().catch((err) => {
|
|
44
|
+
billingEnabledCache.delete(projectId);
|
|
45
|
+
throw err;
|
|
26
46
|
});
|
|
27
|
-
|
|
47
|
+
billingEnabledCache.set(projectId, promise);
|
|
48
|
+
return promise;
|
|
28
49
|
}
|
|
29
50
|
async function setBillingAccount(projectId, billingAccountName) {
|
|
51
|
+
await (0, ensureApiEnabled_1.ensure)(projectId, "cloudbilling.googleapis.com", "billing", true);
|
|
30
52
|
const res = await client.put(utils.endpoint(["projects", projectId, "billingInfo"]), {
|
|
31
53
|
billingAccountName: billingAccountName,
|
|
32
|
-
}, {
|
|
33
|
-
|
|
54
|
+
}, {
|
|
55
|
+
retryCodes: [429, 500, 503],
|
|
56
|
+
headers: { "x-goog-user-project": projectId },
|
|
57
|
+
});
|
|
58
|
+
const enabled = res.body.billingEnabled;
|
|
59
|
+
billingEnabledCache.set(projectId, Promise.resolve(enabled));
|
|
60
|
+
return enabled;
|
|
34
61
|
}
|
|
35
|
-
async function listBillingAccounts() {
|
|
36
|
-
|
|
62
|
+
async function listBillingAccounts(projectId) {
|
|
63
|
+
if (projectId) {
|
|
64
|
+
await (0, ensureApiEnabled_1.ensure)(projectId, "cloudbilling.googleapis.com", "billing", true);
|
|
65
|
+
}
|
|
66
|
+
const res = await client.get(utils.endpoint(["billingAccounts"]), {
|
|
67
|
+
retryCodes: [429, 500, 503],
|
|
68
|
+
headers: projectId ? { "x-goog-user-project": projectId } : undefined,
|
|
69
|
+
});
|
|
37
70
|
return res.body.billingAccounts || [];
|
|
38
71
|
}
|
package/lib/mcp/index.js
CHANGED
|
@@ -79,6 +79,9 @@ class FirebaseMcpServer {
|
|
|
79
79
|
this.clientInfo = clientInfo;
|
|
80
80
|
if (clientInfo?.name) {
|
|
81
81
|
void this.trackGA4("mcp_client_connected");
|
|
82
|
+
if (!process.env.AI_AGENT?.trim()) {
|
|
83
|
+
process.env.AI_AGENT = clientInfo.name;
|
|
84
|
+
}
|
|
82
85
|
}
|
|
83
86
|
if (!this.clientInfo?.name)
|
|
84
87
|
this.clientInfo = { name: "<unknown-client>" };
|
|
@@ -271,7 +274,7 @@ class FirebaseMcpServer {
|
|
|
271
274
|
async mcpCallTool(request) {
|
|
272
275
|
await this.detectProjectRoot();
|
|
273
276
|
const toolName = request.params.name;
|
|
274
|
-
const toolArgs = request.params.arguments;
|
|
277
|
+
const toolArgs = request.params.arguments ?? {};
|
|
275
278
|
const tool = await this.getTool(toolName);
|
|
276
279
|
if (!tool)
|
|
277
280
|
throw new Error(`Tool '${toolName}' could not be found.`);
|
package/lib/mcp/tool.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.tool = tool;
|
|
4
|
-
const
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
5
|
const util_1 = require("./util");
|
|
6
6
|
const availability_1 = require("./util/availability");
|
|
7
7
|
function tool(feature, options, fn) {
|
|
8
8
|
const { isAvailable, ...mcpOptions } = options;
|
|
9
9
|
return {
|
|
10
|
-
mcp: {
|
|
10
|
+
mcp: {
|
|
11
|
+
...mcpOptions,
|
|
12
|
+
inputSchema: (0, util_1.cleanSchema)(zod_1.z.toJSONSchema(options.inputSchema, { target: "draft-7", io: "input" })),
|
|
13
|
+
},
|
|
11
14
|
fn,
|
|
12
15
|
isAvailable: (ctx) => {
|
|
13
16
|
const isAvailableFunc = isAvailable || (0, availability_1.getDefaultFeatureAvailabilityCheck)(feature);
|
|
@@ -30,7 +30,7 @@ exports.fetch_logs = (0, tool_1.tool)("apphosting", {
|
|
|
30
30
|
requiresAuth: true,
|
|
31
31
|
requiresProject: true,
|
|
32
32
|
},
|
|
33
|
-
}, async ({ buildLogs, backendId, location }
|
|
33
|
+
}, async ({ buildLogs, backendId, location }, { projectId }) => {
|
|
34
34
|
location || (location = "");
|
|
35
35
|
if (!backendId) {
|
|
36
36
|
return (0, util_1.toContent)(`backendId must be specified.`);
|
|
@@ -30,7 +30,7 @@ exports.list_backends = (0, tool_1.tool)("apphosting", {
|
|
|
30
30
|
requiresAuth: true,
|
|
31
31
|
requiresProject: true,
|
|
32
32
|
},
|
|
33
|
-
}, async ({ location }
|
|
33
|
+
}, async ({ location }, { projectId }) => {
|
|
34
34
|
projectId = projectId || "";
|
|
35
35
|
if (!location)
|
|
36
36
|
location = "-";
|