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: diff --git a/src/server/server.ts b/src/server/server.ts index 486fbf1..74a623e 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -25,6 +25,12 @@ 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 +51,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 +153,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(