@google-cloud/cloud-run-mcp 1.7.0 → 1.9.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/.env.example +13 -0
- package/.env.gcloud-sdk-oauth +13 -0
- package/README.md +38 -0
- package/constants.js +8 -0
- package/lib/clients.js +292 -0
- package/lib/cloud-api/auth.js +1 -0
- package/lib/cloud-api/billing.js +21 -14
- package/lib/cloud-api/build.js +98 -49
- package/lib/cloud-api/helpers.js +10 -17
- package/lib/cloud-api/projects.js +16 -13
- package/lib/cloud-api/registry.js +9 -5
- package/lib/cloud-api/run.js +20 -38
- package/lib/cloud-api/storage.js +7 -7
- package/lib/deployment/deployer.js +33 -61
- package/lib/deployment/helpers.js +1 -1
- package/lib/middleware/oauth.js +92 -0
- package/lib/util/helpers.js +12 -0
- package/mcp-server.js +51 -7
- package/package.json +3 -3
- package/test/local/clients.test.js +176 -0
- package/test/local/cloud-api/build.test.js +293 -309
- package/test/local/mcp-server-stdio.test.js +0 -1
- package/test/local/mcp-server-streamable-http.test.js +69 -0
- package/test/local/mcp-server.test.js +1 -0
- package/test/local/middleware/oauth.test.js +156 -0
- package/test/local/mock-clients.js +35 -0
- package/test/local/tools.test.js +2 -2
- package/test/need-gcp/test-helpers.js +1 -1
- package/tools/register-tools.js +18 -5
- package/.kokoro/kokoro_build.sh +0 -22
- package/.kokoro/presubmit.cfg +0 -21
- package/.kokoro/run_tests.sh +0 -31
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { test, describe } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { getClient } from '../../lib/clients.js';
|
|
4
|
+
|
|
5
|
+
describe('getClient Helper', () => {
|
|
6
|
+
class MockClient {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test('creates new client instance with authClient when access token provided', async () => {
|
|
13
|
+
const projectId = 'test-project-1';
|
|
14
|
+
const accessToken = 'fake-token-1';
|
|
15
|
+
const service = 'run'; // Must match keys in lib/clients.js clients object
|
|
16
|
+
const key = projectId + accessToken;
|
|
17
|
+
|
|
18
|
+
const client = await getClient(
|
|
19
|
+
service,
|
|
20
|
+
key,
|
|
21
|
+
async () => MockClient,
|
|
22
|
+
{ projectId },
|
|
23
|
+
accessToken
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
assert.ok(client instanceof MockClient);
|
|
27
|
+
assert.strictEqual(client.options.projectId, projectId);
|
|
28
|
+
assert.ok(client.options.authClient);
|
|
29
|
+
|
|
30
|
+
const headers = await client.options.authClient.getRequestHeaders();
|
|
31
|
+
// 'run' is a gRPC service, so it should be wrapped to return a Map
|
|
32
|
+
assert.ok(headers instanceof Map);
|
|
33
|
+
assert.strictEqual(headers.get('Authorization'), 'Bearer fake-token-1');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('creates new client instance WITHOUT authClient when NO access token provided', async () => {
|
|
37
|
+
const projectId = 'test-project-2';
|
|
38
|
+
const service = 'run';
|
|
39
|
+
const key = projectId;
|
|
40
|
+
|
|
41
|
+
const client = await getClient(
|
|
42
|
+
service,
|
|
43
|
+
key,
|
|
44
|
+
async () => MockClient,
|
|
45
|
+
{ projectId },
|
|
46
|
+
null
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
assert.ok(client instanceof MockClient);
|
|
50
|
+
assert.strictEqual(client.options.projectId, projectId);
|
|
51
|
+
assert.strictEqual(client.options.authClient, undefined);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('caches client instances by key', async () => {
|
|
55
|
+
const projectId = 'test-project-3';
|
|
56
|
+
const accessToken = 'token-A';
|
|
57
|
+
const service = 'run';
|
|
58
|
+
const key = projectId + accessToken;
|
|
59
|
+
|
|
60
|
+
const client1 = await getClient(
|
|
61
|
+
service,
|
|
62
|
+
key,
|
|
63
|
+
async () => MockClient,
|
|
64
|
+
{ projectId },
|
|
65
|
+
accessToken
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const client2 = await getClient(
|
|
69
|
+
service,
|
|
70
|
+
key,
|
|
71
|
+
async () => MockClient,
|
|
72
|
+
{ projectId },
|
|
73
|
+
accessToken
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assert.strictEqual(client1, client2);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('creates DIFFERENT client instances for different keys', async () => {
|
|
80
|
+
const projectId = 'test-project-4';
|
|
81
|
+
const service = 'run';
|
|
82
|
+
|
|
83
|
+
const client1 = await getClient(
|
|
84
|
+
service,
|
|
85
|
+
projectId + 'token-A',
|
|
86
|
+
async () => MockClient,
|
|
87
|
+
{ projectId },
|
|
88
|
+
'token-A'
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const client2 = await getClient(
|
|
92
|
+
service,
|
|
93
|
+
projectId + 'token-B',
|
|
94
|
+
async () => MockClient,
|
|
95
|
+
{ projectId },
|
|
96
|
+
'token-B'
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
assert.notStrictEqual(client1, client2);
|
|
100
|
+
|
|
101
|
+
const h1 = await client1.options.authClient.getRequestHeaders();
|
|
102
|
+
assert.ok(h1 instanceof Map);
|
|
103
|
+
assert.strictEqual(h1.get('Authorization'), 'Bearer token-A');
|
|
104
|
+
|
|
105
|
+
const h2 = await client2.options.authClient.getRequestHeaders();
|
|
106
|
+
assert.ok(h2 instanceof Map);
|
|
107
|
+
assert.strictEqual(h2.get('Authorization'), 'Bearer token-B');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('supports different services', async () => {
|
|
111
|
+
const projectId = 'test-project-5';
|
|
112
|
+
const accessToken = 'token-C';
|
|
113
|
+
|
|
114
|
+
const runClient = await getClient(
|
|
115
|
+
'run',
|
|
116
|
+
projectId + accessToken,
|
|
117
|
+
async () => MockClient,
|
|
118
|
+
{ projectId },
|
|
119
|
+
accessToken
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const storageClient = await getClient(
|
|
123
|
+
'storage',
|
|
124
|
+
projectId + accessToken,
|
|
125
|
+
async () => MockClient,
|
|
126
|
+
{ projectId },
|
|
127
|
+
accessToken
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
assert.notStrictEqual(runClient, storageClient); // Different maps
|
|
131
|
+
assert.ok(runClient.options.authClient);
|
|
132
|
+
assert.ok(storageClient.options.authClient);
|
|
133
|
+
|
|
134
|
+
const runHeaders = await runClient.options.authClient.getRequestHeaders();
|
|
135
|
+
assert.ok(runHeaders instanceof Map, 'Run client headers should be a Map');
|
|
136
|
+
|
|
137
|
+
const storageHeaders =
|
|
138
|
+
await storageClient.options.authClient.getRequestHeaders();
|
|
139
|
+
assert.ok(
|
|
140
|
+
!(storageHeaders instanceof Map),
|
|
141
|
+
'Storage client headers should NOT be a Map'
|
|
142
|
+
);
|
|
143
|
+
assert.strictEqual(storageHeaders.Authorization, `Bearer ${accessToken}`);
|
|
144
|
+
|
|
145
|
+
const loggingClient = await getClient(
|
|
146
|
+
'logging',
|
|
147
|
+
projectId + accessToken,
|
|
148
|
+
async () => MockClient,
|
|
149
|
+
{ projectId },
|
|
150
|
+
accessToken
|
|
151
|
+
);
|
|
152
|
+
const loggingHeaders =
|
|
153
|
+
await loggingClient.options.authClient.getRequestHeaders();
|
|
154
|
+
assert.ok(
|
|
155
|
+
!(loggingHeaders instanceof Map),
|
|
156
|
+
'Logging client headers should NOT be a Map'
|
|
157
|
+
);
|
|
158
|
+
assert.strictEqual(loggingHeaders.Authorization, `Bearer ${accessToken}`);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('passes additional options correctly', async () => {
|
|
162
|
+
const projectId = 'test-project-6';
|
|
163
|
+
const service = 'run';
|
|
164
|
+
const extraOpt = 'foo';
|
|
165
|
+
|
|
166
|
+
const client = await getClient(
|
|
167
|
+
service,
|
|
168
|
+
projectId,
|
|
169
|
+
async () => MockClient,
|
|
170
|
+
{ projectId, extraOpt },
|
|
171
|
+
null
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
assert.strictEqual(client.options.extraOpt, extraOpt);
|
|
175
|
+
});
|
|
176
|
+
});
|