@google-cloud/cloud-run-mcp 1.3.0 → 1.5.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.
@@ -3,7 +3,7 @@ Copyright 2025 Google LLC
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
6
- you may obtain a copy of the License at
6
+ You may obtain a copy of the License at
7
7
 
8
8
  https://www.apache.org/licenses/LICENSE-2.0
9
9
 
@@ -15,18 +15,18 @@ limitations under the License.
15
15
  */
16
16
 
17
17
  import { z } from 'zod';
18
- import { deploy, deployImage } from './lib/cloud-run-deploy.js';
19
- import {
20
- listServices,
21
- getService,
22
- getServiceLogs,
23
- } from './lib/cloud-run-services.js';
24
- import {
25
- listProjects,
26
- createProjectAndAttachBilling,
27
- } from './lib/gcp-projects.js';
28
-
29
- import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
18
+ import { listProjects, createProjectAndAttachBilling } from '../lib/gcp-projects.js';
19
+ import { listServices, getService, getServiceLogs } from '../lib/cloud-run-services.js';
20
+ import { deploy, deployImage } from '../lib/cloud-run-deploy.js';
21
+
22
+ function createProgressCallback(sendNotification) {
23
+ return (progress) => {
24
+ sendNotification({
25
+ method: 'notifications/message',
26
+ params: { level: progress.level || 'info', data: progress.data },
27
+ });
28
+ };
29
+ }
30
30
 
