@systemdox/mcp-server 0.1.14 → 0.1.15

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/cli.js CHANGED
@@ -246,6 +246,27 @@ var init_deprecation = __esm({
246
246
  }
247
247
  });
248
248
 
249
+ // src/lib/config-links.ts
250
+ async function workspaceBase(apiClient2) {
251
+ try {
252
+ const access = await apiClient2.get(
253
+ "/v1/docs/portal-access"
254
+ );
255
+ const slug = (access.host ?? "").split(".")[0];
256
+ return slug ? `https://${slug}.systemdox.com` : null;
257
+ } catch {
258
+ return null;
259
+ }
260
+ }
261
+ function configLink(path, base) {
262
+ return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
263
+ }
264
+ var init_config_links = __esm({
265
+ "src/lib/config-links.ts"() {
266
+ "use strict";
267
+ }
268
+ });
269
+
249
270
  // src/tools/get-guardrails.ts
250
271
  import { z } from "zod";
251
272
  function registerGetGuardrails(server2, apiClient2) {
@@ -268,13 +289,9 @@ function registerGetGuardrails(server2, apiClient2) {
268
289
  );
269
290
  }
270
291
  if (filtered.length === 0) {
292
+ const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient2))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
271
293
  return {
272
- content: [
273
- {
274
- type: "text",
275
- text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
276
- }
277
- ]
294
+ content: [{ type: "text", text: text2 }]
278
295
  };
279
296
  }
