gcs-google-mcp-server 0.1.9 → 0.1.10
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/build/healthcheck.js +37 -0
- package/build/index.js +5 -12
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { logInfo } from '../shared/logging.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when a constrained bucket cannot be reached (does not exist or the
|
|
4
|
+
* service account lacks access to it).
|
|
5
|
+
*/
|
|
6
|
+
export class BucketNotAccessibleError extends Error {
|
|
7
|
+
constructor(bucket) {
|
|
8
|
+
super(`Constrained bucket "${bucket}" does not exist or is not accessible`);
|
|
9
|
+
this.name = 'BucketNotAccessibleError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validate GCS credentials and connectivity.
|
|
14
|
+
*
|
|
15
|
+
* - When constrained to a single bucket (`GCS_BUCKET`), probe ONLY that bucket
|
|
16
|
+
* via `headBucket`, which needs only bucket-level permissions
|
|
17
|
+
* (`storage.buckets.get`). This path must NOT call `listBuckets()`, because
|
|
18
|
+
* that requires the project-level `storage.buckets.list` permission, which a
|
|
19
|
+
* least-privilege, bucket-scoped service account intentionally does not have.
|
|
20
|
+
* - Without a constraint, validate by listing buckets, which legitimately
|
|
21
|
+
* requires project-level access.
|
|
22
|
+
*
|
|
23
|
+
* Throws on failure; callers decide how to surface it.
|
|
24
|
+
*/
|
|
25
|
+
export async function validateGcsCredentials(client, constrainedBucket) {
|
|
26
|
+
if (constrainedBucket) {
|
|
27
|
+
const bucketExists = await client.headBucket(constrainedBucket);
|
|
28
|
+
if (!bucketExists) {
|
|
29
|
+
throw new BucketNotAccessibleError(constrainedBucket);
|
|
30
|
+
}
|
|
31
|
+
logInfo('healthcheck', `Constrained bucket "${constrainedBucket}" verified`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
await client.listBuckets();
|
|
35
|
+
logInfo('healthcheck', 'GCS credentials validated successfully');
|
|
36
|
+
}
|
|
37
|
+
}
|
package/build/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
6
|
import { createMCPServer, GoogleCloudStorageClient } from '../shared/index.js';
|
|
7
7
|
import { logServerStart, logError, logWarning, logInfo } from '../shared/logging.js';
|
|
8
|
+
import { validateGcsCredentials } from './healthcheck.js';
|
|
8
9
|
// Read version from package.json
|
|
9
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
11
|
const packageJsonPath = join(__dirname, '..', 'package.json');
|
|
@@ -108,18 +109,10 @@ async function performHealthChecks() {
|
|
|
108
109
|
keyFilePath,
|
|
109
110
|
keyFileContents,
|
|
110
111
|
});
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (constrainedBucket) {
|
|
116
|
-
const bucketExists = await client.headBucket(constrainedBucket);
|
|
117
|
-
if (!bucketExists) {
|
|
118
|
-
logError('healthcheck', `Constrained bucket "${constrainedBucket}" does not exist or is not accessible`);
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
logInfo('healthcheck', `Constrained bucket "${constrainedBucket}" verified`);
|
|
122
|
-
}
|
|
112
|
+
// Validate credentials. When constrained to a single bucket, this probes
|
|
113
|
+
// only that bucket and never calls listBuckets(), so a least-privilege,
|
|
114
|
+
// bucket-scoped service account (without storage.buckets.list) can start.
|
|
115
|
+
await validateGcsCredentials(client, constrainedBucket);
|
|
123
116
|
}
|
|
124
117
|
catch (error) {
|
|
125
118
|
const message = error instanceof Error ? error.message : String(error);
|
package/package.json
CHANGED