gcs-google-mcp-server 0.1.0
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 +241 -0
- package/build/index.integration-with-mock.js +42 -0
- package/build/index.js +152 -0
- package/package.json +50 -0
- package/shared/gcs-client/gcs-client.d.ts +74 -0
- package/shared/gcs-client/gcs-client.integration-mock.d.ts +15 -0
- package/shared/gcs-client/gcs-client.integration-mock.js +131 -0
- package/shared/gcs-client/gcs-client.js +120 -0
- package/shared/index.d.ts +8 -0
- package/shared/index.js +9 -0
- package/shared/logging.d.ts +24 -0
- package/shared/logging.js +40 -0
- package/shared/resources.d.ts +3 -0
- package/shared/resources.js +65 -0
- package/shared/server.d.ts +46 -0
- package/shared/server.js +37 -0
- package/shared/state.d.ts +43 -0
- package/shared/state.js +67 -0
- package/shared/tools/copy-object.d.ts +59 -0
- package/shared/tools/copy-object.js +71 -0
- package/shared/tools/create-bucket.d.ts +45 -0
- package/shared/tools/create-bucket.js +82 -0
- package/shared/tools/delete-bucket.d.ts +38 -0
- package/shared/tools/delete-bucket.js +60 -0
- package/shared/tools/delete-object.d.ts +45 -0
- package/shared/tools/delete-object.js +64 -0
- package/shared/tools/get-object.d.ts +45 -0
- package/shared/tools/get-object.js +65 -0
- package/shared/tools/head-bucket.d.ts +38 -0
- package/shared/tools/head-bucket.js +58 -0
- package/shared/tools/list-buckets.d.ts +27 -0
- package/shared/tools/list-buckets.js +49 -0
- package/shared/tools/list-objects.d.ts +68 -0
- package/shared/tools/list-objects.js +80 -0
- package/shared/tools/put-object.d.ts +69 -0
- package/shared/tools/put-object.js +81 -0
- package/shared/tools.d.ts +30 -0
- package/shared/tools.js +154 -0
- package/shared/types.d.ts +1 -0
- package/shared/types.js +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# GCS MCP Server
|
|
2
|
+
|
|
3
|
+
> **Note**: This package is part of the [MCP Servers](https://github.com/pulsemcp/mcp-servers) monorepo. For the latest updates and full source code, visit the [GCS MCP Server directory](https://github.com/pulsemcp/mcp-servers/tree/main/experimental/gcs).
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
MCP server for Google Cloud Storage operations with fine-grained tool access control. Supports read/write operations on GCS buckets and objects, with configurable tool groups for security and permission management.
|
|
7
|
+
|
|
8
|
+
## Highlights
|
|
9
|
+
|
|
10
|
+
- Full GCS bucket and object management (list, get, put, copy, delete)
|
|
11
|
+
- Fine-grained access control with tool groups (readonly, readwrite)
|
|
12
|
+
- Individual tool enable/disable via environment variables
|
|
13
|
+
- Multiple authentication methods (service account key file, inline JSON, ADC)
|
|
14
|
+
- GCS credential validation with health checks
|
|
15
|
+
- Single bucket constraint mode
|
|
16
|
+
- TypeScript with strict type checking
|
|
17
|
+
- Comprehensive testing (functional, integration, manual)
|
|
18
|
+
|
|
19
|
+
## Capabilities
|
|
20
|
+
|
|
21
|
+
### Tools
|
|
22
|
+
|
|
23
|
+
| Tool | Group | Description |
|
|
24
|
+
| --------------- | --------- | --------------------------------------------------- |
|
|
25
|
+
| `list_buckets` | readonly | List all GCS buckets in the Google Cloud project |
|
|
26
|
+
| `list_objects` | readonly | List objects in a bucket with prefix and pagination |
|
|
27
|
+
| `get_object` | readonly | Get object contents as text |
|
|
28
|
+
| `head_bucket` | readonly | Check if a bucket exists and is accessible |
|
|
29
|
+
| `put_object` | readwrite | Upload or update an object |
|
|
30
|
+
| `delete_object` | readwrite | Delete an object from a bucket |
|
|
31
|
+
| `copy_object` | readwrite | Copy an object within or across buckets |
|
|
32
|
+
| `create_bucket` | readwrite | Create a new GCS bucket |
|
|
33
|
+
| `delete_bucket` | readwrite | Delete an empty GCS bucket |
|
|
34
|
+
|
|
35
|
+
### Resources
|
|
36
|
+
|
|
37
|
+
| Resource | Description |
|
|
38
|
+
| -------------- | ----------------------------------------------- |
|
|
39
|
+
| `gcs://config` | Server configuration and status (for debugging) |
|
|
40
|
+
|
|
41
|
+
### Tool Groups
|
|
42
|
+
|
|
43
|
+
Control which tools are available via the `GCS_ENABLED_TOOLGROUPS` environment variable:
|
|
44
|
+
|
|
45
|
+
| Group | Description |
|
|
46
|
+
| ----------- | -------------------------------------------- |
|
|
47
|
+
| `readonly` | Read-only operations (list, get, head) |
|
|
48
|
+
| `readwrite` | Write operations (put, delete, copy, create) |
|
|
49
|
+
|
|
50
|
+
**Examples:**
|
|
51
|
+
|
|
52
|
+
- `GCS_ENABLED_TOOLGROUPS="readonly"` - Only read operations
|
|
53
|
+
- `GCS_ENABLED_TOOLGROUPS="readonly,readwrite"` - All operations
|
|
54
|
+
- Not set - All tools enabled (default)
|
|
55
|
+
|
|
56
|
+
### Individual Tool Control
|
|
57
|
+
|
|
58
|
+
Fine-grained control over specific tools:
|
|
59
|
+
|
|
60
|
+
- `GCS_ENABLED_TOOLS="list_buckets,get_object"` - Only enable these tools
|
|
61
|
+
- `GCS_DISABLED_TOOLS="delete_bucket,delete_object"` - Disable these tools
|
|
62
|
+
|
|
63
|
+
### Single Bucket Mode
|
|
64
|
+
|
|
65
|
+
Constrain all operations to a specific bucket using `GCS_BUCKET`:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
GCS_BUCKET="my-bucket"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
When set:
|
|
72
|
+
|
|
73
|
+
- All object operations are automatically scoped to this bucket
|
|
74
|
+
- Bucket-level tools (`list_buckets`, `create_bucket`, `delete_bucket`, `head_bucket`) are hidden
|
|
75
|
+
- The `bucket` parameter is automatically injected and hidden from tool inputs
|
|
76
|
+
- For `copy_object`, both source and destination are constrained to the specified bucket
|
|
77
|
+
|
|
78
|
+
This is useful for restricting access to a single bucket without giving broader GCS permissions.
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
### Configuration
|
|
83
|
+
|
|
84
|
+
#### Environment Variables
|
|
85
|
+
|
|
86
|
+
| Variable | Required | Description | Default |
|
|
87
|
+
| ------------------------------ | -------- | ------------------------------------------ | ----------- |
|
|
88
|
+
| `GCS_PROJECT_ID` | Yes | Google Cloud project ID | - |
|
|
89
|
+
| `GCS_SERVICE_ACCOUNT_KEY_FILE` | No | Path to service account key JSON file | - |
|
|
90
|
+
| `GCS_SERVICE_ACCOUNT_KEY_JSON` | No | Service account key JSON contents (inline) | - |
|
|
91
|
+
| `GCS_BUCKET` | No | Constrain operations to single bucket | - |
|
|
92
|
+
| `GCS_ENABLED_TOOLGROUPS` | No | Comma-separated tool groups | All enabled |
|
|
93
|
+
| `GCS_ENABLED_TOOLS` | No | Specific tools to enable | - |
|
|
94
|
+
| `GCS_DISABLED_TOOLS` | No | Specific tools to disable | - |
|
|
95
|
+
| `SKIP_HEALTH_CHECKS` | No | Skip credential validation | `false` |
|
|
96
|
+
|
|
97
|
+
#### Authentication
|
|
98
|
+
|
|
99
|
+
The server supports three authentication methods (in order of precedence):
|
|
100
|
+
|
|
101
|
+
1. **Service Account Key File**: Set `GCS_SERVICE_ACCOUNT_KEY_FILE` to the path of a JSON key file
|
|
102
|
+
2. **Inline Service Account Key**: Set `GCS_SERVICE_ACCOUNT_KEY_JSON` with the JSON contents directly
|
|
103
|
+
3. **Application Default Credentials (ADC)**: No additional env vars needed - uses `gcloud auth application-default login`
|
|
104
|
+
|
|
105
|
+
### Claude Desktop Configuration
|
|
106
|
+
|
|
107
|
+
If this is your first time using MCP Servers, make sure you have the [Claude Desktop application](https://claude.ai/download) and follow the [official MCP setup instructions](https://modelcontextprotocol.io/quickstart/user).
|
|
108
|
+
|
|
109
|
+
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
110
|
+
|
|
111
|
+
Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"mcpServers": {
|
|
116
|
+
"gcs": {
|
|
117
|
+
"command": "npx",
|
|
118
|
+
"args": ["-y", "gcs-google-mcp-server"],
|
|
119
|
+
"env": {
|
|
120
|
+
"GCS_PROJECT_ID": "your-project-id",
|
|
121
|
+
"GCS_SERVICE_ACCOUNT_KEY_FILE": "/path/to/service-account-key.json",
|
|
122
|
+
"GCS_ENABLED_TOOLGROUPS": "readonly"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Restart Claude Desktop and you should be ready to go!
|
|
130
|
+
|
|
131
|
+
### Read-Only Mode
|
|
132
|
+
|
|
133
|
+
For safer exploration, enable only read operations:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"env": {
|
|
138
|
+
"GCS_ENABLED_TOOLGROUPS": "readonly"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Using Application Default Credentials
|
|
144
|
+
|
|
145
|
+
If you have `gcloud` CLI configured locally:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
gcloud auth application-default login
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Then configure without key file:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"env": {
|
|
156
|
+
"GCS_PROJECT_ID": "your-project-id"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
### Install Dependencies
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm run install-all
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Build
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npm run build
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Running in Development Mode
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm run dev
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Testing
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Run functional tests
|
|
185
|
+
npm run test:run
|
|
186
|
+
|
|
187
|
+
# Run integration tests (full MCP protocol)
|
|
188
|
+
npm run test:integration
|
|
189
|
+
|
|
190
|
+
# Run manual tests (real GCS - requires .env)
|
|
191
|
+
npm run test:manual:setup # First time only
|
|
192
|
+
npm run test:manual
|
|
193
|
+
|
|
194
|
+
# Run all automated tests
|
|
195
|
+
npm run test:all
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Manual Testing Setup
|
|
199
|
+
|
|
200
|
+
Create a `.env` file in the gcs directory:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
GCS_PROJECT_ID=your-project-id
|
|
204
|
+
GCS_SERVICE_ACCOUNT_KEY_FILE=/path/to/service-account-key.json
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Then run:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
npm run test:manual
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Project Structure
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
gcs/
|
|
217
|
+
├── local/ # Local server implementation
|
|
218
|
+
│ ├── src/
|
|
219
|
+
│ │ ├── index.ts # Main entry point with env validation
|
|
220
|
+
│ │ └── index.integration-with-mock.ts
|
|
221
|
+
│ └── package.json
|
|
222
|
+
├── shared/ # Shared business logic
|
|
223
|
+
│ ├── src/
|
|
224
|
+
│ │ ├── server.ts # Server factory with DI
|
|
225
|
+
│ │ ├── tools.ts # Tool registration with grouping
|
|
226
|
+
│ │ ├── tools/ # Individual tool implementations
|
|
227
|
+
│ │ ├── resources.ts # Resource implementations
|
|
228
|
+
│ │ ├── gcs-client/ # Google Cloud Storage client wrapper
|
|
229
|
+
│ │ └── logging.ts
|
|
230
|
+
│ └── package.json
|
|
231
|
+
├── tests/ # Test suite
|
|
232
|
+
│ ├── functional/ # Unit tests with mocks
|
|
233
|
+
│ ├── integration/ # MCP protocol tests
|
|
234
|
+
│ ├── manual/ # Real API tests
|
|
235
|
+
│ └── mocks/ # Mock implementations
|
|
236
|
+
└── package.json # Root workspace config
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Integration Test Server Entry Point with Mock Client Factory
|
|
4
|
+
*
|
|
5
|
+
* This file is used for integration testing with a mocked GCS Client.
|
|
6
|
+
* It uses the real MCP server but injects a mock client factory.
|
|
7
|
+
*
|
|
8
|
+
* Mock data is passed via the GCS_MOCK_DATA environment variable.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'fs';
|
|
11
|
+
import { dirname, join } from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
// Import from shared module via symlink (created by setup-dev.js)
|
|
15
|
+
import { createMCPServer, createIntegrationMockGCSClient } from '../shared/index.js';
|
|
16
|
+
// Read version from package.json
|
|
17
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const packageJsonPath = join(__dirname, '..', 'package.json');
|
|
19
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
20
|
+
const VERSION = packageJson.version;
|
|
21
|
+
async function main() {
|
|
22
|
+
const transport = new StdioServerTransport();
|
|
23
|
+
// Parse mock data from environment variable
|
|
24
|
+
let mockData = {};
|
|
25
|
+
if (process.env.GCS_MOCK_DATA) {
|
|
26
|
+
try {
|
|
27
|
+
mockData = JSON.parse(process.env.GCS_MOCK_DATA);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
console.error('Failed to parse GCS_MOCK_DATA:', e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Create client factory that returns our mock
|
|
34
|
+
const clientFactory = () => createIntegrationMockGCSClient(mockData);
|
|
35
|
+
const { server, registerHandlers } = createMCPServer({ version: VERSION });
|
|
36
|
+
await registerHandlers(server, clientFactory);
|
|
37
|
+
await server.connect(transport);
|
|
38
|
+
}
|
|
39
|
+
main().catch((error) => {
|
|
40
|
+
console.error('Server error:', error);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
});
|
package/build/index.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { createMCPServer, GoogleCloudStorageClient } from '../shared/index.js';
|
|
7
|
+
import { logServerStart, logError, logWarning, logInfo } from '../shared/logging.js';
|
|
8
|
+
// Read version from package.json
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const packageJsonPath = join(__dirname, '..', 'package.json');
|
|
11
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
12
|
+
const VERSION = packageJson.version;
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// ENVIRONMENT VALIDATION
|
|
15
|
+
// =============================================================================
|
|
16
|
+
function validateEnvironment() {
|
|
17
|
+
const required = [
|
|
18
|
+
{
|
|
19
|
+
name: 'GCS_PROJECT_ID',
|
|
20
|
+
description: 'Google Cloud project ID',
|
|
21
|
+
example: 'my-project-id',
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
const optional = [
|
|
25
|
+
{
|
|
26
|
+
name: 'GCS_SERVICE_ACCOUNT_KEY_FILE',
|
|
27
|
+
description: 'Path to service account key JSON file',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'GCS_SERVICE_ACCOUNT_KEY_JSON',
|
|
31
|
+
description: 'Service account key JSON contents (inline)',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'GCS_ENABLED_TOOLGROUPS',
|
|
35
|
+
description: 'Comma-separated list of tool groups to enable (readonly, readwrite)',
|
|
36
|
+
defaultValue: 'all groups enabled',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'GCS_ENABLED_TOOLS',
|
|
40
|
+
description: 'Comma-separated list of specific tools to enable (overrides groups)',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'GCS_DISABLED_TOOLS',
|
|
44
|
+
description: 'Comma-separated list of specific tools to disable',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'GCS_BUCKET',
|
|
48
|
+
description: 'Constrain all operations to a single bucket (hides bucket-level tools)',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'SKIP_HEALTH_CHECKS',
|
|
52
|
+
description: 'Skip health checks on startup (set to "true" to skip)',
|
|
53
|
+
defaultValue: 'false',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
const missing = required.filter(({ name }) => !process.env[name]);
|
|
57
|
+
if (missing.length > 0) {
|
|
58
|
+
logError('validateEnvironment', 'Missing required environment variables:');
|
|
59
|
+
missing.forEach(({ name, description, example }) => {
|
|
60
|
+
console.error(` - ${name}: ${description}`);
|
|
61
|
+
console.error(` Example: ${example}`);
|
|
62
|
+
});
|
|
63
|
+
if (optional.length > 0) {
|
|
64
|
+
console.error('\nOptional environment variables:');
|
|
65
|
+
optional.forEach(({ name, description, defaultValue }) => {
|
|
66
|
+
const defaultStr = defaultValue ? ` (default: ${defaultValue})` : '';
|
|
67
|
+
console.error(` - ${name}: ${description}${defaultStr}`);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
console.error('\n----------------------------------------');
|
|
71
|
+
console.error('Please set the required environment variables and try again.');
|
|
72
|
+
console.error('\nAuthentication options:');
|
|
73
|
+
console.error(' 1. Set GCS_SERVICE_ACCOUNT_KEY_FILE to a service account key file path');
|
|
74
|
+
console.error(' 2. Set GCS_SERVICE_ACCOUNT_KEY_JSON with inline JSON credentials');
|
|
75
|
+
console.error(' 3. Use Application Default Credentials (gcloud auth application-default login)');
|
|
76
|
+
console.error('----------------------------------------\n');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
// Log warnings for common configuration issues
|
|
80
|
+
if (process.env.GCS_ENABLED_TOOLGROUPS) {
|
|
81
|
+
logWarning('config', `Tool groups filter active: ${process.env.GCS_ENABLED_TOOLGROUPS}`);
|
|
82
|
+
}
|
|
83
|
+
if (process.env.GCS_ENABLED_TOOLS) {
|
|
84
|
+
logWarning('config', `Enabled tools filter active: ${process.env.GCS_ENABLED_TOOLS}`);
|
|
85
|
+
}
|
|
86
|
+
if (process.env.GCS_DISABLED_TOOLS) {
|
|
87
|
+
logWarning('config', `Disabled tools filter active: ${process.env.GCS_DISABLED_TOOLS}`);
|
|
88
|
+
}
|
|
89
|
+
if (process.env.GCS_BUCKET) {
|
|
90
|
+
logInfo('config', `Bucket constraint active: ${process.env.GCS_BUCKET}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// =============================================================================
|
|
94
|
+
// HEALTH CHECKS
|
|
95
|
+
// =============================================================================
|
|
96
|
+
async function performHealthChecks() {
|
|
97
|
+
if (process.env.SKIP_HEALTH_CHECKS === 'true') {
|
|
98
|
+
logWarning('healthcheck', 'Health checks skipped (SKIP_HEALTH_CHECKS=true)');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const projectId = process.env.GCS_PROJECT_ID;
|
|
103
|
+
const keyFilePath = process.env.GCS_SERVICE_ACCOUNT_KEY_FILE;
|
|
104
|
+
const keyFileContents = process.env.GCS_SERVICE_ACCOUNT_KEY_JSON;
|
|
105
|
+
const constrainedBucket = process.env.GCS_BUCKET;
|
|
106
|
+
const client = new GoogleCloudStorageClient({
|
|
107
|
+
projectId,
|
|
108
|
+
keyFilePath,
|
|
109
|
+
keyFileContents,
|
|
110
|
+
});
|
|
111
|
+
// Try to list buckets to validate credentials
|
|
112
|
+
await client.listBuckets();
|
|
113
|
+
logInfo('healthcheck', 'GCS credentials validated successfully');
|
|
114
|
+
// If GCS_BUCKET is set, verify it exists and is accessible
|
|
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
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
126
|
+
logError('healthcheck', `Failed to validate GCS credentials: ${message}`);
|
|
127
|
+
logError('healthcheck', 'Please check your GCS_PROJECT_ID and authentication configuration');
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// =============================================================================
|
|
132
|
+
// MAIN ENTRY POINT
|
|
133
|
+
// =============================================================================
|
|
134
|
+
async function main() {
|
|
135
|
+
// Step 1: Validate environment variables
|
|
136
|
+
validateEnvironment();
|
|
137
|
+
// Step 2: Perform health checks (validates credentials, connectivity)
|
|
138
|
+
await performHealthChecks();
|
|
139
|
+
// Step 3: Create server using factory
|
|
140
|
+
const { server, registerHandlers } = createMCPServer({ version: VERSION });
|
|
141
|
+
// Step 4: Register all handlers (resources and tools)
|
|
142
|
+
await registerHandlers(server);
|
|
143
|
+
// Step 5: Start server with stdio transport
|
|
144
|
+
const transport = new StdioServerTransport();
|
|
145
|
+
await server.connect(transport);
|
|
146
|
+
logServerStart('gcs-mcp-server');
|
|
147
|
+
}
|
|
148
|
+
// Run the server
|
|
149
|
+
main().catch((error) => {
|
|
150
|
+
logError('main', error);
|
|
151
|
+
process.exit(1);
|
|
152
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gcs-google-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Google Cloud Storage operations with fine-grained tool access control",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"gcs-mcp-server": "./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build/**/*.js",
|
|
12
|
+
"build/**/*.d.ts",
|
|
13
|
+
"shared/**/*.js",
|
|
14
|
+
"shared/**/*.d.ts",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc && npm run build:integration",
|
|
19
|
+
"build:integration": "tsc -p tsconfig.integration.json",
|
|
20
|
+
"start": "node build/index.js",
|
|
21
|
+
"dev": "tsx src/index.ts",
|
|
22
|
+
"predev": "cd ../shared && npm run build && cd ../local && node setup-dev.js",
|
|
23
|
+
"prebuild": "cd ../shared && npm run build && cd ../local && node setup-dev.js",
|
|
24
|
+
"prepublishOnly": "node prepare-publish.js && node ../scripts/prepare-npm-readme.js",
|
|
25
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
26
|
+
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
|
27
|
+
"format": "prettier --write .",
|
|
28
|
+
"format:check": "prettier --check .",
|
|
29
|
+
"stage-publish": "npm version"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@google-cloud/storage": "^7.15.0",
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.19.1",
|
|
34
|
+
"zod": "^3.24.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.10.6",
|
|
38
|
+
"tsx": "^4.19.4",
|
|
39
|
+
"typescript": "^5.7.3"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"mcp",
|
|
43
|
+
"gcs",
|
|
44
|
+
"google-cloud",
|
|
45
|
+
"google-cloud-storage",
|
|
46
|
+
"model-context-protocol"
|
|
47
|
+
],
|
|
48
|
+
"author": "PulseMCP",
|
|
49
|
+
"license": "MIT"
|
|
50
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export interface GCSClientConfig {
|
|
2
|
+
projectId: string;
|
|
3
|
+
keyFilePath?: string;
|
|
4
|
+
keyFileContents?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ListBucketsResult {
|
|
7
|
+
buckets: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
creationDate?: Date;
|
|
10
|
+
}>;
|
|
11
|
+
}
|
|
12
|
+
export interface ListObjectsOptions {
|
|
13
|
+
prefix?: string;
|
|
14
|
+
maxResults?: number;
|
|
15
|
+
pageToken?: string;
|
|
16
|
+
delimiter?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ListObjectsResult {
|
|
19
|
+
objects: Array<{
|
|
20
|
+
key: string;
|
|
21
|
+
size?: number;
|
|
22
|
+
lastModified?: Date;
|
|
23
|
+
storageClass?: string;
|
|
24
|
+
etag?: string;
|
|
25
|
+
}>;
|
|
26
|
+
commonPrefixes: string[];
|
|
27
|
+
isTruncated: boolean;
|
|
28
|
+
nextPageToken?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface GetObjectResult {
|
|
31
|
+
content: string;
|
|
32
|
+
contentType?: string;
|
|
33
|
+
contentLength?: number;
|
|
34
|
+
lastModified?: Date;
|
|
35
|
+
etag?: string;
|
|
36
|
+
metadata?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
export interface PutObjectOptions {
|
|
39
|
+
contentType?: string;
|
|
40
|
+
metadata?: Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
export interface PutObjectResult {
|
|
43
|
+
etag?: string;
|
|
44
|
+
generation?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface CopyObjectResult {
|
|
47
|
+
etag?: string;
|
|
48
|
+
generation?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface IGCSClient {
|
|
51
|
+
listBuckets(): Promise<ListBucketsResult>;
|
|
52
|
+
listObjects(bucket: string, options?: ListObjectsOptions): Promise<ListObjectsResult>;
|
|
53
|
+
getObject(bucket: string, key: string): Promise<GetObjectResult>;
|
|
54
|
+
putObject(bucket: string, key: string, content: string, options?: PutObjectOptions): Promise<PutObjectResult>;
|
|
55
|
+
deleteObject(bucket: string, key: string): Promise<void>;
|
|
56
|
+
createBucket(bucket: string, location?: string): Promise<void>;
|
|
57
|
+
deleteBucket(bucket: string): Promise<void>;
|
|
58
|
+
headBucket(bucket: string): Promise<boolean>;
|
|
59
|
+
copyObject(sourceBucket: string, sourceKey: string, destBucket: string, destKey: string): Promise<CopyObjectResult>;
|
|
60
|
+
}
|
|
61
|
+
export declare class GoogleCloudStorageClient implements IGCSClient {
|
|
62
|
+
private storage;
|
|
63
|
+
constructor(config: GCSClientConfig);
|
|
64
|
+
listBuckets(): Promise<ListBucketsResult>;
|
|
65
|
+
listObjects(bucket: string, options?: ListObjectsOptions): Promise<ListObjectsResult>;
|
|
66
|
+
getObject(bucket: string, key: string): Promise<GetObjectResult>;
|
|
67
|
+
putObject(bucket: string, key: string, content: string, options?: PutObjectOptions): Promise<PutObjectResult>;
|
|
68
|
+
deleteObject(bucket: string, key: string): Promise<void>;
|
|
69
|
+
createBucket(bucket: string, location?: string): Promise<void>;
|
|
70
|
+
deleteBucket(bucket: string): Promise<void>;
|
|
71
|
+
headBucket(bucket: string): Promise<boolean>;
|
|
72
|
+
copyObject(sourceBucket: string, sourceKey: string, destBucket: string, destKey: string): Promise<CopyObjectResult>;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=gcs-client.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IGCSClient } from './gcs-client.js';
|
|
2
|
+
export interface MockGCSData {
|
|
3
|
+
buckets?: Array<{
|
|
4
|
+
name: string;
|
|
5
|
+
creationDate?: Date;
|
|
6
|
+
}>;
|
|
7
|
+
objects?: Record<string, Record<string, {
|
|
8
|
+
content: string;
|
|
9
|
+
contentType?: string;
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
lastModified?: Date;
|
|
12
|
+
}>>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createIntegrationMockGCSClient(mockData?: MockGCSData): IGCSClient;
|
|
15
|
+
//# sourceMappingURL=gcs-client.integration-mock.d.ts.map
|