280
297
  const text = filtered.map(
@@ -331,6 +348,7 @@ var init_get_guardrails = __esm({
331
348
  "use strict";
332
349
  init_language();
333
350
  init_deprecation();
351
+ init_config_links();
334
352
  DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
335
353
  inputSchema = () => ({
336
354
  language: z.string().optional().describe(
@@ -559,7 +577,7 @@ function registerGetTechStack(server2, apiClient2) {
559
577
  content: [
560
578
  {
561
579
  type: "text",
562
- text: "No tech stack entries configured."
580
+ text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient2))}`
563
581
  }
564
582
  ]
565
583
  };
@@ -593,6 +611,7 @@ ${sections}`
593
611
  var init_get_tech_stack = __esm({
594
612
  "src/tools/get-tech-stack.ts"() {
595
613
  "use strict";
614
+ init_config_links();
596
615
  }
597
616
  });
598
617
 
@@ -1527,13 +1546,9 @@ function registerGetProjectRules(server2, apiClient2) {
1527
1546
  );
1528
1547
  }
1529
1548
  if (filtered.length === 0) {
1549
+ const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient2))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
1530
1550
  return {
1531
- content: [
1532
- {
1533
- type: "text",
1534
- text: `No project rules found${category ? ` in category "${category}"` : ""}.`
1535
- }
1536
- ]
1551
+ content: [{ type: "text", text: text2 }]
1537
1552
  };
1538
1553
  }
1539
1554
  const grouped = /* @__PURE__ */ new Map();
@@ -1571,6 +1586,7 @@ var CATEGORY_LABELS;
1571
1586
  var init_get_project_rules = __esm({
1572
1587
  "src/tools/get-project-rules.ts"() {
1573
1588
  "use strict";
1589
+ init_config_links();
1574
1590
  CATEGORY_LABELS = {
1575
1591
  deployment: "Deployment",
1576
1592
  architecture: "Architecture",
@@ -1641,7 +1657,7 @@ function registerGetPromptTemplates(server2, apiClient2) {
1641
1657
  content: [
1642
1658
  {
1643
1659
  type: "text",
1644
- text: "No prompt templates found."
1660
+ text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient2))}`
1645
1661
  }
1646
1662
  ]
1647
1663
  };
@@ -1671,6 +1687,7 @@ ${text}`
1671
1687
  var init_get_prompt_templates = __esm({
1672
1688
  "src/tools/get-prompt-templates.ts"() {
1673
1689
  "use strict";
1690
+ init_config_links();
1674
1691
  }
1675
1692
  });
1676
1693
 
package/dist/http.js CHANGED
@@ -200,6 +200,22 @@ function legacyToolDescription(canonical, description) {
200
200
  return `DEPRECATED \u2014 use \`${canonical}\` instead. This name still works and will not be removed before ${LEGACY_TOOL_REMOVAL_EARLIEST}. ${description}`;
201
201
  }
202
202
 
203
+ // src/lib/config-links.ts
204
+ async function workspaceBase(apiClient) {
205
+ try {
206
+ const access = await apiClient.get(
207
+ "/v1/docs/portal-access"
208
+ );
209
+ const slug = (access.host ?? "").split(".")[0];
210
+ return slug ? `https://${slug}.systemdox.com` : null;
211
+ } catch {
212
+ return null;
213
+ }
214
+ }
215
+ function configLink(path, base) {
216
+ return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
217
+ }
218
+
203
219
  // src/tools/get-guardrails.ts
204
220
  var DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
205
221
  var inputSchema = () => ({
@@ -233,13 +249,9 @@ function registerGetGuardrails(server, apiClient) {
233
249
  );
234
250
  }
235
251
  if (filtered.length === 0) {
252
+ const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
236
253
  return {
237
- content: [
238
- {
239
- type: "text",
240
- text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
241
- }
242
- ]
254
+ content: [{ type: "text", text: text2 }]
243
255
  };
244
256
  }
245
257
  const text = filtered.map(
@@ -494,7 +506,7 @@ function registerGetTechStack(server, apiClient) {
494
506
  content: [
495
507
  {
496
508
  type: "text",
497
- text: "No tech stack entries configured."
509
+ text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient))}`
498
510
  }
499
511
  ]
500
512
  };
@@ -1424,13 +1436,9 @@ function registerGetProjectRules(server, apiClient) {
1424
1436
  );
1425
1437
  }
1426
1438
  if (filtered.length === 0) {
1439
+ const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
1427
1440
  return {
1428
- content: [
1429
- {
1430
- type: "text",
1431
- text: `No project rules found${category ? ` in category "${category}"` : ""}.`
1432
- }
1433
- ]
1441
+ content: [{ type: "text", text: text2 }]
1434
1442
  };
1435
1443
  }
1436
1444
  const grouped = /* @__PURE__ */ new Map();
@@ -1519,7 +1527,7 @@ function registerGetPromptTemplates(server, apiClient) {
1519
1527
  content: [
1520
1528
  {
1521
1529
  type: "text",
1522
- text: "No prompt templates found."
1530
+ text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient))}`
1523
1531
  }
1524
1532
  ]
1525
1533
  };
package/dist/index.js CHANGED
@@ -216,6 +216,22 @@ function legacyToolDescription(canonical, description) {
216
216
  return `DEPRECATED \u2014 use \`${canonical}\` instead. This name still works and will not be removed before ${LEGACY_TOOL_REMOVAL_EARLIEST}. ${description}`;
217
217
  }
218
218
 
219
+ // src/lib/config-links.ts
220
+ async function workspaceBase(apiClient2) {
221
+ try {
222
+ const access = await apiClient2.get(
223
+ "/v1/docs/portal-access"
224
+ );
225
+ const slug = (access.host ?? "").split(".")[0];
226
+ return slug ? `https://${slug}.systemdox.com` : null;
227
+ } catch {
228
+ return null;
229
+ }
230
+ }
231
+ function configLink(path, base) {
232
+ return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
233
+ }
234
+
219
235
  // src/tools/get-guardrails.ts
220
236
  var DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
221
237
  var inputSchema = () => ({
@@ -249,13 +265,9 @@ function registerGetGuardrails(server2, apiClient2) {
249
265
  );
250
266
  }
251
267
  if (filtered.length === 0) {
268
+ const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient2))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
252
269
  return {
253
- content: [
254
- {
255
- type: "text",
256
- text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
257
- }
258
- ]
270
+ content: [{ type: "text", text: text2 }]
259
271
  };
260
272
  }
261
273
  const text = filtered.map(
@@ -510,7 +522,7 @@ function registerGetTechStack(server2, apiClient2) {
510
522
  content: [
511
523
  {
512
524
  type: "text",
513
- text: "No tech stack entries configured."
525
+ text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient2))}`
514
526
  }
515
527
  ]
516
528
  };
@@ -1440,13 +1452,9 @@ function registerGetProjectRules(server2, apiClient2) {
1440
1452
  );
1441
1453
  }
1442
1454
  if (filtered.length === 0) {
1455
+ const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient2))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
1443
1456
  return {
1444
- content: [
1445
- {
1446
- type: "text",
1447
- text: `No project rules found${category ? ` in category "${category}"` : ""}.`
1448
- }
1449
- ]
1457
+ content: [{ type: "text", text: text2 }]
1450
1458
  };
1451
1459
  }
1452
1460
  const grouped = /* @__PURE__ */ new Map();
@@ -1535,7 +1543,7 @@ function registerGetPromptTemplates(server2, apiClient2) {
1535
1543
  content: [
1536
1544
  {
1537
1545
  type: "text",
1538
- text: "No prompt templates found."
1546
+ text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient2))}`
1539
1547
  }
1540
1548
  ]
1541
1549
  };
@@ -0,0 +1,18 @@
1
+ import type { SystemDoxApiClient } from "./api-client.js";
2
+ /**
3
+ * The tenant's workspace base URL (https://{slug}.systemdox.com), or null
4
+ * when it can't be resolved. The slug is the first label of the portal host
5
+ * that GET /v1/docs/portal-access reports — the API builds that host as
6
+ * `{slug}.{DOCS_DOMAIN}`, so the first label is the slug whichever docs
7
+ * domain is live. The GET goes through the api client's response cache, so
8
+ * repeated empty states don't re-fetch.
9
+ */
10
+ export declare function workspaceBase(apiClient: SystemDoxApiClient): Promise<string | null>;
11
+ /**
12
+ * Where to add missing configuration: a full URL when the workspace base is
13
+ * known, the in-app path otherwise.
14
+ *
15
+ * Mirrored by apps/app/src/pages/ai/mcpPreview.ts — keep the output
16
+ * byte-identical when either side changes.
17
+ */
18
+ export declare function configLink(path: string, base: string | null): string;
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/config-links.ts
4
+ async function workspaceBase(apiClient) {
5
+ try {
6
+ const access = await apiClient.get(
7
+ "/v1/docs/portal-access"
8
+ );
9
+ const slug = (access.host ?? "").split(".")[0];
10
+ return slug ? `https://${slug}.systemdox.com` : null;
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+ function configLink(path, base) {
16
+ return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
17
+ }
18
+ export {
19
+ configLink,
20
+ workspaceBase
21
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@systemdox/mcp-server",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "description": "MCP server that exposes SystemDox checks, specs, docs, and tech stack to AI coding tools",
6
6
  "main": "./dist/index.js",