UNPKG

devsecops-argocd-mcp

Version:
1,150 lines (1,137 loc) 38 kB
#!/usr/bin/env node var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/cmd/cmd.ts import yargs from "yargs"; import { hideBin } from "yargs/helpers"; // src/server/transport.ts import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import express from "express"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; // src/logging/logging.ts import { pino } from "pino"; import { stderr } from "process"; var logger = pino(pino.destination(stderr)); // src/server/server.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; // package.json var package_default = { name: "devsecops-argocd-mcp", version: "1.0.1", description: "DevSecOps hackathon ArgoCD MCP", repository: { type: "git", url: "git+https://github.com/wix-private/devsecops-argocd-mcp.git" }, keywords: [ "secops-argocd-mcp", "devsecops-argocd-mcp", "wix-secops-argocd-mcp", "mcp", "argocd", "argocd-mcp", "argocd-mcp-server", "argo-cd", "argo-cd-mcp", "argo-cd-mcp-server", "cicd", "cicd-mcp", "cicd-mcp-server", "gitops", "gitops-mcp", "gitops-mcp-server", "kubernetes", "kubernetes-mcp", "kubernetes-mcp-server" ], main: "dist/index.js", type: "module", bin: { "argocd-mcp": "dist/index.js" }, files: [ "dist", "images", "README.md", "LICENSE" ], scripts: { dev: "tsx watch src/index.ts http", "dev-sse": "tsx watch src/index.ts sse", "dev-stdio": "tsx watch src/index.ts stdio", lint: "eslint src/**/*.ts --no-warn-ignored", "lint:fix": "eslint src/**/*.ts --fix", build: "tsup", "build:watch": "tsup --watch", "generate-types": "dtsgen -c dtsgen.json -o src/types/argocd.d.ts swagger.json", prepare: "npm run build" }, author: "Akuity, Inc.", license: "Apache-2.0", dependencies: { "@modelcontextprotocol/sdk": "^1.10.1", dotenv: "^16.5.0", express: "^5.1.0", pino: "^9.6.0", yargs: "^17.7.2", zod: "^3.24.3" }, devDependencies: { "@dtsgenerator/replace-namespace": "^1.7.0", "@eslint/js": "^9.25.0", "@types/express": "^5.0.1", "@types/node": "^22.14.1", "@types/yargs": "^17.0.33", dtsgenerator: "^3.19.2", eslint: "^9.25.0", "eslint-config-prettier": "^10.1.2", "eslint-plugin-prettier": "^5.2.6", prettier: "3.5.3", tsup: "^8.4.0", tsx: "^4.19.3", typescript: "^5.8.3", "typescript-eslint": "^8.30.1" } }; // src/argocd/http.ts var HttpClient = class { constructor(baseUrl, apiToken) { this.baseUrl = baseUrl; this.apiToken = apiToken; this.headers = { Authorization: `Bearer ${this.apiToken}`, "Content-Type": "application/json" }; } request(url, params, init) { return __async(this, null, function* () { const urlObject = this.absUrl(url); if (params) { Object.entries(params).forEach(([key, value]) => { urlObject.searchParams.set(key, (value == null ? void 0 : value.toString()) || ""); }); } const response = yield fetch(urlObject, __spreadProps(__spreadValues({}, init), { headers: __spreadValues(__spreadValues({}, init == null ? void 0 : init.headers), this.headers) })); const body = yield response.json(); return { status: response.status, headers: response.headers, body }; }); } requestStream(url, params, cb, init) { return __async(this, null, function* () { var _a; const urlObject = this.absUrl(url); if (params) { Object.entries(params).forEach(([key, value]) => { urlObject.searchParams.set(key, (value == null ? void 0 : value.toString()) || ""); }); } const response = yield fetch(urlObject, __spreadProps(__spreadValues({}, init), { headers: __spreadValues(__spreadValues({}, init == null ? void 0 : init.headers), this.headers) })); const reader = (_a = response.body) == null ? void 0 : _a.getReader(); if (!reader) { throw new Error("response body is not readable"); } const decoder = new TextDecoder("utf-8"); let buffer = ""; while (true) { const { done, value } = yield reader.read(); if (done) { break; } buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop() || ""; for (const line of lines) { if (line.trim()) { const json = JSON.parse(line); cb == null ? void 0 : cb(json["result"]); } } } }); } absUrl(url) { if (url.startsWith("http://") || url.startsWith("https://")) { return new URL(url); } return new URL(url, this.baseUrl); } get(url, params) { return __async(this, null, function* () { const response = yield this.request(url, params); return response; }); } getStream(url, params, cb) { return __async(this, null, function* () { yield this.requestStream(url, params, cb); }); } post(url, params, body) { return __async(this, null, function* () { const response = yield this.request(url, params, { method: "POST", body: body ? JSON.stringify(body) : void 0 }); return response; }); } put(url, params, body) { return __async(this, null, function* () { const response = yield this.request(url, params, { method: "PUT", body: body ? JSON.stringify(body) : void 0 }); return response; }); } delete(url, params) { return __async(this, null, function* () { const response = yield this.request(url, params, { method: "DELETE" }); return response; }); } }; // src/argocd/client.ts var ArgoCDClient = class { constructor(baseUrl, apiToken) { this.baseUrl = baseUrl; this.apiToken = apiToken; this.client = new HttpClient(this.baseUrl, this.apiToken); } listApplications(params) { return __async(this, null, function* () { const { body } = yield this.client.get(`/api/v1/applications`, params); return body; }); } getApplication(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}` ); return body; }); } createApplication(application) { return __async(this, null, function* () { const { body } = yield this.client.post( `/api/v1/applications`, null, application ); return body; }); } updateApplication(applicationName, application) { return __async(this, null, function* () { const { body } = yield this.client.put( `/api/v1/applications/${applicationName}`, null, application ); return body; }); } deleteApplication(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.delete( `/api/v1/applications/${applicationName}` ); return body; }); } syncApplication(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.post( `/api/v1/applications/${applicationName}/sync` ); return body; }); } getApplicationResourceTree(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}/resource-tree` ); return body; }); } getApplicationManagedResources(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}/managed-resources` ); return body; }); } getApplicationLogs(applicationName) { return __async(this, null, function* () { const logs = []; yield this.client.getStream( `/api/v1/applications/${applicationName}/logs`, { follow: false, tailLines: 100 }, (chunk) => logs.push(chunk) ); return logs; }); } getWorkloadLogs(applicationName, applicationNamespace, resourceRef) { return __async(this, null, function* () { const logs = []; yield this.client.getStream( `/api/v1/applications/${applicationName}/logs`, { appNamespace: applicationNamespace, namespace: resourceRef.namespace, resourceName: resourceRef.name, group: resourceRef.group, kind: resourceRef.kind, version: resourceRef.version, follow: false, tailLines: 100 }, (chunk) => logs.push(chunk) ); return logs; }); } getPodLogs(applicationName, podName) { return __async(this, null, function* () { const logs = []; yield this.client.getStream( `/api/v1/applications/${applicationName}/pods/${podName}/logs`, { follow: false, tailLines: 100 }, (chunk) => logs.push(chunk) ); return logs; }); } getApplicationEvents(applicationName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}/events` ); return body; }); } getResourceEvents(applicationName, applicationNamespace, resourceUID, resourceNamespace, resourceName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}/events`, { appNamespace: applicationNamespace, resourceNamespace, resourceUID, resourceName } ); return body; }); } getResourceActions(applicationName, applicationNamespace, resourceRef) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applications/${applicationName}/resource/actions`, { appNamespace: applicationNamespace, namespace: resourceRef.namespace, resourceName: resourceRef.name, group: resourceRef.group, kind: resourceRef.kind, version: resourceRef.version } ); return body; }); } runResourceAction(applicationName, applicationNamespace, resourceRef, action) { return __async(this, null, function* () { const { body } = yield this.client.post( `/api/v1/applications/${applicationName}/resource/actions`, { appNamespace: applicationNamespace, namespace: resourceRef.namespace, resourceName: resourceRef.name, group: resourceRef.group, kind: resourceRef.kind, version: resourceRef.version }, action ); return body; }); } listClusters(params) { return __async(this, null, function* () { const { body } = yield this.client.get("/api/v1/clusters", params); return body; }); } createCluster(cluster, upsert) { return __async(this, null, function* () { const { body } = yield this.client.post( "/api/v1/clusters", upsert ? { upsert } : void 0, cluster ); return body; }); } // ApplicationSet methods listApplicationSets(params) { return __async(this, null, function* () { const { body } = yield this.client.get("/api/v1/applicationsets", params); return body; }); } getApplicationSet(applicationSetName) { return __async(this, null, function* () { const { body } = yield this.client.get( `/api/v1/applicationsets/${applicationSetName}` ); return body; }); } createApplicationSet(applicationSet) { return __async(this, null, function* () { const { body } = yield this.client.post( "/api/v1/applicationsets", null, applicationSet ); return body; }); } updateApplicationSet(applicationSetName, applicationSet) { return __async(this, null, function* () { const { body } = yield this.client.put( `/api/v1/applicationsets/${applicationSetName}`, null, applicationSet ); return body; }); } deleteApplicationSet(applicationSetName) { return __async(this, null, function* () { const { body } = yield this.client.delete( `/api/v1/applicationsets/${applicationSetName}` ); return body; }); } }; // src/server/server.ts import { z as z2 } from "zod"; // src/shared/models/schema.ts import { z } from "zod"; var ApplicationNamespaceSchema = z.string().describe( `The namespace of the application. Note that this may differ from the namespace of individual resources. Make sure to verify the application namespace in the Application resource \u2014 it is often argocd, but not always.` ); var ResourceRefSchema = z.object({ uid: z.string(), kind: z.string(), namespace: z.string(), name: z.string(), version: z.string(), group: z.string() }); var ApplicationSchema = z.object({ metadata: z.object({ name: z.string(), namespace: ApplicationNamespaceSchema }), spec: z.object({ project: z.string(), source: z.object({ repoURL: z.string(), path: z.string(), targetRevision: z.string() }), syncPolicy: z.object({ syncOptions: z.array(z.string()), automated: z.object({ prune: z.boolean(), selfHeal: z.boolean() }).optional(), retry: z.object({ limit: z.number(), backoff: z.object({ duration: z.string(), maxDuration: z.string(), factor: z.number() }) }) }), destination: z.object({ server: z.string().optional(), namespace: z.string().optional(), name: z.string().optional() }).refine( (data) => !data.server && !!data.name || !!data.server && !data.name, { message: "Only one of server or name must be specified in destination" } ).describe( `The destination of the application. Only one of server or name must be specified.` ) }) }); var ClusterConfigSchema = z.object({ tlsClientConfig: z.object({ insecure: z.boolean().optional(), caData: z.string().optional(), certData: z.string().optional(), keyData: z.string().optional(), serverName: z.string().optional() }).optional(), username: z.string().optional(), password: z.string().optional(), bearerToken: z.string().optional(), execProviderConfig: z.object({ command: z.string().optional(), args: z.array(z.string()).optional(), env: z.record(z.string()).optional(), apiVersion: z.string().optional(), installHint: z.string().optional() }).optional(), awsAuthConfig: z.object({ clusterName: z.string().optional(), roleARN: z.string().optional() }).optional() }).optional(); var ConnectionStateSchema = z.object({ status: z.string().optional(), message: z.string().optional(), attemptedAt: z.string().optional() }).optional(); var ClusterInfoSchema = z.object({ connectionState: ConnectionStateSchema, serverVersion: z.string().optional(), cacheInfo: z.object({ resourcesCount: z.number().optional(), apisCount: z.number().optional(), lastCacheSyncTime: z.string().optional() }).optional(), applicationsCount: z.number().optional(), apiVersions: z.array(z.string()).optional() }).optional(); var ClusterSchema = z.object({ annotations: z.record(z.string()).optional().describe("Annotations for cluster secret metadata"), clusterResources: z.boolean().optional().describe("Indicates if cluster level resources should be managed. This setting is used only if cluster is connected in a namespaced mode."), config: ClusterConfigSchema.describe("ClusterConfig is the configuration attributes"), connectionState: ConnectionStateSchema.describe("ConnectionState contains information about remote resource connection state"), info: ClusterInfoSchema.describe("ClusterInfo contains information about the cluster"), labels: z.record(z.string()).optional().describe("Labels for cluster secret metadata"), name: z.string().optional().describe("Name of the cluster. If omitted, will use the server address"), namespaces: z.array(z.string()).optional().describe("Holds list of namespaces which are accessible in that cluster. Cluster level resources will be ignored if namespace list is not empty."), project: z.string().optional().describe("Reference between project and cluster that allow you automatically to be added as item inside Destinations project entity"), refreshRequestedAt: z.string().optional().describe("Time when refresh was requested"), server: z.string().describe("Server is the API server URL of the Kubernetes cluster"), serverVersion: z.string().optional().describe("Deprecated: use Info.ServerVersion field instead. The server version"), shard: z.number().optional().describe("Shard contains optional shard number. Calculated on the fly by the application controller if not specified.") }); var ApplicationSetGeneratorSchema = z.object({ list: z.object({ elements: z.array(z.record(z.any())).optional(), template: z.record(z.any()).optional() }).optional(), clusters: z.object({ selector: z.object({ matchLabels: z.record(z.string()).optional(), matchExpressions: z.array(z.object({ key: z.string(), operator: z.string(), values: z.array(z.string()).optional() })).optional() }).optional(), template: z.record(z.any()).optional(), values: z.record(z.any()).optional() }).optional(), git: z.object({ repoURL: z.string(), revision: z.string().optional(), directories: z.array(z.object({ path: z.string(), exclude: z.boolean().optional() })).optional(), files: z.array(z.object({ path: z.string() })).optional(), template: z.record(z.any()).optional(), values: z.record(z.any()).optional() }).optional(), scmProvider: z.object({ github: z.object({ organization: z.string(), api: z.string().optional(), tokenRef: z.object({ secretName: z.string(), key: z.string() }).optional(), allBranches: z.boolean().optional() }).optional(), gitlab: z.object({ group: z.string(), api: z.string().optional(), tokenRef: z.object({ secretName: z.string(), key: z.string() }).optional(), allBranches: z.boolean().optional() }).optional(), template: z.record(z.any()).optional(), values: z.record(z.any()).optional() }).optional(), pullRequest: z.object({ github: z.object({ owner: z.string(), repo: z.string(), api: z.string().optional(), tokenRef: z.object({ secretName: z.string(), key: z.string() }).optional(), labels: z.array(z.string()).optional() }).optional(), gitlab: z.object({ project: z.string(), api: z.string().optional(), tokenRef: z.object({ secretName: z.string(), key: z.string() }).optional(), labels: z.array(z.string()).optional() }).optional(), template: z.record(z.any()).optional(), values: z.record(z.any()).optional() }).optional(), matrix: z.object({ generators: z.array(z.lazy(() => ApplicationSetGeneratorSchema)).optional(), template: z.record(z.any()).optional() }).optional(), merge: z.object({ generators: z.array(z.lazy(() => ApplicationSetGeneratorSchema)).optional(), mergeKeys: z.array(z.string()).optional(), template: z.record(z.any()).optional() }).optional() }); var ApplicationSetSchema = z.object({ metadata: z.object({ name: z.string(), namespace: ApplicationNamespaceSchema, labels: z.record(z.string()).optional(), annotations: z.record(z.string()).optional() }), spec: z.object({ generators: z.array(ApplicationSetGeneratorSchema), template: z.object({ metadata: z.object({ name: z.string(), namespace: z.string().optional(), labels: z.record(z.string()).optional(), annotations: z.record(z.string()).optional() }), spec: z.object({ project: z.string(), source: z.object({ repoURL: z.string(), path: z.string(), targetRevision: z.string(), helm: z.object({ valueFiles: z.array(z.string()).optional(), parameters: z.array(z.object({ name: z.string(), value: z.string(), forceString: z.boolean().optional() })).optional(), values: z.string().optional() }).optional(), kustomize: z.object({ namePrefix: z.string().optional(), nameSuffix: z.string().optional(), images: z.array(z.string()).optional(), commonLabels: z.record(z.string()).optional(), commonAnnotations: z.record(z.string()).optional() }).optional() }), destination: z.object({ server: z.string().optional(), namespace: z.string().optional(), name: z.string().optional() }), syncPolicy: z.object({ syncOptions: z.array(z.string()).optional(), automated: z.object({ prune: z.boolean().optional(), selfHeal: z.boolean().optional() }).optional(), retry: z.object({ limit: z.number().optional(), backoff: z.object({ duration: z.string().optional(), maxDuration: z.string().optional(), factor: z.number().optional() }).optional() }).optional() }).optional() }) }), syncPolicy: z.object({ preserveResourcesOnDeletion: z.boolean().optional() }).optional(), goTemplate: z.boolean().optional(), goTemplateOptions: z.array(z.string()).optional() }) }); // src/server/server.ts var Server = class extends McpServer { constructor(serverInfo) { super({ name: package_default.name, version: package_default.version }); this.argocdClient = new ArgoCDClient(serverInfo.argocdBaseUrl, serverInfo.argocdApiToken); this.addJsonOutputTool( "list_applications", "list_applications returns list of applications", { search: z2.string().optional().describe( 'Search applications by name. This is a partial match on the application name and does not support glob patterns (e.g. "*"). Optional.' ) }, (_0) => __async(this, [_0], function* ({ search }) { return yield this.argocdClient.listApplications({ search: search != null ? search : void 0 }); }) ); this.addJsonOutputTool( "get_application", "get_application returns application by application name", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.getApplication(applicationName); }) ); this.addJsonOutputTool( "create_application", "create_application creates application", { application: ApplicationSchema }, (_0) => __async(this, [_0], function* ({ application }) { return yield this.argocdClient.createApplication(application); }) ); this.addJsonOutputTool( "update_application", "update_application updates application", { applicationName: z2.string(), application: ApplicationSchema }, (_0) => __async(this, [_0], function* ({ applicationName, application }) { return yield this.argocdClient.updateApplication( applicationName, application ); }) ); this.addJsonOutputTool( "delete_application", "delete_application deletes application", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.deleteApplication(applicationName); }) ); this.addJsonOutputTool( "sync_application", "sync_application syncs application", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.syncApplication(applicationName); }) ); this.addJsonOutputTool( "get_application_resource_tree", "get_application_resource_tree returns resource tree for application by application name", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.getApplicationResourceTree(applicationName); }) ); this.addJsonOutputTool( "get_application_managed_resources", "get_application_managed_resources returns managed resources for application by application name", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.getApplicationManagedResources(applicationName); }) ); this.addJsonOutputTool( "get_application_workload_logs", "get_application_workload_logs returns logs for application workload (Deployment, StatefulSet, Pod, etc.) by application name and resource ref", { applicationName: z2.string(), applicationNamespace: ApplicationNamespaceSchema, resourceRef: ResourceRefSchema }, (_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceRef }) { return yield this.argocdClient.getWorkloadLogs( applicationName, applicationNamespace, resourceRef ); }) ); this.addJsonOutputTool( "get_application_events", "get_application_events returns events for application by application name", { applicationName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName }) { return yield this.argocdClient.getApplicationEvents(applicationName); }) ); this.addJsonOutputTool( "get_resource_events", "get_resource_events returns events for a resource that is managed by an application", { applicationName: z2.string(), applicationNamespace: ApplicationNamespaceSchema, resourceUID: z2.string(), resourceNamespace: z2.string(), resourceName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceUID, resourceNamespace, resourceName }) { return yield this.argocdClient.getResourceEvents( applicationName, applicationNamespace, resourceUID, resourceNamespace, resourceName ); }) ); this.addJsonOutputTool( "get_resource_actions", "get_resource_actions returns actions for a resource that is managed by an application", { applicationName: z2.string(), applicationNamespace: ApplicationNamespaceSchema, resourceRef: ResourceRefSchema }, (_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceRef }) { return yield this.argocdClient.getResourceActions( applicationName, applicationNamespace, resourceRef ); }) ); this.addJsonOutputTool( "run_resource_action", "run_resource_action runs an action on a resource", { applicationName: z2.string(), applicationNamespace: ApplicationNamespaceSchema, resourceRef: ResourceRefSchema, action: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceRef, action }) { return yield this.argocdClient.runResourceAction( applicationName, applicationNamespace, resourceRef, action ); }) ); this.addJsonOutputTool( "list_clusters", "list_clusters returns list of clusters registered with ArgoCD", { server: z2.string().optional(), name: z2.string().optional(), idType: z2.string().optional().describe('Type of cluster identifier ("server" - default, "name")'), idValue: z2.string().optional().describe("Cluster server URL or cluster name") }, (_0) => __async(this, [_0], function* ({ server, name, idType, idValue }) { return yield this.argocdClient.listClusters({ server, name, idType, idValue }); }) ); this.addJsonOutputTool( "create_cluster", "create_cluster creates a cluster", { cluster: ClusterSchema, upsert: z2.boolean().optional().describe("If true, updates the cluster if it already exists") }, (_0) => __async(this, [_0], function* ({ cluster, upsert }) { return yield this.argocdClient.createCluster(cluster, upsert); }) ); this.addJsonOutputTool( "list_applicationsets", "list_applicationsets returns list of ApplicationSets", { search: z2.string().optional().describe( 'Search ApplicationSets by name. This is a partial match on the ApplicationSet name and does not support glob patterns (e.g. "*"). Optional.' ), project: z2.string().optional().describe("Filter ApplicationSets by project. Optional.") }, (_0) => __async(this, [_0], function* ({ search, project }) { return yield this.argocdClient.listApplicationSets({ search: search != null ? search : void 0, project: project != null ? project : void 0 }); }) ); this.addJsonOutputTool( "get_applicationset", "get_applicationset returns ApplicationSet by ApplicationSet name", { applicationSetName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationSetName }) { return yield this.argocdClient.getApplicationSet(applicationSetName); }) ); this.addJsonOutputTool( "create_applicationset", "create_applicationset creates ApplicationSet", { applicationSet: ApplicationSetSchema }, (_0) => __async(this, [_0], function* ({ applicationSet }) { return yield this.argocdClient.createApplicationSet(applicationSet); }) ); this.addJsonOutputTool( "update_applicationset", "update_applicationset updates ApplicationSet", { applicationSetName: z2.string(), applicationSet: ApplicationSetSchema }, (_0) => __async(this, [_0], function* ({ applicationSetName, applicationSet }) { return yield this.argocdClient.updateApplicationSet( applicationSetName, applicationSet ); }) ); this.addJsonOutputTool( "delete_applicationset", "delete_applicationset deletes ApplicationSet", { applicationSetName: z2.string() }, (_0) => __async(this, [_0], function* ({ applicationSetName }) { return yield this.argocdClient.deleteApplicationSet(applicationSetName); }) ); } addJsonOutputTool(name, description, paramsSchema, cb) { this.tool(name, description, paramsSchema, (...args) => __async(this, null, function* () { try { const result = yield cb.apply(this, args); return { isError: false, content: [{ type: "text", text: JSON.stringify(result) }] }; } catch (error) { return { isError: true, content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }] }; } })); } }; var createServer = (serverInfo) => { return new Server(serverInfo); }; // src/server/transport.ts import { randomUUID } from "node:crypto"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"; var connectStdioTransport = () => { const server = createServer({ argocdBaseUrl: process.env.ARGOCD_BASE_URL || "", argocdApiToken: process.env.ARGOCD_API_TOKEN || "" }); logger.info("Connecting to stdio transport"); server.connect(new StdioServerTransport()); }; var connectSSETransport = (port) => { const app = express(); const transports = {}; app.get("/sse", (req, res) => __async(void 0, null, function* () { const server = createServer({ argocdBaseUrl: req.headers["x-argocd-base-url"] || "", argocdApiToken: req.headers["x-argocd-api-token"] || "" }); const transport = new SSEServerTransport("/messages", res); transports[transport.sessionId] = transport; res.on("close", () => { delete transports[transport.sessionId]; }); yield server.connect(transport); })); app.post("/messages", (req, res) => __async(void 0, null, function* () { const sessionId = req.query.sessionId; const transport = transports[sessionId]; if (transport) { yield transport.handlePostMessage(req, res); } else { res.status(400).send(`No transport found for sessionId: ${sessionId}`); } })); logger.info(`Connecting to SSE transport on port: ${port}`); app.listen(port); }; var connectHttpTransport = (port) => { const app = express(); app.use(express.json()); const httpTransports = {}; app.post("/mcp", (req, res) => __async(void 0, null, function* () { var _a; const sessionIdFromHeader = req.headers["mcp-session-id"]; let transport; if (sessionIdFromHeader && httpTransports[sessionIdFromHeader]) { transport = httpTransports[sessionIdFromHeader]; } else if (!sessionIdFromHeader && isInitializeRequest(req.body)) { const argocdBaseUrl = req.headers["x-argocd-base-url"] || ""; const argocdApiToken = req.headers["x-argocd-api-token"] || ""; if (argocdBaseUrl == "" || argocdApiToken == "") { res.status(400).send("x-argocd-base-url and x-argocd-api-token must be provided in headers."); return; } transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (newSessionId) => { httpTransports[newSessionId] = transport; } }); transport.onclose = () => { if (transport.sessionId) { delete httpTransports[transport.sessionId]; } }; const server = createServer({ argocdBaseUrl, argocdApiToken }); yield server.connect(transport); } else { const errorMsg = sessionIdFromHeader ? `Invalid or expired session ID: ${sessionIdFromHeader}` : "Bad Request: Not an initialization request and no valid session ID provided."; res.status(400).json({ jsonrpc: "2.0", error: { code: -32e3, message: errorMsg }, id: ((_a = req.body) == null ? void 0 : _a.id) !== void 0 ? req.body.id : null }); return; } yield transport.handleRequest(req, res, req.body); })); const handleSessionRequest = (req, res) => __async(void 0, null, function* () { const sessionId = req.headers["mcp-session-id"]; if (!sessionId || !httpTransports[sessionId]) { res.status(400).send("Invalid or missing session ID"); return; } const transport = httpTransports[sessionId]; yield transport.handleRequest(req, res); }); app.get("/mcp", handleSessionRequest); app.delete("/mcp", handleSessionRequest); logger.info(`Connecting to Http Stream transport on port: ${port}`); app.listen(port); }; // src/cmd/cmd.ts var cmd = () => { const exe = yargs(hideBin(process.argv)); exe.command( "stdio", "Start ArgoCD MCP server using stdio.", () => { }, () => connectStdioTransport() ); exe.command( "sse", "Start ArgoCD MCP server using SSE.", (yargs2) => { return yargs2.option("port", { type: "number", default: 3e3 }); }, ({ port }) => connectSSETransport(port) ); exe.command( "http", "Start ArgoCD MCP server using Http Stream.", (yargs2) => { return yargs2.option("port", { type: "number", default: 3e3 }); }, ({ port }) => connectHttpTransport(port) ); exe.demandCommand().parseSync(); }; // src/index.ts import dotenv from "dotenv"; dotenv.config(); cmd(); //# sourceMappingURL=index.js.map