argocd-mcp
Version:
Argo CD MCP Server
990 lines (977 loc) • 35.1 kB
JavaScript
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: "argocd-mcp",
version: "0.0.0",
description: "Argo CD MCP Server",
repository: {
type: "git",
url: "git+https://github.com/argoproj-labs/mcp-for-argocd.git"
},
keywords: [
"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",
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"
},
author: "Argo Proj Contributors.",
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* () {
var _a, _b, _c, _d;
const { body } = yield this.client.get(
`/api/v1/applications`,
(params == null ? void 0 : params.search) ? { search: params.search } : void 0
);
const strippedItems = (_b = (_a = body.items) == null ? void 0 : _a.map((app) => {
var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j;
return {
metadata: {
name: (_a2 = app.metadata) == null ? void 0 : _a2.name,
namespace: (_b2 = app.metadata) == null ? void 0 : _b2.namespace,
labels: (_c2 = app.metadata) == null ? void 0 : _c2.labels,
creationTimestamp: (_d2 = app.metadata) == null ? void 0 : _d2.creationTimestamp
},
spec: {
project: (_e = app.spec) == null ? void 0 : _e.project,
source: (_f = app.spec) == null ? void 0 : _f.source,
destination: (_g = app.spec) == null ? void 0 : _g.destination
},
status: {
sync: (_h = app.status) == null ? void 0 : _h.sync,
health: (_i = app.status) == null ? void 0 : _i.health,
summary: (_j = app.status) == null ? void 0 : _j.summary
}
};
})) != null ? _b : [];
const start = (_c = params == null ? void 0 : params.offset) != null ? _c : 0;
const end = (params == null ? void 0 : params.limit) ? start + params.limit : strippedItems.length;
const items = strippedItems.slice(start, end);
return {
items,
metadata: {
resourceVersion: (_d = body.metadata) == null ? void 0 : _d.resourceVersion,
totalItems: strippedItems.length,
returnedItems: items.length,
hasMore: end < strippedItems.length
}
};
});
}
getApplication(applicationName, appNamespace) {
return __async(this, null, function* () {
const queryParams = appNamespace ? { appNamespace } : void 0;
const { body } = yield this.client.get(
`/api/v1/applications/${applicationName}`,
queryParams
);
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, options) {
return __async(this, null, function* () {
const queryParams = {};
if (options == null ? void 0 : options.appNamespace) {
queryParams.appNamespace = options.appNamespace;
}
if ((options == null ? void 0 : options.cascade) !== void 0) {
queryParams.cascade = options.cascade;
}
if (options == null ? void 0 : options.propagationPolicy) {
queryParams.propagationPolicy = options.propagationPolicy;
}
const { body } = yield this.client.delete(
`/api/v1/applications/${applicationName}`,
Object.keys(queryParams).length > 0 ? queryParams : void 0
);
return body;
});
}
syncApplication(applicationName, options) {
return __async(this, null, function* () {
const syncRequest = {};
if (options == null ? void 0 : options.appNamespace) {
syncRequest.appNamespace = options.appNamespace;
}
if ((options == null ? void 0 : options.dryRun) !== void 0) {
syncRequest.dryRun = options.dryRun;
}
if ((options == null ? void 0 : options.prune) !== void 0) {
syncRequest.prune = options.prune;
}
if (options == null ? void 0 : options.revision) {
syncRequest.revision = options.revision;
}
if (options == null ? void 0 : options.syncOptions) {
syncRequest.syncOptions = options.syncOptions;
}
const { body } = yield this.client.post(
`/api/v1/applications/${applicationName}/sync`,
null,
Object.keys(syncRequest).length > 0 ? syncRequest : void 0
);
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, filters) {
return __async(this, null, function* () {
const { body } = yield this.client.get(
`/api/v1/applications/${applicationName}/managed-resources`,
filters
);
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, container) {
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,
container
},
(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;
});
}
getResource(applicationName, applicationNamespace, resourceRef) {
return __async(this, null, function* () {
const { body } = yield this.client.get(
`/api/v1/applications/${applicationName}/resource`,
{
appNamespace: applicationNamespace,
namespace: resourceRef.namespace,
resourceName: resourceRef.name,
group: resourceRef.group,
kind: resourceRef.kind,
version: resourceRef.version
}
);
return body.manifest;
});
}
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;
});
}
};
// src/server/server.ts
import { z as z2 } from "zod";
// src/shared/models/schema.ts
import { z } from "zod";
var ApplicationNamespaceSchema = z.string().min(1).describe(
`The namespace where the ArgoCD application resource will be created.
This is the namespace of the Application resource itself, not the destination namespace for the application's resources.
You can specify any valid Kubernetes namespace (e.g., 'argocd', 'argocd-apps', 'my-namespace', etc.).
The default ArgoCD namespace is typically 'argocd', but you can use any namespace you prefer.`
);
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.`
)
})
});
// src/server/server.ts
var Server = class extends McpServer {
constructor(serverInfo) {
var _a;
super({
name: package_default.name,
version: package_default.version
});
this.argocdClient = new ArgoCDClient(serverInfo.argocdBaseUrl, serverInfo.argocdApiToken);
const isReadOnly = String((_a = process.env.MCP_READ_ONLY) != null ? _a : "").trim().toLowerCase() === "true";
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.'
),
limit: z2.number().int().positive().optional().describe(
"Maximum number of applications to return. Use this to reduce token usage when there are many applications. Optional."
),
offset: z2.number().int().min(0).optional().describe(
"Number of applications to skip before returning results. Use with limit for pagination. Optional."
)
},
(_0) => __async(this, [_0], function* ({ search, limit, offset }) {
return yield this.argocdClient.listApplications({
search: search != null ? search : void 0,
limit,
offset
});
})
);
this.addJsonOutputTool(
"get_application",
"get_application returns application by application name. Optionally specify the application namespace to get applications from non-default namespaces.",
{
applicationName: z2.string(),
applicationNamespace: ApplicationNamespaceSchema.optional()
},
(_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace }) {
return yield this.argocdClient.getApplication(applicationName, applicationNamespace);
})
);
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 with optional filtering. Use filters to avoid token limits with large applications. Examples: kind="ConfigMap" for config maps only, namespace="production" for specific namespace, or combine multiple filters.',
{
applicationName: z2.string(),
kind: z2.string().optional().describe(
'Filter by Kubernetes resource kind (e.g., "ConfigMap", "Secret", "Deployment")'
),
namespace: z2.string().optional().describe("Filter by Kubernetes namespace"),
name: z2.string().optional().describe("Filter by resource name"),
version: z2.string().optional().describe("Filter by resource API version"),
group: z2.string().optional().describe("Filter by API group"),
appNamespace: z2.string().optional().describe("Filter by Argo CD application namespace"),
project: z2.string().optional().describe("Filter by Argo CD project")
},
(_0) => __async(this, [_0], function* ({ applicationName, kind, namespace, name, version, group, appNamespace, project }) {
const filters = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, kind && { kind }), namespace && { namespace }), name && { name }), version && { version }), group && { group }), appNamespace && { appNamespace }), project && { project });
return yield this.argocdClient.getApplicationManagedResources(
applicationName,
Object.keys(filters).length > 0 ? filters : void 0
);
})
);
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 and optionally container name",
{
applicationName: z2.string(),
applicationNamespace: ApplicationNamespaceSchema,
resourceRef: ResourceRefSchema,
container: z2.string()
},
(_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceRef, container }) {
return yield this.argocdClient.getWorkloadLogs(
applicationName,
applicationNamespace,
resourceRef,
container
);
})
);
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_resources",
"get_resources return manifests for resources specified by resourceRefs. If resourceRefs is empty or not provided, fetches all resources managed by the application.",
{
applicationName: z2.string(),
applicationNamespace: ApplicationNamespaceSchema,
resourceRefs: ResourceRefSchema.array().optional()
},
(_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, resourceRefs }) {
var _a2;
let refs = resourceRefs || [];
if (refs.length === 0) {
const tree = yield this.argocdClient.getApplicationResourceTree(applicationName);
refs = ((_a2 = tree.nodes) == null ? void 0 : _a2.map((node) => ({
uid: node.uid,
version: node.version,
group: node.group,
kind: node.kind,
name: node.name,
namespace: node.namespace
}))) || [];
}
return Promise.all(
refs.map(
(ref) => this.argocdClient.getResource(applicationName, applicationNamespace, ref)
)
);
})
);
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
);
})
);
if (!isReadOnly) {
this.addJsonOutputTool(
"create_application",
'create_application creates a new ArgoCD application in the specified namespace. The application.metadata.namespace field determines where the Application resource will be created (e.g., "argocd", "argocd-apps", or any custom namespace).',
{ 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. Specify applicationNamespace if the application is in a non-default namespace to avoid permission errors.",
{
applicationName: z2.string(),
applicationNamespace: ApplicationNamespaceSchema.optional().describe(
"The namespace where the application is located. Required if application is not in the default namespace."
),
cascade: z2.boolean().optional().describe("Whether to cascade the deletion to child resources"),
propagationPolicy: z2.string().optional().describe('Deletion propagation policy (e.g., "Foreground", "Background", "Orphan")')
},
(_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, cascade, propagationPolicy }) {
const options = {};
if (applicationNamespace) options.appNamespace = applicationNamespace;
if (cascade !== void 0) options.cascade = cascade;
if (propagationPolicy) options.propagationPolicy = propagationPolicy;
return yield this.argocdClient.deleteApplication(
applicationName,
Object.keys(options).length > 0 ? options : void 0
);
})
);
this.addJsonOutputTool(
"sync_application",
"sync_application syncs application. Specify applicationNamespace if the application is in a non-default namespace to avoid permission errors.",
{
applicationName: z2.string(),
applicationNamespace: ApplicationNamespaceSchema.optional().describe(
"The namespace where the application is located. Required if application is not in the default namespace."
),
dryRun: z2.boolean().optional().describe("Perform a dry run sync without applying changes"),
prune: z2.boolean().optional().describe("Remove resources that are no longer defined in the source"),
revision: z2.string().optional().describe("Sync to a specific revision instead of the latest"),
syncOptions: z2.array(z2.string()).optional().describe(
'Additional sync options (e.g., ["CreateNamespace=true", "PrunePropagationPolicy=foreground"])'
)
},
(_0) => __async(this, [_0], function* ({ applicationName, applicationNamespace, dryRun, prune, revision, syncOptions }) {
const options = {};
if (applicationNamespace) options.appNamespace = applicationNamespace;
if (dryRun !== void 0) options.dryRun = dryRun;
if (prune !== void 0) options.prune = prune;
if (revision) options.revision = revision;
if (syncOptions) options.syncOptions = syncOptions;
return yield this.argocdClient.syncApplication(
applicationName,
Object.keys(options).length > 0 ? options : void 0
);
})
);
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
);
})
);
}
}
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"] || process.env.ARGOCD_BASE_URL || "";
const argocdApiToken = req.headers["x-argocd-api-token"] || process.env.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