@centrali-io/centrali-mcp 5.0.3 → 5.1.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 +1 -1
- package/dist/index.js +4 -1
- package/dist/tools/service-accounts.d.ts +7 -1
- package/dist/tools/service-accounts.js +33 -5
- package/package.json +1 -1
- package/src/index.ts +4 -1
- package/src/tools/service-accounts.ts +46 -3
package/README.md
CHANGED
|
@@ -266,7 +266,7 @@ After connecting, call `describe_centrali` first — it returns the full capabil
|
|
|
266
266
|
### Identity
|
|
267
267
|
| Tool | Description |
|
|
268
268
|
|------|-------------|
|
|
269
|
-
| `get_current_identity` | Get the MCP
|
|
269
|
+
| `get_current_identity` | Get the current authenticated MCP identity (service account or OAuth user) |
|
|
270
270
|
|
|
271
271
|
### Structures (Deprecated)
|
|
272
272
|
| Tool | Description |
|
package/dist/index.js
CHANGED
|
@@ -78,7 +78,10 @@ function main() {
|
|
|
78
78
|
(0, validation_js_1.registerValidationTools)(server, sdk);
|
|
79
79
|
(0, pages_js_1.registerPageTools)(server, sdk, baseUrl, workspaceId);
|
|
80
80
|
(0, auth_providers_js_1.registerAuthProviderTools)(server, sdk, baseUrl, workspaceId);
|
|
81
|
-
(0, service_accounts_js_1.registerServiceAccountTools)(server, sdk, baseUrl, workspaceId,
|
|
81
|
+
(0, service_accounts_js_1.registerServiceAccountTools)(server, sdk, baseUrl, workspaceId, {
|
|
82
|
+
clientId,
|
|
83
|
+
isServiceAccount: true,
|
|
84
|
+
});
|
|
82
85
|
(0, describe_js_1.registerDescribeTools)(server);
|
|
83
86
|
// Register resources
|
|
84
87
|
(0, structures_js_2.registerCollectionResources)(server, sdk);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { CentraliSDK } from "@centrali-io/centrali-sdk";
|
|
3
|
-
export
|
|
3
|
+
export interface CurrentIdentityContext {
|
|
4
|
+
clientId?: string;
|
|
5
|
+
userId?: string;
|
|
6
|
+
scopes?: string[];
|
|
7
|
+
isServiceAccount?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerServiceAccountTools(server: McpServer, sdk: CentraliSDK, centraliUrl: string, workspaceId: string, currentIdentity?: CurrentIdentityContext): void;
|
|
@@ -85,16 +85,42 @@ function formatError(error, context) {
|
|
|
85
85
|
}
|
|
86
86
|
return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
|
|
87
87
|
}
|
|
88
|
-
function registerServiceAccountTools(server, sdk, centraliUrl, workspaceId,
|
|
88
|
+
function registerServiceAccountTools(server, sdk, centraliUrl, workspaceId, currentIdentity) {
|
|
89
89
|
const getSaClient = () => createIamClient(sdk, centraliUrl, workspaceId, "service-accounts");
|
|
90
|
+
const getUsersClient = () => createIamClient(sdk, centraliUrl, workspaceId, "users");
|
|
90
91
|
const getRolesClient = () => createIamClient(sdk, centraliUrl, workspaceId, "roles");
|
|
91
92
|
const getGroupsClient = () => createIamClient(sdk, centraliUrl, workspaceId, "groups");
|
|
92
93
|
// ── Identity ─────────────────────────────────────────────────────
|
|
93
|
-
server.tool("get_current_identity", "Get the current MCP
|
|
94
|
-
var _a, _b, _c;
|
|
94
|
+
server.tool("get_current_identity", "Get the current authenticated MCP identity. In stdio/service-account mode, returns the MCP service account. In hosted OAuth mode, fetches the authenticated user's profile, roles, and groups from IAM.", {}, () => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
95
96
|
try {
|
|
97
|
+
if ((currentIdentity === null || currentIdentity === void 0 ? void 0 : currentIdentity.userId) && !currentIdentity.isServiceAccount) {
|
|
98
|
+
const meRes = yield getUsersClient().get("/me");
|
|
99
|
+
const user = meRes.data;
|
|
100
|
+
return {
|
|
101
|
+
content: [{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: JSON.stringify({
|
|
104
|
+
identityType: "user",
|
|
105
|
+
userId: (_a = user.id) !== null && _a !== void 0 ? _a : currentIdentity.userId,
|
|
106
|
+
email: (_b = user.email) !== null && _b !== void 0 ? _b : null,
|
|
107
|
+
name: (_d = (_c = user.name) !== null && _c !== void 0 ? _c : user.displayName) !== null && _d !== void 0 ? _d : null,
|
|
108
|
+
firstName: (_e = user.firstName) !== null && _e !== void 0 ? _e : null,
|
|
109
|
+
lastName: (_f = user.lastName) !== null && _f !== void 0 ? _f : null,
|
|
110
|
+
username: (_g = user.username) !== null && _g !== void 0 ? _g : null,
|
|
111
|
+
roles: ((_h = user.roles) !== null && _h !== void 0 ? _h : []).map((r) => { var _a; return (_a = r.name) !== null && _a !== void 0 ? _a : r; }),
|
|
112
|
+
groups: ((_j = user.groups) !== null && _j !== void 0 ? _j : []).map((g) => { var _a; return (_a = g.name) !== null && _a !== void 0 ? _a : g; }),
|
|
113
|
+
scopes: (_k = currentIdentity.scopes) !== null && _k !== void 0 ? _k : [],
|
|
114
|
+
workspace: workspaceId,
|
|
115
|
+
oauthClientId: (_l = currentIdentity.clientId) !== null && _l !== void 0 ? _l : null,
|
|
116
|
+
_hint: "Authenticated via OAuth user token. Roles and groups are fetched from IAM. Scopes come from the OAuth token. If a tool still returns 403, check both OAuth scopes and workspace IAM policies. Service-account remediation tools do not apply to user identities.",
|
|
117
|
+
}, null, 2),
|
|
118
|
+
}],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const ownClientId = currentIdentity === null || currentIdentity === void 0 ? void 0 : currentIdentity.clientId;
|
|
96
122
|
const result = yield getSaClient().get("/", { params: { pageSize: 100 } });
|
|
97
|
-
const accounts = (
|
|
123
|
+
const accounts = (_p = (_o = (_m = result.data) === null || _m === void 0 ? void 0 : _m.data) !== null && _o !== void 0 ? _o : result.data) !== null && _p !== void 0 ? _p : [];
|
|
98
124
|
const me = Array.isArray(accounts)
|
|
99
125
|
? accounts.find((sa) => sa.clientId === ownClientId)
|
|
100
126
|
: null;
|
|
@@ -105,7 +131,7 @@ function registerServiceAccountTools(server, sdk, centraliUrl, workspaceId, ownC
|
|
|
105
131
|
text: JSON.stringify({
|
|
106
132
|
error: "Could not identify current service account",
|
|
107
133
|
clientId: ownClientId,
|
|
108
|
-
hint: "The service account may not have permission to list service accounts, or the clientId doesn't match any
|
|
134
|
+
hint: "The service account may not have permission to list service accounts, or the clientId doesn't match any service account in this workspace.",
|
|
109
135
|
}, null, 2),
|
|
110
136
|
}],
|
|
111
137
|
isError: true,
|
|
@@ -115,11 +141,13 @@ function registerServiceAccountTools(server, sdk, centraliUrl, workspaceId, ownC
|
|
|
115
141
|
content: [{
|
|
116
142
|
type: "text",
|
|
117
143
|
text: JSON.stringify({
|
|
144
|
+
identityType: "service-account",
|
|
118
145
|
id: me.id,
|
|
119
146
|
clientId: me.clientId,
|
|
120
147
|
name: me.name,
|
|
121
148
|
description: me.description,
|
|
122
149
|
revoked: me.revoked,
|
|
150
|
+
workspace: workspaceId,
|
|
123
151
|
_hint: "Use this 'id' (numeric) with scan_service_account_permissions, simulate_service_account_permission, and generate_remediation to check or fix your own permissions.",
|
|
124
152
|
}, null, 2),
|
|
125
153
|
}],
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -75,7 +75,10 @@ async function main() {
|
|
|
75
75
|
registerValidationTools(server, sdk);
|
|
76
76
|
registerPageTools(server, sdk, baseUrl, workspaceId);
|
|
77
77
|
registerAuthProviderTools(server, sdk, baseUrl, workspaceId);
|
|
78
|
-
registerServiceAccountTools(server, sdk, baseUrl, workspaceId,
|
|
78
|
+
registerServiceAccountTools(server, sdk, baseUrl, workspaceId, {
|
|
79
|
+
clientId,
|
|
80
|
+
isServiceAccount: true,
|
|
81
|
+
});
|
|
79
82
|
registerDescribeTools(server);
|
|
80
83
|
|
|
81
84
|
// Register resources
|
|
@@ -78,8 +78,22 @@ function formatError(error: unknown, context: string): string {
|
|
|
78
78
|
return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
export
|
|
81
|
+
export interface CurrentIdentityContext {
|
|
82
|
+
clientId?: string;
|
|
83
|
+
userId?: string;
|
|
84
|
+
scopes?: string[];
|
|
85
|
+
isServiceAccount?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function registerServiceAccountTools(
|
|
89
|
+
server: McpServer,
|
|
90
|
+
sdk: CentraliSDK,
|
|
91
|
+
centraliUrl: string,
|
|
92
|
+
workspaceId: string,
|
|
93
|
+
currentIdentity?: CurrentIdentityContext,
|
|
94
|
+
) {
|
|
82
95
|
const getSaClient = () => createIamClient(sdk, centraliUrl, workspaceId, "service-accounts");
|
|
96
|
+
const getUsersClient = () => createIamClient(sdk, centraliUrl, workspaceId, "users");
|
|
83
97
|
const getRolesClient = () => createIamClient(sdk, centraliUrl, workspaceId, "roles");
|
|
84
98
|
const getGroupsClient = () => createIamClient(sdk, centraliUrl, workspaceId, "groups");
|
|
85
99
|
|
|
@@ -87,10 +101,37 @@ export function registerServiceAccountTools(server: McpServer, sdk: CentraliSDK,
|
|
|
87
101
|
|
|
88
102
|
server.tool(
|
|
89
103
|
"get_current_identity",
|
|
90
|
-
"Get the current MCP
|
|
104
|
+
"Get the current authenticated MCP identity. In stdio/service-account mode, returns the MCP service account. In hosted OAuth mode, fetches the authenticated user's profile, roles, and groups from IAM.",
|
|
91
105
|
{},
|
|
92
106
|
async () => {
|
|
93
107
|
try {
|
|
108
|
+
if (currentIdentity?.userId && !currentIdentity.isServiceAccount) {
|
|
109
|
+
const meRes = await getUsersClient().get("/me");
|
|
110
|
+
const user = meRes.data;
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
content: [{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: JSON.stringify({
|
|
116
|
+
identityType: "user",
|
|
117
|
+
userId: user.id ?? currentIdentity.userId,
|
|
118
|
+
email: user.email ?? null,
|
|
119
|
+
name: user.name ?? user.displayName ?? null,
|
|
120
|
+
firstName: user.firstName ?? null,
|
|
121
|
+
lastName: user.lastName ?? null,
|
|
122
|
+
username: user.username ?? null,
|
|
123
|
+
roles: (user.roles ?? []).map((r: any) => r.name ?? r),
|
|
124
|
+
groups: (user.groups ?? []).map((g: any) => g.name ?? g),
|
|
125
|
+
scopes: currentIdentity.scopes ?? [],
|
|
126
|
+
workspace: workspaceId,
|
|
127
|
+
oauthClientId: currentIdentity.clientId ?? null,
|
|
128
|
+
_hint: "Authenticated via OAuth user token. Roles and groups are fetched from IAM. Scopes come from the OAuth token. If a tool still returns 403, check both OAuth scopes and workspace IAM policies. Service-account remediation tools do not apply to user identities.",
|
|
129
|
+
}, null, 2),
|
|
130
|
+
}],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const ownClientId = currentIdentity?.clientId;
|
|
94
135
|
const result = await getSaClient().get("/", { params: { pageSize: 100 } });
|
|
95
136
|
const accounts = result.data?.data ?? result.data ?? [];
|
|
96
137
|
const me = Array.isArray(accounts)
|
|
@@ -104,7 +145,7 @@ export function registerServiceAccountTools(server: McpServer, sdk: CentraliSDK,
|
|
|
104
145
|
text: JSON.stringify({
|
|
105
146
|
error: "Could not identify current service account",
|
|
106
147
|
clientId: ownClientId,
|
|
107
|
-
hint: "The service account may not have permission to list service accounts, or the clientId doesn't match any
|
|
148
|
+
hint: "The service account may not have permission to list service accounts, or the clientId doesn't match any service account in this workspace.",
|
|
108
149
|
}, null, 2),
|
|
109
150
|
}],
|
|
110
151
|
isError: true,
|
|
@@ -115,11 +156,13 @@ export function registerServiceAccountTools(server: McpServer, sdk: CentraliSDK,
|
|
|
115
156
|
content: [{
|
|
116
157
|
type: "text",
|
|
117
158
|
text: JSON.stringify({
|
|
159
|
+
identityType: "service-account",
|
|
118
160
|
id: me.id,
|
|
119
161
|
clientId: me.clientId,
|
|
120
162
|
name: me.name,
|
|
121
163
|
description: me.description,
|
|
122
164
|
revoked: me.revoked,
|
|
165
|
+
workspace: workspaceId,
|
|
123
166
|
_hint: "Use this 'id' (numeric) with scan_service_account_permissions, simulate_service_account_permission, and generate_remediation to check or fix your own permissions.",
|
|
124
167
|
}, null, 2),
|
|
125
168
|
}],
|