cyberark-mcp 1.0.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.
- package/README.md +19 -0
- package/dist/api.d.ts +7 -0
- package/dist/api.js +75 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +56 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# cyberark-mcp
|
|
2
|
+
|
|
3
|
+
CyberArk PVWA API: logon, safes, accounts. Token cached per process.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export CYBERARK_BASE_URL=...
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Needs CYBERARK_BASE_URL (PVWA host) plus CYBERARK_USERNAME and CYBERARK_PASSWORD.
|
|
12
|
+
|
|
13
|
+
## Tools
|
|
14
|
+
|
|
15
|
+
- `list_safes` — CyberArk safes visible to the logon user.
|
|
16
|
+
- `list_accounts` — CyberArk accounts, optionally filtered by safe.
|
|
17
|
+
- `get_account` — One CyberArk account by id (metadata, not the password value).
|
|
18
|
+
|
|
19
|
+
Part of [awesome-mcps](https://github.com/mrfentmen/awesome-mcps).
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class CyberarkError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare function errorMessage(e: unknown): string;
|
|
5
|
+
export declare function listSafes(): Promise<string>;
|
|
6
|
+
export declare function listAccounts(safeName?: string): Promise<string>;
|
|
7
|
+
export declare function getAccount(accountId: string): Promise<string>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export class CyberarkError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "CyberarkError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function errorMessage(e) {
|
|
8
|
+
return e instanceof Error ? e.message : String(e);
|
|
9
|
+
}
|
|
10
|
+
const UA = { "User-Agent": "awesome-mcps/1.0" };
|
|
11
|
+
function envStrict(name) {
|
|
12
|
+
const v = process.env[name];
|
|
13
|
+
if (!v)
|
|
14
|
+
throw new CyberarkError(`Set the ${name} environment variable.`);
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
17
|
+
async function apiBase() {
|
|
18
|
+
return envStrict("CYBERARK_BASE_URL").replace(/\/$/, "");
|
|
19
|
+
}
|
|
20
|
+
let cachedToken = "";
|
|
21
|
+
async function authHeaders() {
|
|
22
|
+
if (!cachedToken) {
|
|
23
|
+
const base = await apiBase();
|
|
24
|
+
const res = await fetch(`${base}/PasswordVault/API/Auth/Cyberark/Logon`, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { ...UA, "Content-Type": "application/json" },
|
|
27
|
+
body: JSON.stringify({ username: envStrict("CYBERARK_USERNAME"), password: envStrict("CYBERARK_PASSWORD") }),
|
|
28
|
+
});
|
|
29
|
+
if (!res.ok)
|
|
30
|
+
throw new CyberarkError(`CyberArk logon failed: HTTP ${res.status}`);
|
|
31
|
+
const data = (await res.json());
|
|
32
|
+
if (!data.CyberArkLogonResult)
|
|
33
|
+
throw new CyberarkError("CyberArk logon returned no token");
|
|
34
|
+
cachedToken = data.CyberArkLogonResult;
|
|
35
|
+
}
|
|
36
|
+
return { Authorization: cachedToken };
|
|
37
|
+
}
|
|
38
|
+
function pretty(data) {
|
|
39
|
+
const t = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
40
|
+
return t.length > 12000 ? t.slice(0, 12000) + "\n…(truncated)" : t;
|
|
41
|
+
}
|
|
42
|
+
async function req(url, init = {}) {
|
|
43
|
+
const res = await fetch(url, { headers: { ...UA, ...(await authHeaders()), ...(init.headers ?? {}) }, ...init });
|
|
44
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
45
|
+
const data = ct.includes("json") ? await res.json() : await res.text();
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const detail = typeof data === "string" ? data.slice(0, 300) : JSON.stringify(data).slice(0, 300);
|
|
48
|
+
throw new CyberarkError(`HTTP ${res.status}: ${detail}`);
|
|
49
|
+
}
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
export async function listSafes() {
|
|
53
|
+
const base = await apiBase();
|
|
54
|
+
let url = `${base}/PasswordVault/API/Safes`;
|
|
55
|
+
const data = await req(url);
|
|
56
|
+
return pretty(data);
|
|
57
|
+
}
|
|
58
|
+
export async function listAccounts(safeName) {
|
|
59
|
+
const base = await apiBase();
|
|
60
|
+
let url = `${base}/PasswordVault/API/Accounts`;
|
|
61
|
+
const qs = new URLSearchParams();
|
|
62
|
+
if (safeName !== undefined)
|
|
63
|
+
qs.append("safeName", String(safeName));
|
|
64
|
+
const qstr = qs.toString();
|
|
65
|
+
if (qstr)
|
|
66
|
+
url += (url.includes('?') ? '&' : '?') + qstr;
|
|
67
|
+
const data = await req(url);
|
|
68
|
+
return pretty(data);
|
|
69
|
+
}
|
|
70
|
+
export async function getAccount(accountId) {
|
|
71
|
+
const base = await apiBase();
|
|
72
|
+
let url = `${base}/PasswordVault/API/Accounts/${encodeURIComponent(String(accountId))}`;
|
|
73
|
+
const data = await req(url);
|
|
74
|
+
return pretty(data);
|
|
75
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
+
import { createServer } from "./server.js";
|
|
3
|
+
async function main() {
|
|
4
|
+
const server = createServer();
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
await server.connect(transport);
|
|
7
|
+
console.error("MCP server running on stdio");
|
|
8
|
+
}
|
|
9
|
+
main().catch((err) => {
|
|
10
|
+
console.error("Fatal error:", err);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { errorMessage, listSafes, listAccounts, getAccount, } from "./api.js";
|
|
4
|
+
const text = (t) => ({ content: [{ type: "text", text: t }] });
|
|
5
|
+
const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
|
|
6
|
+
const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
|
|
7
|
+
export function createServer() {
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: "cyberark-mcp",
|
|
10
|
+
version: "1.0.0",
|
|
11
|
+
});
|
|
12
|
+
server.registerTool("list_safes", {
|
|
13
|
+
title: "List safes",
|
|
14
|
+
description: "CyberArk safes visible to the logon user.",
|
|
15
|
+
inputSchema: z.object({}),
|
|
16
|
+
annotations: READ_ONLY,
|
|
17
|
+
}, async ({}) => {
|
|
18
|
+
try {
|
|
19
|
+
return text(await listSafes());
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
return textError(errorMessage(e));
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
server.registerTool("list_accounts", {
|
|
26
|
+
title: "List accounts",
|
|
27
|
+
description: "CyberArk accounts, optionally filtered by safe.",
|
|
28
|
+
inputSchema: z.object({
|
|
29
|
+
safeName: z.string().optional().describe("Safe name filter"),
|
|
30
|
+
}),
|
|
31
|
+
annotations: READ_ONLY,
|
|
32
|
+
}, async ({ safeName }) => {
|
|
33
|
+
try {
|
|
34
|
+
return text(await listAccounts(safeName));
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return textError(errorMessage(e));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
server.registerTool("get_account", {
|
|
41
|
+
title: "Get account",
|
|
42
|
+
description: "One CyberArk account by id (metadata, not the password value).",
|
|
43
|
+
inputSchema: z.object({
|
|
44
|
+
accountId: z.string().describe("Account id"),
|
|
45
|
+
}),
|
|
46
|
+
annotations: READ_ONLY,
|
|
47
|
+
}, async ({ accountId }) => {
|
|
48
|
+
try {
|
|
49
|
+
return text(await getAccount(accountId));
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
return textError(errorMessage(e));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return server;
|
|
56
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cyberark-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CyberArk PVWA API: logon, safes, accounts. Token cached per process.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"mcpName": "io.github.mrfentmen/cyberark-mcp",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/mrfentmen/awesome-mcps.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"cyberark-mcp": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.json",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "rm -rf dist && tsc -p tsconfig.json && node dist/index.js",
|
|
22
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"cyberark",
|
|
27
|
+
"secrets",
|
|
28
|
+
"vault",
|
|
29
|
+
"security"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
34
|
+
"zod": "^3.23.8"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"typescript": "^5.6.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=20"
|
|
42
|
+
}
|
|
43
|
+
}
|