mcp-cohesity 2.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/LICENSE +77 -0
- package/README.md +494 -0
- package/dist/cohesity-client.d.ts +47 -0
- package/dist/cohesity-client.js +126 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +149 -0
- package/dist/tools/active-directory.d.ts +11 -0
- package/dist/tools/active-directory.js +82 -0
- package/dist/tools/alerts.d.ts +6 -0
- package/dist/tools/alerts.js +111 -0
- package/dist/tools/antivirus.d.ts +24 -0
- package/dist/tools/antivirus.js +180 -0
- package/dist/tools/audit-logs.d.ts +10 -0
- package/dist/tools/audit-logs.js +161 -0
- package/dist/tools/clones.d.ts +24 -0
- package/dist/tools/clones.js +107 -0
- package/dist/tools/cluster-reports.d.ts +10 -0
- package/dist/tools/cluster-reports.js +224 -0
- package/dist/tools/cluster.d.ts +6 -0
- package/dist/tools/cluster.js +33 -0
- package/dist/tools/external-targets.d.ts +3 -0
- package/dist/tools/external-targets.js +145 -0
- package/dist/tools/kms.d.ts +14 -0
- package/dist/tools/kms.js +164 -0
- package/dist/tools/notifications.d.ts +3 -0
- package/dist/tools/notifications.js +156 -0
- package/dist/tools/protection.d.ts +3 -0
- package/dist/tools/protection.js +514 -0
- package/dist/tools/recovery.d.ts +6 -0
- package/dist/tools/recovery.js +101 -0
- package/dist/tools/reports.d.ts +3 -0
- package/dist/tools/reports.js +346 -0
- package/dist/tools/restore.d.ts +3 -0
- package/dist/tools/restore.js +220 -0
- package/dist/tools/roles.d.ts +11 -0
- package/dist/tools/roles.js +95 -0
- package/dist/tools/run-actions.d.ts +17 -0
- package/dist/tools/run-actions.js +190 -0
- package/dist/tools/runs.d.ts +6 -0
- package/dist/tools/runs.js +94 -0
- package/dist/tools/source-registration.d.ts +11 -0
- package/dist/tools/source-registration.js +456 -0
- package/dist/tools/sources.d.ts +3 -0
- package/dist/tools/sources.js +161 -0
- package/dist/tools/stats.d.ts +3 -0
- package/dist/tools/stats.js +164 -0
- package/dist/tools/storage.d.ts +3 -0
- package/dist/tools/storage.js +191 -0
- package/dist/tools/tiering.d.ts +3 -0
- package/dist/tools/tiering.js +132 -0
- package/dist/tools/users.d.ts +13 -0
- package/dist/tools/users.js +203 -0
- package/package.json +57 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User management tools — list, create, update, and delete Cohesity users
|
|
3
|
+
* (both LOCAL and AD/IdP-backed). All shapes verified against cluster_v2_api.yaml.
|
|
4
|
+
*
|
|
5
|
+
* GET /v2/users — UsersList
|
|
6
|
+
* POST /v2/users — CreateUsersParameters (array of CreateUserParameters)
|
|
7
|
+
* POST /v2/users/delete — DeleteUsersRequest { sids[] }
|
|
8
|
+
* GET /v2/users/{sid} — User
|
|
9
|
+
* PUT /v2/users/{sid} — UpdateUserParameters
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
const reply = (text, isError = false) => ({
|
|
13
|
+
content: [{ type: "text", text }],
|
|
14
|
+
isError,
|
|
15
|
+
});
|
|
16
|
+
export function registerUserTools(server, client) {
|
|
17
|
+
// ── List Users ─────────────────────────────────────────────────────────
|
|
18
|
+
server.tool("list_users", "List Cohesity users. Filterable by domain, sid, username (partial or exact), email, or role.", {
|
|
19
|
+
domain: z.string().optional().describe("Restrict to this auth domain (e.g., LOCAL or AD FQDN)"),
|
|
20
|
+
sids: z.array(z.string()).optional().describe("Restrict to these SIDs"),
|
|
21
|
+
usernames: z.array(z.string()).optional().describe("Restrict to these usernames"),
|
|
22
|
+
match_partial_names: z
|
|
23
|
+
.boolean()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Treat usernames as partial matches instead of exact"),
|
|
26
|
+
email_addresses: z.array(z.string()).optional().describe("Restrict to these email addresses"),
|
|
27
|
+
roles: z.array(z.string()).optional().describe("Restrict to users having these roles"),
|
|
28
|
+
tenant_ids: z.array(z.string()).optional().describe("Restrict to these tenant IDs"),
|
|
29
|
+
include_tenants: z
|
|
30
|
+
.boolean()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Include users of nested tenants the caller can see"),
|
|
33
|
+
}, async (args) => {
|
|
34
|
+
try {
|
|
35
|
+
const qp = {};
|
|
36
|
+
if (args.domain)
|
|
37
|
+
qp.domain = args.domain;
|
|
38
|
+
if (args.sids?.length)
|
|
39
|
+
qp.sids = args.sids.join(",");
|
|
40
|
+
if (args.usernames?.length)
|
|
41
|
+
qp.usernames = args.usernames.join(",");
|
|
42
|
+
if (args.match_partial_names !== undefined)
|
|
43
|
+
qp.matchPartialNames = String(args.match_partial_names);
|
|
44
|
+
if (args.email_addresses?.length)
|
|
45
|
+
qp.emailAddresses = args.email_addresses.join(",");
|
|
46
|
+
if (args.roles?.length)
|
|
47
|
+
qp.roles = args.roles.join(",");
|
|
48
|
+
if (args.tenant_ids?.length)
|
|
49
|
+
qp.tenantIds = args.tenant_ids.join(",");
|
|
50
|
+
if (args.include_tenants !== undefined)
|
|
51
|
+
qp.includeTenants = String(args.include_tenants);
|
|
52
|
+
const data = await client.getV2("users", qp);
|
|
53
|
+
return reply(JSON.stringify(data, null, 2));
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
return reply(`Error listing users: ${err}`, true);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// ── Get User by SID ────────────────────────────────────────────────────
|
|
60
|
+
server.tool("get_user", "Get a single Cohesity user by SID", { sid: z.string().describe("User SID") }, async (args) => {
|
|
61
|
+
try {
|
|
62
|
+
const data = await client.getV2(`users/${encodeURIComponent(args.sid)}`);
|
|
63
|
+
return reply(JSON.stringify(data, null, 2));
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
return reply(`Error fetching user ${args.sid}: ${err}`, true);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// ── Create Local User ──────────────────────────────────────────────────
|
|
70
|
+
// POST /v2/users takes an array; we expose a single-user shape for clarity.
|
|
71
|
+
server.tool("create_local_user", "Create a new LOCAL Cohesity user with a password. For AD/IdP users, use create_ad_user.", {
|
|
72
|
+
username: z.string().describe("Login username"),
|
|
73
|
+
password: z.string().describe("Initial password for the LOCAL user"),
|
|
74
|
+
email: z.string().optional().describe("Email address"),
|
|
75
|
+
description: z.string().optional().describe("Free-form description"),
|
|
76
|
+
roles: z
|
|
77
|
+
.array(z.string())
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Cohesity role names to assign (e.g. COHESITY_VIEWER, COHESITY_ADMIN)"),
|
|
80
|
+
restricted: z
|
|
81
|
+
.boolean()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Restricted users can only view/manage objects they have permissions on"),
|
|
84
|
+
locked: z.boolean().optional().describe("Create the user in a locked state"),
|
|
85
|
+
effective_time_msecs: z
|
|
86
|
+
.number()
|
|
87
|
+
.optional()
|
|
88
|
+
.describe("Epoch ms from which the user can log in"),
|
|
89
|
+
expiry_time_msecs: z.number().optional().describe("Epoch ms when the user expires"),
|
|
90
|
+
}, async (args) => {
|
|
91
|
+
try {
|
|
92
|
+
const user = {
|
|
93
|
+
username: args.username,
|
|
94
|
+
domain: "LOCAL",
|
|
95
|
+
localUserParams: {
|
|
96
|
+
password: args.password,
|
|
97
|
+
...(args.email && { email: args.email }),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
if (args.description)
|
|
101
|
+
user.description = args.description;
|
|
102
|
+
if (args.roles?.length)
|
|
103
|
+
user.roles = args.roles;
|
|
104
|
+
if (args.restricted !== undefined)
|
|
105
|
+
user.restricted = args.restricted;
|
|
106
|
+
if (args.locked !== undefined)
|
|
107
|
+
user.locked = args.locked;
|
|
108
|
+
if (args.effective_time_msecs !== undefined)
|
|
109
|
+
user.effectiveTimeMsecs = args.effective_time_msecs;
|
|
110
|
+
if (args.expiry_time_msecs !== undefined)
|
|
111
|
+
user.expiryTimeMsecs = args.expiry_time_msecs;
|
|
112
|
+
const result = await client.postV2("users", [user]);
|
|
113
|
+
return reply(`User created.\n${JSON.stringify(result, null, 2)}`);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return reply(`Error creating user: ${err}`, true);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// ── Create AD/IdP User ─────────────────────────────────────────────────
|
|
120
|
+
server.tool("create_ad_user", "Create a Cohesity user mapped to an existing Active Directory or IdP principal. No password is set on Cohesity — auth flows through the identity provider.", {
|
|
121
|
+
username: z.string().describe("Principal username on the AD/IdP domain"),
|
|
122
|
+
domain: z.string().describe("Auth domain FQDN (e.g. corp.example.com)"),
|
|
123
|
+
email: z.string().optional().describe("Email address"),
|
|
124
|
+
description: z.string().optional().describe("Free-form description"),
|
|
125
|
+
roles: z.array(z.string()).optional().describe("Cohesity role names to assign"),
|
|
126
|
+
restricted: z.boolean().optional().describe("Restricted user flag"),
|
|
127
|
+
}, async (args) => {
|
|
128
|
+
try {
|
|
129
|
+
const user = {
|
|
130
|
+
username: args.username,
|
|
131
|
+
domain: args.domain,
|
|
132
|
+
};
|
|
133
|
+
if (args.description)
|
|
134
|
+
user.description = args.description;
|
|
135
|
+
if (args.roles?.length)
|
|
136
|
+
user.roles = args.roles;
|
|
137
|
+
if (args.restricted !== undefined)
|
|
138
|
+
user.restricted = args.restricted;
|
|
139
|
+
const result = await client.postV2("users", [user]);
|
|
140
|
+
return reply(`AD/IdP user mapped.\n${JSON.stringify(result, null, 2)}`);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return reply(`Error mapping AD/IdP user: ${err}`, true);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// ── Update User ────────────────────────────────────────────────────────
|
|
147
|
+
// PUT /v2/users/{sid}
|
|
148
|
+
server.tool("update_user", "Update a Cohesity user — roles, description, restricted flag, or LOCAL user password.", {
|
|
149
|
+
sid: z.string().describe("User SID to update"),
|
|
150
|
+
username: z.string().optional().describe("New username (rare; usually keep stable)"),
|
|
151
|
+
description: z.string().optional().describe("New description"),
|
|
152
|
+
roles: z.array(z.string()).optional().describe("Replace role list"),
|
|
153
|
+
restricted: z.boolean().optional().describe("Toggle restricted flag"),
|
|
154
|
+
locked: z.boolean().optional().describe("Lock/unlock the user"),
|
|
155
|
+
new_password: z.string().optional().describe("New password (LOCAL users only)"),
|
|
156
|
+
current_password: z
|
|
157
|
+
.string()
|
|
158
|
+
.optional()
|
|
159
|
+
.describe("Required if a session user is changing their own password"),
|
|
160
|
+
email: z.string().optional().describe("Update email address (LOCAL users only)"),
|
|
161
|
+
}, async (args) => {
|
|
162
|
+
try {
|
|
163
|
+
const body = {};
|
|
164
|
+
if (args.username)
|
|
165
|
+
body.username = args.username;
|
|
166
|
+
if (args.description !== undefined)
|
|
167
|
+
body.description = args.description;
|
|
168
|
+
if (args.roles)
|
|
169
|
+
body.roles = args.roles;
|
|
170
|
+
if (args.restricted !== undefined)
|
|
171
|
+
body.restricted = args.restricted;
|
|
172
|
+
if (args.locked !== undefined)
|
|
173
|
+
body.locked = args.locked;
|
|
174
|
+
const local = {};
|
|
175
|
+
if (args.new_password)
|
|
176
|
+
local.password = args.new_password;
|
|
177
|
+
if (args.current_password)
|
|
178
|
+
local.currentPassword = args.current_password;
|
|
179
|
+
if (args.email !== undefined)
|
|
180
|
+
local.email = args.email;
|
|
181
|
+
if (Object.keys(local).length > 0)
|
|
182
|
+
body.localUserParams = local;
|
|
183
|
+
const result = await client.putV2(`users/${encodeURIComponent(args.sid)}`, body);
|
|
184
|
+
return reply(`User updated.\n${JSON.stringify(result, null, 2)}`);
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
return reply(`Error updating user: ${err}`, true);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
// ── Delete Users ───────────────────────────────────────────────────────
|
|
191
|
+
// POST /v2/users/delete — note: POST not DELETE, because batch.
|
|
192
|
+
server.tool("delete_users", "Delete one or more Cohesity users by SID. AD/IdP principal accounts are NOT deleted — only the Cohesity-side mapping.", {
|
|
193
|
+
sids: z.array(z.string()).min(1).describe("SIDs of users to delete"),
|
|
194
|
+
}, async (args) => {
|
|
195
|
+
try {
|
|
196
|
+
await client.postV2("users/delete", { sids: args.sids });
|
|
197
|
+
return reply(`Deleted ${args.sids.length} user(s).`);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
return reply(`Error deleting users: ${err}`, true);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-cohesity",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "MCP server for Cohesity DataProtect — 108 tools across 23 categories for source registration, backup, recovery, retention/WORM, archival, monitoring, reporting, identity, audit, antivirus, KMS, and clones",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-cohesity": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"dev": "tsx src/index.ts",
|
|
19
|
+
"test": "node tests/qa-harness.mjs",
|
|
20
|
+
"prepublishOnly": "npm run build"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"cohesity",
|
|
25
|
+
"backup",
|
|
26
|
+
"data-protection",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"ai",
|
|
29
|
+
"claude",
|
|
30
|
+
"restore",
|
|
31
|
+
"disaster-recovery",
|
|
32
|
+
"vmware"
|
|
33
|
+
],
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/dvermagithub/CohesityMCP.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/dvermagithub/CohesityMCP",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/dvermagithub/CohesityMCP/issues"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
44
|
+
"zod": "^3.24.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^22.0.0",
|
|
48
|
+
"tsx": "^4.19.0",
|
|
49
|
+
"typescript": "^5.7.0",
|
|
50
|
+
"undici": "^8.3.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
56
|
+
"author": "Deepak Verma (https://github.com/dvermagithub)"
|
|
57
|
+
}
|