delinea-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 ADDED
@@ -0,0 +1,19 @@
1
+ # delinea-mcp
2
+
3
+ Delinea Secret Server API: OAuth login, secret search, secret retrieval, folders.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ export DELINEA_BASE_URL=...
9
+ ```
10
+
11
+ Needs DELINEA_BASE_URL (e.g. https://tenant.secretservercloud.com) plus DELINEA_USERNAME and DELINEA_PASSWORD.
12
+
13
+ ## Tools
14
+
15
+ - `search_secrets` — Search Delinea secrets by text across allowed vaults.
16
+ - `get_secret` — Retrieve one Delinea secret with field values.
17
+ - `list_folders` — Top-level Delinea secret folders.
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 DelineaError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare function errorMessage(e: unknown): string;
5
+ export declare function searchSecrets(query: string): Promise<string>;
6
+ export declare function getSecret(secretId: string): Promise<string>;
7
+ export declare function listFolders(): Promise<string>;
package/dist/api.js ADDED
@@ -0,0 +1,74 @@
1
+ export class DelineaError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "DelineaError";
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 DelineaError(`Set the ${name} environment variable.`);
15
+ return v;
16
+ }
17
+ async function apiBase() {
18
+ return envStrict("DELINEA_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}/oauth2/token`, {
25
+ method: "POST",
26
+ headers: { ...UA, "Content-Type": "application/x-www-form-urlencoded" },
27
+ body: new URLSearchParams({ username: envStrict("DELINEA_USERNAME"), password: envStrict("DELINEA_PASSWORD"), grant_type: "password" }).toString(),
28
+ });
29
+ if (!res.ok)
30
+ throw new DelineaError(`Delinea login failed: HTTP ${res.status}`);
31
+ const data = (await res.json());
32
+ if (!data.access_token)
33
+ throw new DelineaError("Delinea login returned no token");
34
+ cachedToken = data.access_token;
35
+ }
36
+ return { Authorization: "Bearer " + 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 DelineaError(`HTTP ${res.status}: ${detail}`);
49
+ }
50
+ return data;
51
+ }
52
+ export async function searchSecrets(query) {
53
+ const base = await apiBase();
54
+ let url = `${base}/api/v1/secrets`;
55
+ const qs = new URLSearchParams();
56
+ qs.append("filter.searchText", String(query));
57
+ const qstr = qs.toString();
58
+ if (qstr)
59
+ url += (url.includes('?') ? '&' : '?') + qstr;
60
+ const data = await req(url);
61
+ return pretty(data);
62
+ }
63
+ export async function getSecret(secretId) {
64
+ const base = await apiBase();
65
+ let url = `${base}/api/v1/secrets/${encodeURIComponent(String(secretId))}`;
66
+ const data = await req(url);
67
+ return pretty(data);
68
+ }
69
+ export async function listFolders() {
70
+ const base = await apiBase();
71
+ let url = `${base}/api/v1/folders`;
72
+ const data = await req(url);
73
+ return pretty(data);
74
+ }
@@ -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
+ });
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
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, searchSecrets, getSecret, listFolders, } 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: "delinea-mcp",
10
+ version: "1.0.0",
11
+ });
12
+ server.registerTool("search_secrets", {
13
+ title: "Search secrets",
14
+ description: "Search Delinea secrets by text across allowed vaults.",
15
+ inputSchema: z.object({
16
+ query: z.string().describe("Search text"),
17
+ }),
18
+ annotations: READ_ONLY,
19
+ }, async ({ query }) => {
20
+ try {
21
+ return text(await searchSecrets(query));
22
+ }
23
+ catch (e) {
24
+ return textError(errorMessage(e));
25
+ }
26
+ });
27
+ server.registerTool("get_secret", {
28
+ title: "Get secret",
29
+ description: "Retrieve one Delinea secret with field values.",
30
+ inputSchema: z.object({
31
+ secretId: z.string().describe("Secret id"),
32
+ }),
33
+ annotations: READ_ONLY,
34
+ }, async ({ secretId }) => {
35
+ try {
36
+ return text(await getSecret(secretId));
37
+ }
38
+ catch (e) {
39
+ return textError(errorMessage(e));
40
+ }
41
+ });
42
+ server.registerTool("list_folders", {
43
+ title: "List folders",
44
+ description: "Top-level Delinea secret folders.",
45
+ inputSchema: z.object({}),
46
+ annotations: READ_ONLY,
47
+ }, async ({}) => {
48
+ try {
49
+ return text(await listFolders());
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": "delinea-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Delinea Secret Server API: OAuth login, secret search, secret retrieval, folders.",
5
+ "type": "module",
6
+ "mcpName": "io.github.mrfentmen/delinea-mcp",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/mrfentmen/awesome-mcps.git"
10
+ },
11
+ "bin": {
12
+ "delinea-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
+ "delinea",
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
+ }