31
31
  function gcpTool(gcpCredentialsAvailable, fn) {
32
32
  if (!gcpCredentialsAvailable) {
@@ -42,24 +42,15 @@ function gcpTool(gcpCredentialsAvailable, fn) {
42
42
  return fn;
43
43
  }
44
44
 
45
- export const registerTools = (
46
- server,
47
- {
48
- defaultProjectId,
49
- defaultRegion,
50
- defaultServiceName,
51
- skipIamCheck,
52
- gcpCredentialsAvailable,
53
- } = {}
54
- ) => {
55
- // Tool to list GCP projects
45
+ // Tool to list GCP projects
46
+ function registerListProjectsTool(server, options) {
56
47
  server.registerTool(
57
48
  'list_projects',
58
49
  {
59
50
  description: 'Lists available GCP projects',
60
51
  inputSchema: {},
61
52
  },
62
- gcpTool(gcpCredentialsAvailable, async () => {
53
+ gcpTool(options.gcpCredentialsAvailable, async () => {
63
54
  try {
64
55
  const projects = await listProjects();
65
56
  return {
@@ -82,8 +73,10 @@ export const registerTools = (
82
73
  }
83
74
  })
84
75
  );
76
+ }
85
77
 
86
- // Tool to create a new GCP project
78
+ // Tool to create a new GCP project
79
+ function registerCreateProjectTool(server, options) {
87
80
  server.registerTool(
88
81
  'create_project',
89
82
  {
@@ -98,7 +91,7 @@ export const registerTools = (
98
91
  ),
99
92
  },
100
93
  },
101
- gcpTool(gcpCredentialsAvailable, async ({ projectId }) => {
94
+ gcpTool(options.gcpCredentialsAvailable, async ({ projectId }) => {
102
95
  if (
103
96
  projectId !== undefined &&
104
97
  (typeof projectId !== 'string' || projectId.trim() === '')
@@ -134,8 +127,10 @@ export const registerTools = (
134
127
  }
135
128
  })
136
129
  );
130
+ }
137
131
 
138
- // Listing Cloud Run services
132
+ // Listing Cloud Run services
133
+ function registerListServicesTool(server, options) {
139
134
  server.registerTool(
140
135
  'list_services',
141
136
  {
@@ -144,14 +139,14 @@ export const registerTools = (
144
139
  project: z
145
140
  .string()
146
141
  .describe('Google Cloud project ID')
147
- .default(defaultProjectId),
142
+ .default(options.defaultProjectId),
148
143
  region: z
149
144
  .string()
150
145
  .describe('Region where the services are located')
151
- .default(defaultRegion),
146
+ .default(options.defaultRegion),
152
147
  },
153
148
  },
154
- gcpTool(gcpCredentialsAvailable, async ({ project, region }) => {
149
+ gcpTool(options.gcpCredentialsAvailable, async ({ project, region }) => {
155
150
  if (typeof project !== 'string') {
156
151
  return {
157
152
  content: [
@@ -191,8 +186,10 @@ export const registerTools = (
191
186
  }
192
187
  })
193
188
  );
189
+ }
194
190
 
195
- // Dynamic resource for getting a specific service
191
+ // Dynamic resource for getting a specific service
192
+ function registerGetServiceTool(server, options) {
196
193
  server.registerTool(
197
194
  'get_service',
198
195
  {
@@ -201,18 +198,18 @@ export const registerTools = (
201
198
  project: z
202
199
  .string()
203
200
  .describe('Google Cloud project ID containing the service')
204
- .default(defaultProjectId),
201
+ .default(options.defaultProjectId),
205
202
  region: z
206
203
  .string()
207
204
  .describe('Region where the service is located')
208
- .default(defaultRegion),
205
+ .default(options.defaultRegion),
209
206
  service: z
210
207
  .string()
211
208
  .describe('Name of the Cloud Run service')
212
- .default(defaultServiceName),
209
+ .default(options.defaultServiceName),
213
210
  },
214
211
  },
215
- gcpTool(gcpCredentialsAvailable, async ({ project, region, service }) => {
212
+ gcpTool(options.gcpCredentialsAvailable, async ({ project, region, service }) => {
216
213
  if (typeof project !== 'string') {
217
214
  return {
218
215
  content: [
@@ -260,8 +257,10 @@ export const registerTools = (
260
257
  }
261
258
  })
262
259
  );
260
+ }
263
261
 
264
- // Logs for a service
262
+ // Get logs for a service
263
+ function registerGetServiceLogTool(server, options) {
265
264
  server.registerTool(
266
265
  'get_service_log',
267
266
  {
@@ -271,18 +270,18 @@ export const registerTools = (
271
270
  project: z
272
271
  .string()
273
272
  .describe('Google Cloud project ID containing the service')
274
- .default(defaultProjectId),
273
+ .default(options.defaultProjectId),
275
274
  region: z
276
275
  .string()
277
276
  .describe('Region where the service is located')
278
- .default(defaultRegion),
277
+ .default(options.defaultRegion),
279
278
  service: z
280
279
  .string()
281
280
  .describe('Name of the Cloud Run service')
282
- .default(defaultServiceName),
281
+ .default(options.defaultServiceName),
283
282
  },
284
283
  },
285
- gcpTool(gcpCredentialsAvailable, async ({ project, region, service }) => {
284
+ gcpTool(options.gcpCredentialsAvailable, async ({ project, region, service }) => {
286
285
  let allLogs = [];
287
286
  let requestOptions;
288
287
  try {
@@ -323,83 +322,10 @@ export const registerTools = (
323
322
  }
324
323
  })
325
324
  );
325
+ }
326
326
 
327
- server.registerTool(
328
- 'deploy_local_files',
329
- {
330
- description:
331
- 'Deploy local files to Cloud Run. Takes an array of absolute file paths from the local filesystem that will be deployed. Use this tool if the files exists on the user local filesystem.',
332
- inputSchema: {
333
- project: z
334
- .string()
335
- .describe(
336
- 'Google Cloud project ID. Do not select it yourself, make sure the user provides or confirms the project ID.'
337
- )
338
- .default(defaultProjectId),
339
- region: z
340
- .string()
341
- .optional()
342
- .default(defaultRegion)
343
- .describe('Region to deploy the service to'),
344
- service: z
345
- .string()
346
- .optional()
347
- .default(defaultServiceName)
348
- .describe('Name of the Cloud Run service to deploy to'),
349
- files: z
350
- .array(z.string())
351
- .describe(
352
- 'Array of absolute file paths to deploy (e.g. ["/home/user/project/src/index.js", "/home/user/project/package.json"])'
353
- ),
354
- },
355
- },
356
- gcpTool(
357
- gcpCredentialsAvailable,
358
- async ({ project, region, service, files }) => {
359
- if (typeof project !== 'string') {
360
- throw new Error(
361
- 'Project must specified, please prompt the user for a valid existing Google Cloud project ID.'
362
- );
363
- }
364
- if (typeof files !== 'object' || !Array.isArray(files)) {
365
- throw new Error('Files must specified');
366
- }
367
- if (files.length === 0) {
368
- throw new Error('No files specified for deployment');
369
- }
370
-
371
- // Deploy to Cloud Run
372
- try {
373
- // TODO: Should we return intermediate progress messages? we'd need to use sendNotification for that, see https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/examples/server/jsonResponseStreamableHttp.ts#L46C24-L46C41
374
- const response = await deploy({
375
- projectId: project,
376
- serviceName: service,
377
- region: region,
378
- files: files,
379
- skipIamCheck: skipIamCheck, // Pass the new flag
380
- });
381
- return {
382
- content: [
383
- {
384
- type: 'text',
385
- text: `Cloud Run service ${service} deployed in project ${project}\nCloud Console: https://console.cloud.google.com/run/detail/${region}/${service}?project=${project}\nService URL: ${response.uri}`,
386
- },
387
- ],
388
- };
389
- } catch (error) {
390
- return {
391
- content: [
392
- {
393
- type: 'text',
394
- text: `Error deploying to Cloud Run: ${error.message || error}`,
395
- },
396
- ],
397
- };
398
- }
399
- }
400
- )
401
- );
402
-
327
+ // Tool to deploy to Cloud Run from local folder
328
+ function registerDeployLocalFolderTool(server, options) {
403
329
  server.registerTool(
404
330
  'deploy_local_folder',
405
331
  {
@@ -411,16 +337,16 @@ export const registerTools = (
411
337
  .describe(
412
338
  'Google Cloud project ID. Do not select it yourself, make sure the user provides or confirms the project ID.'
413
339
  )
414
- .default(defaultProjectId),
340
+ .default(options.defaultProjectId),
415
341
  region: z
416
342
  .string()
417
343
  .optional()
418
- .default(defaultRegion)
344
+ .default(options.defaultRegion)
419
345
  .describe('Region to deploy the service to'),
420
346
  service: z
421
347
  .string()
422
348
  .optional()
423
- .default(defaultServiceName)
349
+ .default(options.defaultServiceName)
424
350
  .describe('Name of the Cloud Run service to deploy to'),
425
351
  folderPath: z
426
352
  .string()
@@ -430,8 +356,11 @@ export const registerTools = (
430
356
  },
431
357
  },
432
358
  gcpTool(
433
- gcpCredentialsAvailable,
434
- async ({ project, region, service, folderPath }) => {
359
+ options.gcpCredentialsAvailable,
360
+ async (
361
+ { project, region, service, folderPath },
362
+ { sendNotification }
363
+ ) => {
435
364
  if (typeof project !== 'string') {
436
365
  throw new Error(
437
366
  'Project must be specified, please prompt the user for a valid existing Google Cloud project ID.'
@@ -443,14 +372,20 @@ export const registerTools = (
443
372
  );
444
373
  }
445
374
 
375
+ const progressCallback = createProgressCallback(sendNotification);
376
+
446
377
  // Deploy to Cloud Run
447
378
  try {
379
+ await progressCallback({
380
+ data: `Starting deployment of local folder for service ${service} in project ${project}...`,
381
+ });
448
382
  const response = await deploy({
449
383
  projectId: project,
450
384
  serviceName: service,
451
385
  region: region,
452
386
  files: [folderPath],
453
- skipIamCheck: skipIamCheck, // Pass the new flag
387
+ skipIamCheck: options.skipIamCheck, // Pass the new flag
388
+ progressCallback,
454
389
  });
455
390
  return {
456
391
  content: [
@@ -473,7 +408,10 @@ export const registerTools = (
473
408
  }
474
409
  )
475
410
  );
411
+ }
476
412
 
413
+ // Tool to deploy to Cloud Run from file contents
414
+ function registerDeployFileContentsTool(server, options) {
477
415
  server.registerTool(
478
416
  'deploy_file_contents',
479
417
  {
@@ -485,16 +423,16 @@ export const registerTools = (
485
423
  .describe(
486
424
  'Google Cloud project ID. Leave unset for the app to be deployed in a new project. If provided, make sure the user confirms the project ID they want to deploy to.'
487
425
  )
488
- .default(defaultProjectId),
426
+ .default(options.defaultProjectId),
489
427
  region: z
490
428
  .string()
491
429
  .optional()
492
- .default(defaultRegion)
430
+ .default(options.defaultRegion)
493
431
  .describe('Region to deploy the service to'),
494
432
  service: z
495
433
  .string()
496
434
  .optional()
497
- .default(defaultServiceName)
435
+ .default(options.defaultServiceName)
498
436
  .describe('Name of the Cloud Run service to deploy to'),
499
437
  files: z
500
438
  .array(
@@ -514,8 +452,8 @@ export const registerTools = (
514
452
  },
515
453
  },
516
454
  gcpTool(
517
- gcpCredentialsAvailable,
518
- async ({ project, region, service, files }) => {
455
+ options.gcpCredentialsAvailable,
456
+ async ({ project, region, service, files }, { sendNotification }) => {
519
457
  if (typeof project !== 'string') {
520
458
  throw new Error(
521
459
  'Project must specified, please prompt the user for a valid existing Google Cloud project ID.'
@@ -535,14 +473,20 @@ export const registerTools = (
535
473
  }
536
474
  }
537
475
 
476
+ const progressCallback = createProgressCallback(sendNotification);
477
+
538
478
  // Deploy to Cloud Run
539
479
  try {
480
+ await progressCallback({
481
+ data: `Starting deployment of file contents for service ${service} in project ${project}...`,
482
+ });
540
483
  const response = await deploy({
541
484
  projectId: project,
542
485
  serviceName: service,
543
486
  region: region,
544
487
  files: files,
545
- skipIamCheck: skipIamCheck, // Pass the new flag
488
+ skipIamCheck: options.skipIamCheck, // Pass the new flag
489
+ progressCallback,
546
490
  });
547
491
  return {
548
492
  content: [
@@ -565,7 +509,10 @@ export const registerTools = (
565
509
  }
566
510
  )
567
511
  );
512
+ }
568
513
 
514
+ // Tool to deploy to Cloud Run from container image
515
+ function registerDeployContainerImageTool(server, options) {
569
516
  server.registerTool(
570
517
  'deploy_container_image',
571
518
  {
@@ -577,16 +524,16 @@ export const registerTools = (
577
524
  .describe(
578
525
  'Google Cloud project ID. Do not select it yourself, make sure the user provides or confirms the project ID.'
579
526
  )
580
- .default(defaultProjectId),
527
+ .default(options.defaultProjectId),
581
528
  region: z
582
529
  .string()
583
530
  .optional()
584
- .default(defaultRegion)
531
+ .default(options.defaultRegion)
585
532
  .describe('Region to deploy the service to'),
586
533
  service: z
587
534
  .string()
588
535
  .optional()
589
- .default(defaultServiceName)
536
+ .default(options.defaultServiceName)
590
537
  .describe('Name of the Cloud Run service to deploy to'),
591
538
  imageUrl: z
592
539
  .string()
@@ -596,8 +543,8 @@ export const registerTools = (
596
543
  },
597
544
  },
598
545
  gcpTool(
599
- gcpCredentialsAvailable,
600
- async ({ project, region, service, imageUrl }) => {
546
+ options.gcpCredentialsAvailable,
547
+ async ({ project, region, service, imageUrl }, { sendNotification }) => {
601
548
  if (typeof project !== 'string') {
602
549
  throw new Error(
603
550
  'Project must specified, please prompt the user for a valid existing Google Cloud project ID.'
@@ -609,6 +556,8 @@ export const registerTools = (
609
556
  );
610
557
  }
611
558
 
559
+ const progressCallback = createProgressCallback(sendNotification);
560
+
612
561
  // Deploy to Cloud Run
613
562
  try {
614
563
  const response = await deployImage({
@@ -616,7 +565,8 @@ export const registerTools = (
616
565
  serviceName: service,
617
566
  region: region,
618
567
  imageUrl: imageUrl,
619
- skipIamCheck: skipIamCheck,
568
+ skipIamCheck: options.skipIamCheck,
569
+ progressCallback,
620
570
  });
621
571
  return {
622
572
  content: [
@@ -639,331 +589,15 @@ export const registerTools = (
639
589
  }
640
590
  )
641
591
  );
642
- };
643
-
644
- export const registerToolsRemote = async (
645
- server,
646
- {
647
- defaultProjectId,
648
- defaultRegion,
649
- defaultServiceName,
650
- skipIamCheck = false,
651
- gcpCredentialsAvailable,
652
- } = {}
653
- ) => {
654
- // We no longer call checkGCP here; the effective defaults are passed in.
655
- const currentProject = defaultProjectId; // Use the passed effective project ID
656
- const currentRegion = defaultRegion; // Use the passed effective region
657
-
658
- if (!currentProject) {
659
- throw new Error(
660
- 'Cannot register remote tools: GCP project ID could not be determined. Please ensure GOOGLE_CLOUD_PROJECT environment variable is set or the server is running on GCP.'
661
- );
662
- }
663
-
664
- // Listing Cloud Run services (Remote)
665
- server.registerTool(
666
- 'list_services',
667
- {
668
- description: `Lists Cloud Run services in GCP project ${currentProject} and a given region.`,
669
- inputSchema: {
670
- region: z
671
- .string()
672
- .describe('Region where the services are located')
673
- .default(currentRegion),
674
- },
675
- },
676
- gcpTool(gcpCredentialsAvailable, async ({ region }) => {
677
- try {
678
- const services = await listServices(currentProject, region);
679
- const serviceList = services
680
- .map((s) => {
681
- const serviceName = s.name.split('/').pop();
682
- return `- ${serviceName} (URL: ${s.uri})`;
683
- })
684
- .join('\n');
685
- return {
686
- content: [
687
- {
688
- type: 'text',
689
- text: `Services in project ${currentProject} (location ${region}):\n${serviceList}`,
690
- },
691
- ],
692
- };
693
- } catch (error) {
694
- return {
695
- content: [
696
- {
697
- type: 'text',
698
- text: `Error listing services for project ${currentProject} (region ${currentRegion}): ${error.message}`,
699
- },
700
- ],
701
- };
702
- }
703
- })
704
- );
705
-
706
- // Dynamic resource for getting a specific service (Remote)
707
- server.registerTool(
708
- 'get_service',
709
- {
710
- description: `Gets details for a specific Cloud Run service in GCP project ${currentProject}.`,
711
- inputSchema: {
712
- region: z
713
- .string()
714
- .describe('Region where the service is located')
715
- .default(currentRegion),
716
- service: z
717
- .string()
718
- .describe('Name of the Cloud Run service')
719
- .default(defaultServiceName),
720
- },
721
- },
722
- gcpTool(gcpCredentialsAvailable, async ({ region, service }) => {
723
- if (typeof service !== 'string') {
724
- return {
725
- content: [
726
- { type: 'text', text: 'Error: Service name must be provided.' },
727
- ],
728
- };
729
- }
730
- try {
731
- const serviceDetails = await getService(
732
- currentProject,
733
- region,
734
- service
735
- );
736
- if (serviceDetails) {
737
- return {
738
- content: [
739
- {
740
- type: 'text',
741
- text: `Name: ${service}\nRegion: ${region}\nProject: ${currentProject}\nURL: ${serviceDetails.uri}\nLast deployed by: ${serviceDetails.lastModifier}`,
742
- },
743
- ],
744
- };
745
- } else {
746
- return {
747
- content: [
748
- {
749
- type: 'text',
750
- text: `Service ${service} not found in project ${currentProject} (region ${currentRegion}).`,
751
- },
752
- ],
753
- };
754
- }
755
- } catch (error) {
756
- return {
757
- content: [
758
- {
759
- type: 'text',
760
- text: `Error getting service ${service} in project ${currentProject} (region ${currentRegion}): ${error.message}`,
761
- },
762
- ],
763
- };
764
- }
765
- })
766
- );
767
-
768
- // Logs for a service
769
- server.registerTool(
770
- 'get_service_log',
771
- {
772
- description:
773
- 'Gets Logs and Error Messages for a specific Cloud Run service.',
774
- inputSchema: {
775
- project: z
776
- .string()
777
- .describe('Google Cloud project ID containing the service')
778
- .default(currentProject), // Use currentProject
779
- region: z
780
- .string()
781
- .describe('Region where the service is located')
782
- .default(currentRegion), // Use currentRegion
783
- service: z
784
- .string()
785
- .describe('Name of the Cloud Run service')
786
- .default(defaultServiceName),
787
- },
788
- },
789
- gcpTool(gcpCredentialsAvailable, async ({ project, region, service }) => {
790
- let allLogs = [];
791
- let requestOptions;
792
- try {
793
- do {
794
- // Fetch a page of logs
795
- const response = await getServiceLogs(
796
- project,
797
- region,
798
- service,
799
- requestOptions
800
- );
801
-
802
- if (response.logs) {
803
- allLogs.push(response.logs);
804
- }
805
-
806
- // Set the requestOptions incl pagintion token for the next iteration
807
-
808
- requestOptions = response.requestOptions;
809
- } while (requestOptions); // Continue as long as there is a next page token
810
- return {
811
- content: [
812
- {
813
- type: 'text',
814
- text: allLogs.join('\n'),
815
- },
816
- ],
817
- };
818
- } catch (error) {
819
- return {
820
- content: [
821
- {
822
- type: 'text',
823
- text: `Error getting Logs for service ${service} in project ${project} (region ${region}): ${error.message}`,
824
- },
825
- ],
826
- };
827
- }
828
- })
829
- );
830
-
831
- // Deploy file contents to Cloud Run (Remote)
832
- server.registerTool(
833
- 'deploy_file_contents',
834
- {
835
- description: `Deploy files to Cloud Run by providing their contents directly to the GCP project ${currentProject}.`,
836
- inputSchema: {
837
- region: z
838
- .string()
839
- .optional()
840
- .default(currentRegion)
841
- .describe('Region to deploy the service to'),
842
- service: z
843
- .string()
844
- .optional()
845
- .default(defaultServiceName)
846
- .describe('Name of the Cloud Run service to deploy to'), // Use defaultServiceName
847
- files: z
848
- .array(
849
- z.object({
850
- filename: z
851
- .string()
852
- .describe(
853
- 'Name and path of the file (e.g. "src/index.js" or "data/config.json")'
854
- ),
855
- content: z.string().describe('Text content of the file'),
856
- })
857
- )
858
- .describe('Array of file objects containing filename and content'),
859
- },
860
- },
861
- gcpTool(gcpCredentialsAvailable, async ({ region, service, files }) => {
862
- console.log(
863
- `New deploy request (remote): ${JSON.stringify({ project: currentProject, region, service, files })}`
864
- );
865
-
866
- if (
867
- typeof files !== 'object' ||
868
- !Array.isArray(files) ||
869
- files.length === 0
870
- ) {
871
- throw new Error('Files must be specified');
872
- }
873
-
874
- // Validate that each file has content
875
- for (const file of files) {
876
- if (!file.content) {
877
- throw new Error(`File ${file.filename} must have content`);
878
- }
879
- }
880
-
881
- // Deploy to Cloud Run
882
- try {
883
- const response = await deploy({
884
- projectId: currentProject,
885
- serviceName: service,
886
- region: region,
887
- files: files,
888
- skipIamCheck: skipIamCheck, // Pass the new flag
889
- });
890
- return {
891
- content: [
892
- {
893
- type: 'text',
894
- text: `Cloud Run service ${service} deployed in project ${currentProject}\nCloud Console: https://console.cloud. google.com/run/detail/${region}/${service}?project=${currentProject}\nService URL: ${response.uri}`,
895
- },
896
- ],
897
- };
898
- } catch (error) {
899
- return {
900
- content: [
901
- {
902
- type: 'text',
903
- text: `Error deploying to Cloud Run: ${error.message || error}`,
904
- },
905
- ],
906
- };
907
- }
908
- })
909
- );
910
-
911
- server.registerTool(
912
- 'deploy_container_image',
913
- {
914
- description: `Deploys a container image to Cloud Run in the GCP project ${currentProject}. Use this tool if the user provides a container image URL.`,
915
- inputSchema: {
916
- region: z
917
- .string()
918
- .optional()
919
- .default(currentRegion)
920
- .describe('Region to deploy the service to'),
921
- service: z
922
- .string()
923
- .optional()
924
- .default(defaultServiceName)
925
- .describe('Name of the Cloud Run service to deploy to'),
926
- imageUrl: z
927
- .string()
928
- .describe(
929
- 'The URL of the container image to deploy (e.g. "gcr.io/cloudrun/hello")'
930
- ),
931
- },
932
- },
933
- gcpTool(gcpCredentialsAvailable, async ({ region, service, imageUrl }) => {
934
- if (typeof imageUrl !== 'string' || imageUrl.trim() === '') {
935
- throw new Error(
936
- 'Container image URL must be specified and be a non-empty string.'
937
- );
938
- }
592
+ }
939
593
 
940
- // Deploy to Cloud Run
941
- try {
942
- const response = await deployImage({
943
- projectId: currentProject,
944
- serviceName: service,
945
- region: region,
946
- imageUrl: imageUrl,
947
- skipIamCheck: skipIamCheck,
948
- });
949
- return {
950
- content: [
951
- {
952
- type: 'text',
953
- text: `Cloud Run service ${service} deployed in project ${currentProject}\nCloud Console: https://console.cloud. google.com/run/detail/${region}/${service}?project=${currentProject}\nService URL: ${response.uri}`,
954
- },
955
- ],
956
- };
957
- } catch (error) {
958
- return {
959
- content: [
960
- {
961
- type: 'text',
962
- text: `Error deploying to Cloud Run: ${error.message || error}`,
963
- },
964
- ],
965
- };
966
- }
967
- })
968
- );
594
+ export {
595
+ registerListProjectsTool,
596
+ registerCreateProjectTool,
597
+ registerListServicesTool,
598
+ registerGetServiceTool,
599
+ registerGetServiceLogTool,
600
+ registerDeployLocalFolderTool,
601
+ registerDeployFileContentsTool,
602
+ registerDeployContainerImageTool,
969
603
  };