From 71b79a4e7677e2a18001736be91c99176109f5bf Mon Sep 17 00:00:00 2001 From: Mossaab Stiri Date: Sat, 26 Jul 2025 22:45:10 +0200 Subject: [PATCH 1/3] feat: add conditional registration of modification tools based on read-only mode --- src/server/server.ts | 99 ++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index 486fbf1..18841d6 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -25,6 +25,9 @@ export class Server extends McpServer { }); this.argocdClient = new ArgoCDClient(serverInfo.argocdBaseUrl, serverInfo.argocdApiToken); + const isReadOnly = String(process.env.MCP_READ_ONLY ?? '').trim().toLowerCase() === 'true'; + + // Always register read/query tools this.addJsonOutputTool( 'list_applications', 'list_applications returns list of applications', @@ -45,35 +48,6 @@ export class Server extends McpServer { { applicationName: z.string() }, async ({ applicationName }) => await this.argocdClient.getApplication(applicationName) ); - this.addJsonOutputTool( - 'create_application', - 'create_application creates application', - { application: ApplicationSchema }, - async ({ application }) => - await this.argocdClient.createApplication(application as V1alpha1Application) - ); - this.addJsonOutputTool( - 'update_application', - 'update_application updates application', - { applicationName: z.string(), application: ApplicationSchema }, - async ({ applicationName, application }) => - await this.argocdClient.updateApplication( - applicationName, - application as V1alpha1Application - ) - ); - this.addJsonOutputTool( - 'delete_application', - 'delete_application deletes application', - { applicationName: z.string() }, - async ({ applicationName }) => await this.argocdClient.deleteApplication(applicationName) - ); - this.addJsonOutputTool( - 'sync_application', - 'sync_application syncs application', - { applicationName: z.string() }, - async ({ applicationName }) => await this.argocdClient.syncApplication(applicationName) - ); this.addJsonOutputTool( 'get_application_resource_tree', 'get_application_resource_tree returns resource tree for application by application name', @@ -176,23 +150,56 @@ export class Server extends McpServer { resourceRef as V1alpha1ResourceResult ) ); - this.addJsonOutputTool( - 'run_resource_action', - 'run_resource_action runs an action on a resource', - { - applicationName: z.string(), - applicationNamespace: ApplicationNamespaceSchema, - resourceRef: ResourceRefSchema, - action: z.string() - }, - async ({ applicationName, applicationNamespace, resourceRef, action }) => - await this.argocdClient.runResourceAction( - applicationName, - applicationNamespace, - resourceRef as V1alpha1ResourceResult, - action - ) - ); + + // Only register modification tools if not in read-only mode + if (!isReadOnly) { + this.addJsonOutputTool( + 'create_application', + 'create_application creates application', + { application: ApplicationSchema }, + async ({ application }) => + await this.argocdClient.createApplication(application as V1alpha1Application) + ); + this.addJsonOutputTool( + 'update_application', + 'update_application updates application', + { applicationName: z.string(), application: ApplicationSchema }, + async ({ applicationName, application }) => + await this.argocdClient.updateApplication( + applicationName, + application as V1alpha1Application + ) + ); + this.addJsonOutputTool( + 'delete_application', + 'delete_application deletes application', + { applicationName: z.string() }, + async ({ applicationName }) => await this.argocdClient.deleteApplication(applicationName) + ); + this.addJsonOutputTool( + 'sync_application', + 'sync_application syncs application', + { applicationName: z.string() }, + async ({ applicationName }) => await this.argocdClient.syncApplication(applicationName) + ); + this.addJsonOutputTool( + 'run_resource_action', + 'run_resource_action runs an action on a resource', + { + applicationName: z.string(), + applicationNamespace: ApplicationNamespaceSchema, + resourceRef: ResourceRefSchema, + action: z.string() + }, + async ({ applicationName, applicationNamespace, resourceRef, action }) => + await this.argocdClient.runResourceAction( + applicationName, + applicationNamespace, + resourceRef as V1alpha1ResourceResult, + action + ) + ); + } } private addJsonOutputTool( From 26997bc216199f618cea9a0621a73a07862b5a43 Mon Sep 17 00:00:00 2001 From: Mossaab Stiri Date: Sat, 26 Jul 2025 22:45:15 +0200 Subject: [PATCH 2/3] docs: add instructions for running MCP Server in ReadOnly mode --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 6ace6e2..e2e14bb 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,22 @@ This disables TLS certificate validation for Node.js when connecting to Argo CD > **Warning**: Disabling SSL verification reduces security. Use this setting only in development environments or when you understand the security implications. + +### Read Only Mode + +If you want to run the MCP Server in a ReadOnly mode to avoid resource or application modification, you should set the environment variable: +``` +"MCP_READ_ONLY": "true" +``` +This will disable the following tools: +- `create_application` +- `update_application` +- `delete_application` +- `sync_application` +- `run_resource_action` + +By default, all the tools will be available. + ## Available Tools The server provides the following ArgoCD management tools: From edbdc59e97a2e08af2de668e47180c01f3a869f8 Mon Sep 17 00:00:00 2001 From: Jiacheng Xu Date: Fri, 8 Aug 2025 15:46:48 +0800 Subject: [PATCH 3/3] fix lint --- src/server/server.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/server/server.ts b/src/server/server.ts index 18841d6..74a623e 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -25,7 +25,10 @@ export class Server extends McpServer { }); this.argocdClient = new ArgoCDClient(serverInfo.argocdBaseUrl, serverInfo.argocdApiToken); - const isReadOnly = String(process.env.MCP_READ_ONLY ?? '').trim().toLowerCase() === 'true'; + const isReadOnly = + String(process.env.MCP_READ_ONLY ?? '') + .trim() + .toLowerCase() === 'true'; // Always register read/query tools this.addJsonOutputTool(