@mgsoftwarebv/mg-dashboard-mcp 7.4.24 → 7.4.25
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/dist/index.js +116 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -724,10 +724,10 @@ var TRIGGER_TOOL_MODULE_MAP = {
|
|
|
724
724
|
"trigger-env": "settings"
|
|
725
725
|
};
|
|
726
726
|
async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
|
|
727
|
-
const
|
|
727
|
+
const sql36 = `SELECT re.\\"apiKey\\" || '~~' || p.\\"externalRef\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
|
|
728
728
|
const cmd = [
|
|
729
729
|
`PORT=$(docker port "${WA_CONTAINER}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
|
|
730
|
-
`ROW=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${
|
|
730
|
+
`ROW=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql36}" 2>/dev/null | tr -d '[:space:]')`,
|
|
731
731
|
'echo "$PORT|$ROW"'
|
|
732
732
|
].join(" && ");
|
|
733
733
|
const result = await sshExec2(conn, cmd, proxy);
|
|
@@ -749,8 +749,8 @@ async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
|
|
|
749
749
|
return { port, apiKey: apiKey2, projectRef: projectRef || "" };
|
|
750
750
|
}
|
|
751
751
|
async function fetchRunLogs(runId, conn, proxy, sshExec2) {
|
|
752
|
-
const
|
|
753
|
-
const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${
|
|
752
|
+
const sql36 = `SELECT level, message, \\"isError\\", \\"createdAt\\" FROM \\"TaskEvent\\" WHERE \\"runId\\" = '${runId}' AND level IN ('INFO','WARN','ERROR','DEBUG','LOG','TRACE') ORDER BY \\"startTime\\" ASC LIMIT 200`;
|
|
753
|
+
const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql36}" 2>/dev/null`;
|
|
754
754
|
const result = await sshExec2(conn, cmd, proxy);
|
|
755
755
|
const output = result.stdout.trim();
|
|
756
756
|
if (!output) return "";
|
|
@@ -832,8 +832,8 @@ async function handleTriggerTool(name, args2, deps) {
|
|
|
832
832
|
switch (name) {
|
|
833
833
|
// -----------------------------------------------------------------
|
|
834
834
|
case "trigger-list": {
|
|
835
|
-
const
|
|
836
|
-
const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${
|
|
835
|
+
const sql36 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
|
|
836
|
+
const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql36}" 2>/dev/null`;
|
|
837
837
|
const result = await sshExec2(conn, cmd, proxy);
|
|
838
838
|
const output = result.stdout.trim();
|
|
839
839
|
if (!output) {
|
|
@@ -1317,6 +1317,56 @@ async function proxyJson(ctx, route, body) {
|
|
|
1317
1317
|
};
|
|
1318
1318
|
}
|
|
1319
1319
|
|
|
1320
|
+
// src/git-credential-tools.ts
|
|
1321
|
+
var GIT_CREDENTIAL_TOOL_NAME = "git-credential";
|
|
1322
|
+
var GIT_CREDENTIAL_TOOLS = [
|
|
1323
|
+
{
|
|
1324
|
+
name: GIT_CREDENTIAL_TOOL_NAME,
|
|
1325
|
+
description: "Issue a 15-minute mggit access token for git.mgsoftware.nl (username=token, Basic password). Bound to owner/name + write bit. Intended for git credential helpers and agents that need to clone/fetch/push. Not a git runner \u2014 do not use this to execute git commands. Requires module git_hosting.",
|
|
1326
|
+
inputSchema: {
|
|
1327
|
+
type: "object",
|
|
1328
|
+
properties: {
|
|
1329
|
+
repo: {
|
|
1330
|
+
type: "string",
|
|
1331
|
+
description: "Repository as owner/name (e.g. MGSoftwareBV/mg-dashboard)."
|
|
1332
|
+
},
|
|
1333
|
+
write: {
|
|
1334
|
+
type: "boolean",
|
|
1335
|
+
description: "Request push rights (default true). Fetch-only: false."
|
|
1336
|
+
}
|
|
1337
|
+
},
|
|
1338
|
+
required: ["repo"]
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
];
|
|
1342
|
+
async function handleGitCredentialTool(args2, ctx) {
|
|
1343
|
+
const repo = typeof args2.repo === "string" ? args2.repo.trim() : "";
|
|
1344
|
+
if (!repo) {
|
|
1345
|
+
return { content: [{ type: "text", text: "Error: repo is required (owner/name)" }] };
|
|
1346
|
+
}
|
|
1347
|
+
const write = args2.write !== false;
|
|
1348
|
+
const res = await fetch(`${ctx.dashboardBaseUrl.replace(/\/$/, "")}/api/git/credential`, {
|
|
1349
|
+
method: "POST",
|
|
1350
|
+
headers: {
|
|
1351
|
+
"content-type": "application/json",
|
|
1352
|
+
authorization: `Bearer ${ctx.apiKey}`
|
|
1353
|
+
},
|
|
1354
|
+
body: JSON.stringify({ repo, write })
|
|
1355
|
+
});
|
|
1356
|
+
const text23 = await res.text().catch(() => "");
|
|
1357
|
+
if (!res.ok) {
|
|
1358
|
+
return {
|
|
1359
|
+
content: [
|
|
1360
|
+
{
|
|
1361
|
+
type: "text",
|
|
1362
|
+
text: `Error: git-credential failed (${res.status}). ${text23.slice(0, 300)}`
|
|
1363
|
+
}
|
|
1364
|
+
]
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
return { content: [{ type: "text", text: text23 || "{}" }] };
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1320
1370
|
// src/mailserver-tools.ts
|
|
1321
1371
|
var MAILSERVER_TOOL_NAME = "mailserver";
|
|
1322
1372
|
var MAILSERVER_ACTIONS = [
|
|
@@ -7331,6 +7381,26 @@ pgTable(
|
|
|
7331
7381
|
index("git_access_log_op_status_idx").on(table.op, table.status)
|
|
7332
7382
|
]
|
|
7333
7383
|
);
|
|
7384
|
+
pgTable(
|
|
7385
|
+
"git_credential_grant",
|
|
7386
|
+
{
|
|
7387
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
7388
|
+
tokenHash: text("token_hash").notNull(),
|
|
7389
|
+
userId: uuid("user_id").notNull(),
|
|
7390
|
+
apiKeyId: uuid("api_key_id").notNull(),
|
|
7391
|
+
repo: text("repo").notNull(),
|
|
7392
|
+
write: boolean("write").notNull().default(true),
|
|
7393
|
+
principal: text("principal").notNull(),
|
|
7394
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
7395
|
+
issuedIp: text("issued_ip").notNull().default(""),
|
|
7396
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
7397
|
+
},
|
|
7398
|
+
(table) => [
|
|
7399
|
+
uniqueIndex("git_credential_grant_token_hash_uidx").on(table.tokenHash),
|
|
7400
|
+
index("git_credential_grant_expires_idx").on(table.expiresAt),
|
|
7401
|
+
index("git_credential_grant_user_idx").on(table.userId, table.expiresAt)
|
|
7402
|
+
]
|
|
7403
|
+
);
|
|
7334
7404
|
var directoryLinkType = pgEnum("directory_link_type", [
|
|
7335
7405
|
"dofollow",
|
|
7336
7406
|
"nofollow",
|
|
@@ -8135,6 +8205,22 @@ pgTable(
|
|
|
8135
8205
|
)
|
|
8136
8206
|
]
|
|
8137
8207
|
);
|
|
8208
|
+
|
|
8209
|
+
// ../platform/dist/utils/permissions.js
|
|
8210
|
+
var MODULE_KEYS = [
|
|
8211
|
+
"users",
|
|
8212
|
+
"ssh_servers",
|
|
8213
|
+
"wiki",
|
|
8214
|
+
"ci_cd",
|
|
8215
|
+
"settings",
|
|
8216
|
+
"cursor_remote",
|
|
8217
|
+
"code_battle",
|
|
8218
|
+
"git_hosting"
|
|
8219
|
+
];
|
|
8220
|
+
({
|
|
8221
|
+
modules: Object.fromEntries(MODULE_KEYS.map((k) => [k, false]))});
|
|
8222
|
+
({
|
|
8223
|
+
modules: Object.fromEntries(MODULE_KEYS.map((k) => [k, true]))});
|
|
8138
8224
|
var SSH_POOL_IDLE_MS = 6e4;
|
|
8139
8225
|
var sshPool = /* @__PURE__ */ new Map();
|
|
8140
8226
|
function poolKey(options) {
|
|
@@ -10688,7 +10774,7 @@ async function writeAuditLog(entry) {
|
|
|
10688
10774
|
);
|
|
10689
10775
|
}
|
|
10690
10776
|
}
|
|
10691
|
-
var
|
|
10777
|
+
var MODULE_KEYS2 = [
|
|
10692
10778
|
"users",
|
|
10693
10779
|
"ssh_servers",
|
|
10694
10780
|
"wiki",
|
|
@@ -10699,9 +10785,9 @@ var MODULE_KEYS = [
|
|
|
10699
10785
|
"code_battle",
|
|
10700
10786
|
"git_hosting"
|
|
10701
10787
|
];
|
|
10702
|
-
var
|
|
10788
|
+
var FULL_PERMISSIONS2 = {
|
|
10703
10789
|
modules: Object.fromEntries(
|
|
10704
|
-
|
|
10790
|
+
MODULE_KEYS2.map((k) => [k, true])
|
|
10705
10791
|
),
|
|
10706
10792
|
resources: { ssh_servers: ["*"] }
|
|
10707
10793
|
};
|
|
@@ -10709,12 +10795,12 @@ function parsePermissions(raw) {
|
|
|
10709
10795
|
if (!raw || typeof raw !== "object") return null;
|
|
10710
10796
|
return raw;
|
|
10711
10797
|
}
|
|
10712
|
-
function
|
|
10713
|
-
if (roleName === "superadmin") return
|
|
10798
|
+
function resolvePermissions2(roleName, roleDefaults, userOverrides) {
|
|
10799
|
+
if (roleName === "superadmin") return FULL_PERMISSIONS2;
|
|
10714
10800
|
const base = parsePermissions(roleDefaults);
|
|
10715
10801
|
const overrides = parsePermissions(userOverrides);
|
|
10716
10802
|
const modules = {};
|
|
10717
|
-
for (const key of
|
|
10803
|
+
for (const key of MODULE_KEYS2) {
|
|
10718
10804
|
const userVal = overrides?.modules?.[key];
|
|
10719
10805
|
const roleVal = base?.modules?.[key];
|
|
10720
10806
|
modules[key] = userVal !== void 0 ? userVal : roleVal !== void 0 ? roleVal : false;
|
|
@@ -10763,6 +10849,7 @@ var TOOL_MODULE_MAP = {
|
|
|
10763
10849
|
"cursor-remote-list": "cursor_remote",
|
|
10764
10850
|
"cursor-remote-run": "cursor_remote",
|
|
10765
10851
|
"ai-company": "ssh_servers",
|
|
10852
|
+
"git-credential": "git_hosting",
|
|
10766
10853
|
// cursor-skill intentionally unmapped — any valid API key may pull shared skills
|
|
10767
10854
|
...TRIGGER_TOOL_MODULE_MAP
|
|
10768
10855
|
};
|
|
@@ -10906,7 +10993,7 @@ async function validateApiKey(key) {
|
|
|
10906
10993
|
const roleName = userData.role_name || "user";
|
|
10907
10994
|
const roleDefaults = userData.role_default_permissions ?? {};
|
|
10908
10995
|
const userOverrides = userData.permissions ?? null;
|
|
10909
|
-
const permissions =
|
|
10996
|
+
const permissions = resolvePermissions2(roleName, roleDefaults, userOverrides);
|
|
10910
10997
|
const allowedServerIds = intersectServerAccess(
|
|
10911
10998
|
data.allowed_server_ids,
|
|
10912
10999
|
permissions.resources.ssh_servers
|
|
@@ -10917,9 +11004,9 @@ async function validateApiKey(key) {
|
|
|
10917
11004
|
WHERE id = ${data.id}
|
|
10918
11005
|
AND (last_used_at IS NULL OR last_used_at < now() - interval '60 seconds')
|
|
10919
11006
|
`);
|
|
10920
|
-
const moduleCount =
|
|
11007
|
+
const moduleCount = MODULE_KEYS2.filter((k) => permissions.modules[k]).length;
|
|
10921
11008
|
console.error(
|
|
10922
|
-
`Authenticated as user ${data.created_by} (role: ${roleName}, modules: ${moduleCount}/${
|
|
11009
|
+
`Authenticated as user ${data.created_by} (role: ${roleName}, modules: ${moduleCount}/${MODULE_KEYS2.length})`
|
|
10923
11010
|
);
|
|
10924
11011
|
return {
|
|
10925
11012
|
apiKeyId: data.id,
|
|
@@ -11153,7 +11240,7 @@ async function validateSshKey(pubkeyPathInput, expectedApiKeyId) {
|
|
|
11153
11240
|
const roleName = userData.role_name || "user";
|
|
11154
11241
|
const roleDefaults = userData.role_default_permissions ?? {};
|
|
11155
11242
|
const userOverrides = userData.permissions ?? null;
|
|
11156
|
-
const permissions =
|
|
11243
|
+
const permissions = resolvePermissions2(roleName, roleDefaults, userOverrides);
|
|
11157
11244
|
const allowedServerIds = intersectServerAccess(
|
|
11158
11245
|
apiRow.allowed_server_ids,
|
|
11159
11246
|
permissions.resources.ssh_servers
|
|
@@ -11170,9 +11257,9 @@ async function validateSshKey(pubkeyPathInput, expectedApiKeyId) {
|
|
|
11170
11257
|
AND (last_used_at IS NULL OR last_used_at < now() - interval '60 seconds')`
|
|
11171
11258
|
)
|
|
11172
11259
|
]);
|
|
11173
|
-
const moduleCount =
|
|
11260
|
+
const moduleCount = MODULE_KEYS2.filter((k) => permissions.modules[k]).length;
|
|
11174
11261
|
console.error(
|
|
11175
|
-
`Authenticated via SSH key "${keyRow.name}" (fp ${fingerprint.slice(0, 24)}...) as user ${apiRow.created_by} (role: ${roleName}, modules: ${moduleCount}/${
|
|
11262
|
+
`Authenticated via SSH key "${keyRow.name}" (fp ${fingerprint.slice(0, 24)}...) as user ${apiRow.created_by} (role: ${roleName}, modules: ${moduleCount}/${MODULE_KEYS2.length})`
|
|
11176
11263
|
);
|
|
11177
11264
|
return {
|
|
11178
11265
|
apiKeyId: apiRow.id,
|
|
@@ -13453,11 +13540,11 @@ CREATE TABLE IF NOT EXISTS _mcp_migrations (
|
|
|
13453
13540
|
applied_by TEXT
|
|
13454
13541
|
);
|
|
13455
13542
|
`.trim();
|
|
13456
|
-
function normaliseMigrationSql(
|
|
13457
|
-
return
|
|
13543
|
+
function normaliseMigrationSql(sql36) {
|
|
13544
|
+
return sql36.replace(/\r\n/g, "\n").trim() + "\n";
|
|
13458
13545
|
}
|
|
13459
|
-
function migrationSha256(
|
|
13460
|
-
return createHash("sha256").update(
|
|
13546
|
+
function migrationSha256(sql36) {
|
|
13547
|
+
return createHash("sha256").update(sql36.replace(/\r\n/g, "\n"), "utf8").digest("hex");
|
|
13461
13548
|
}
|
|
13462
13549
|
function dollarQuoteTag(value) {
|
|
13463
13550
|
let tag = "_mcp";
|
|
@@ -15469,6 +15556,7 @@ var TOOLS = [
|
|
|
15469
15556
|
}
|
|
15470
15557
|
},
|
|
15471
15558
|
...MAILSERVER_TOOLS,
|
|
15559
|
+
...GIT_CREDENTIAL_TOOLS,
|
|
15472
15560
|
...HERMES_COMPANY_TOOLS,
|
|
15473
15561
|
// ----- Trigger.dev -----
|
|
15474
15562
|
...TRIGGER_TOOLS
|
|
@@ -19237,6 +19325,12 @@ Install: GET https://dashboard.mgsoftware.nl/api/downloads/versions.txt then \u2
|
|
|
19237
19325
|
token
|
|
19238
19326
|
});
|
|
19239
19327
|
}
|
|
19328
|
+
case GIT_CREDENTIAL_TOOL_NAME: {
|
|
19329
|
+
return handleGitCredentialTool(a, {
|
|
19330
|
+
dashboardBaseUrl,
|
|
19331
|
+
apiKey: apiKey ?? ""
|
|
19332
|
+
});
|
|
19333
|
+
}
|
|
19240
19334
|
case HERMES_COMPANY_TOOL_NAME: {
|
|
19241
19335
|
return handleHermesCompanyTool(a, {
|
|
19242
19336
|
userId: ctx.userId,
|
package/package.json
CHANGED