@systemdox/mcp-server 0.1.49 → 0.1.50

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/setup-mcp.js CHANGED
@@ -64,14 +64,6 @@ var SystemDoxApiClient = class {
64
64
  this.config = config;
65
65
  this.cache = new ResponseCache(config.cacheTtlMs);
66
66
  }
67
- async validate() {
68
- const res = await this.fetchRaw("/v1/health");
69
- if (!res.ok) {
70
- throw new Error(
71
- `SystemDox API authentication failed (${res.status}). Check your SYSTEMDOX_API_KEY.`
72
- );
73
- }
74
- }
75
67
  async get(path, params) {
76
68
  const url = this.buildUrl(path, params);
77
69
  const cacheKey = url.toString();
@@ -85,8 +77,8 @@ var SystemDoxApiClient = class {
85
77
  }
86
78
  /** A read that skips the cache: an install must take the version that is
87
79
  * latest now, not the one cached before someone published another. */
88
- async getFresh(path) {
89
- const res = await this.fetchRaw(path);
80
+ async getFresh(path, signal) {
81
+ const res = await this.fetchRaw(path, void 0, signal);
90
82
  if (!res.ok) throw new SystemDoxApiError(res.status, await res.text());
91
83
  return await res.json();
92
84
  }
@@ -116,8 +108,8 @@ var SystemDoxApiClient = class {
116
108
  // One method per operationId. Every read skips the cache: setup, sync and
117
109
  // plugin-path act on what the workspace holds now.
118
110
  /** getOwnTeamSetup: the key's own workspace, named in `workspace`. */
119
- getOwnTeamSetup() {
120
- return this.getFresh(TEAM_SETUP);
111
+ getOwnTeamSetup(signal) {
112
+ return this.getFresh(TEAM_SETUP, signal);
121
113
  }
122
114
  getTeamSetup(workspace) {
123
115
  return this.getFresh(`${TEAM_SETUP}/${seg(workspace)}`);
@@ -221,14 +213,15 @@ var SystemDoxApiClient = class {
221
213
  }
222
214
  return url;
223
215
  }
224
- async fetchRaw(path, params) {
216
+ async fetchRaw(path, params, signal) {
225
217
  const url = this.buildUrl(path, params);
226
218
  return fetch(url, {
227
219
  headers: {
228
220
  Authorization: `Bearer ${this.config.apiKey}`,
229
221
  "X-API-Key": this.config.apiKey,
230
222
  Accept: "application/json"
231
- }
223
+ },
224
+ signal
232
225
  });
233
226
  }
234
227
  };
@@ -615,9 +608,10 @@ async function setupMcpServer(opts) {
615
608
  Your key for ${workspace} is in ${credentialsPath()} (readable by you alone), not in these configs.
616
609
 
617
610
  Done! Restart your AI coding tool to activate the SystemDox MCP server.
618
- The server provides 21 tools: get_context, get_checks,
611
+ The server provides 25 tools: get_context, get_team_setup, get_checks,
619
612
  get_project_rules, get_prompt_templates, get_specs, get_docs,
620
613
  get_tech_stack, get_planning_context, get_plan_board, get_change,
614
+ get_document_links, trace_document_path, get_graph_stats,
621
615
  create_check, create_project_rule, create_prompt_template,
622
616
  update_spec, report_decision, publish_skill, list_skills,
623
617
  install_skill, publish_setup_part, resolve_person, sync_memory.
@@ -68,14 +68,6 @@ var SystemDoxApiClient = class {
68
68
  this.config = config;
69
69
  this.cache = new ResponseCache(config.cacheTtlMs);
70
70
  }
71
- async validate() {
72
- const res = await this.fetchRaw("/v1/health");
73
- if (!res.ok) {
74
- throw new Error(
75
- `SystemDox API authentication failed (${res.status}). Check your SYSTEMDOX_API_KEY.`
76
- );
77
- }
78
- }
79
71
  async get(path, params) {
80
72
  const url = this.buildUrl(path, params);
81
73
  const cacheKey = url.toString();
@@ -89,8 +81,8 @@ var SystemDoxApiClient = class {
89
81
  }
90
82
  /** A read that skips the cache: an install must take the version that is
91
83
  * latest now, not the one cached before someone published another. */
92
- async getFresh(path) {
93
- const res = await this.fetchRaw(path);
84
+ async getFresh(path, signal) {
85
+ const res = await this.fetchRaw(path, void 0, signal);
94
86
  if (!res.ok) throw new SystemDoxApiError(res.status, await res.text());
95
87
  return await res.json();
96
88
  }
@@ -120,8 +112,8 @@ var SystemDoxApiClient = class {
120
112
  // One method per operationId. Every read skips the cache: setup, sync and
121
113
  // plugin-path act on what the workspace holds now.
122
114
  /** getOwnTeamSetup: the key's own workspace, named in `workspace`. */
123
- getOwnTeamSetup() {
124
- return this.getFresh(TEAM_SETUP);
115
+ getOwnTeamSetup(signal) {
116
+ return this.getFresh(TEAM_SETUP, signal);
125
117
  }
126
118
  getTeamSetup(workspace) {
127
119
  return this.getFresh(`${TEAM_SETUP}/${seg(workspace)}`);
@@ -225,14 +217,15 @@ var SystemDoxApiClient = class {
225
217
  }
226
218
  return url;
227
219
  }
228
- async fetchRaw(path, params) {
220
+ async fetchRaw(path, params, signal) {
229
221
  const url = this.buildUrl(path, params);
230
222
  return fetch(url, {
231
223
  headers: {
232
224
  Authorization: `Bearer ${this.config.apiKey}`,
233
225
  "X-API-Key": this.config.apiKey,
234
226
  Accept: "application/json"
235
- }
227
+ },
228
+ signal
236
229
  });
237
230
  }
238
231
  };
@@ -65,14 +65,6 @@ var SystemDoxApiClient = class {
65
65
  this.config = config;
66
66
  this.cache = new ResponseCache(config.cacheTtlMs);
67
67
  }
68
- async validate() {
69
- const res = await this.fetchRaw("/v1/health");
70
- if (!res.ok) {
71
- throw new Error(
72
- `SystemDox API authentication failed (${res.status}). Check your SYSTEMDOX_API_KEY.`
73
- );
74
- }
75
- }
76
68
  async get(path, params) {
77
69
  const url = this.buildUrl(path, params);
78
70
  const cacheKey = url.toString();
@@ -86,8 +78,8 @@ var SystemDoxApiClient = class {
86
78
  }
87
79
  /** A read that skips the cache: an install must take the version that is
88
80
  * latest now, not the one cached before someone published another. */
89
- async getFresh(path) {
90
- const res = await this.fetchRaw(path);
81
+ async getFresh(path, signal) {
82
+ const res = await this.fetchRaw(path, void 0, signal);
91
83
  if (!res.ok) throw new SystemDoxApiError(res.status, await res.text());
92
84
  return await res.json();
93
85
  }
@@ -117,8 +109,8 @@ var SystemDoxApiClient = class {
117
109
  // One method per operationId. Every read skips the cache: setup, sync and
118
110
  // plugin-path act on what the workspace holds now.
119
111
  /** getOwnTeamSetup: the key's own workspace, named in `workspace`. */
120
- getOwnTeamSetup() {
121
- return this.getFresh(TEAM_SETUP);
112
+ getOwnTeamSetup(signal) {
113
+ return this.getFresh(TEAM_SETUP, signal);
122
114
  }
123
115
  getTeamSetup(workspace) {
124
116
  return this.getFresh(`${TEAM_SETUP}/${seg(workspace)}`);
@@ -222,14 +214,15 @@ var SystemDoxApiClient = class {
222
214
  }
223
215
  return url;
224
216
  }
225
- async fetchRaw(path, params) {
217
+ async fetchRaw(path, params, signal) {
226
218
  const url = this.buildUrl(path, params);
227
219
  return fetch(url, {
228
220
  headers: {
229
221
  Authorization: `Bearer ${this.config.apiKey}`,
230
222
  "X-API-Key": this.config.apiKey,
231
223
  Accept: "application/json"
232
- }
224
+ },
225
+ signal
233
226
  });
234
227
  }
235
228
  };
@@ -0,0 +1,87 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { SystemDoxApiClient } from "../lib/api-client.js";
3
+ /**
4
+ * The document graph over MCP (ADR-224, specs/changes/document-graph/contract.md §5).
5
+ * Three read-only tools on the hosted and the local server. Every answer says
6
+ * how each link is known, and one that was cut says so.
7
+ */
8
+ interface GraphNode {
9
+ id: string;
10
+ label: string;
11
+ type: string;
12
+ repo: string;
13
+ path: string;
14
+ }
15
+ interface NeighbourLink {
16
+ direction: "out" | "in";
17
+ relation: string;
18
+ provenance: string;
19
+ confidence: number;
20
+ file: string;
21
+ line: number;
22
+ other: GraphNode;
23
+ }
24
+ interface AmbiguousLink {
25
+ reference: string;
26
+ file: string;
27
+ line: number;
28
+ candidates: GraphNode[];
29
+ }
30
+ interface Neighbours {
31
+ doc: GraphNode;
32
+ links: NeighbourLink[];
33
+ ambiguous: AmbiguousLink[];
34
+ total: number;
35
+ truncated: boolean;
36
+ }
37
+ interface PathStep {
38
+ from: GraphNode;
39
+ to: GraphNode;
40
+ relation: string;
41
+ provenance: string;
42
+ confidence: number;
43
+ file: string;
44
+ line: number;
45
+ reversed: boolean;
46
+ }
47
+ interface GraphPath {
48
+ found: boolean;
49
+ hops: number;
50
+ confidence: number;
51
+ steps: PathStep[];
52
+ }
53
+ interface RepoFreshness {
54
+ repo: string;
55
+ documents: number;
56
+ links: number;
57
+ indexedCommit: string;
58
+ indexedAt: string;
59
+ headCommit: string;
60
+ pushedAt: string;
61
+ behind: boolean;
62
+ }
63
+ interface GraphStats {
64
+ nodeCount: number;
65
+ edgeCount: number;
66
+ links: {
67
+ declared: number;
68
+ extracted: number;
69
+ inferred: number;
70
+ ambiguous: number;
71
+ };
72
+ repos: RepoFreshness[];
73
+ }
74
+ interface RepoLink {
75
+ source: string;
76
+ target: string;
77
+ relation: string;
78
+ provenance: string;
79
+ confidence: number;
80
+ file: string;
81
+ line: number;
82
+ }
83
+ export declare function formatNeighbours(answer: Neighbours): string;
84
+ export declare function formatPath(answer: GraphPath, maxHops: number): string;
85
+ export declare function formatStats(stats: GraphStats, repoLinks: RepoLink[]): string;
86
+ export declare function registerDocumentGraph(server: McpServer, apiClient: SystemDoxApiClient): void;
87
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { SystemDoxApiClient } from "../lib/api-client.js";
3
+ export declare function registerGetTeamSetup(server: McpServer, apiClient: SystemDoxApiClient, { localFiles, keyProblem }: {
4
+ localFiles: boolean;
5
+ keyProblem?: string;
6
+ }): void;
@@ -29,6 +29,7 @@ import { homedir } from "os";
29
29
  import { dirname, join, relative, resolve, sep } from "path";
30
30
  var MANIFEST_FILE = ".systemdox-skill.json";
31
31
  var ENTRY_FILE = "SKILL.md";
32
+ var PLUGIN_MANIFEST_FOLDER = ".claude-plugin";
32
33
  var MAX_FILES = 100;
33
34
  var MAX_FILE_BYTES = 256 * 1024;
34
35
  var MAX_TOTAL_BYTES = 1024 * 1024;
@@ -53,7 +54,7 @@ function isValidName(name) {
53
54
  return name.length <= 64 && NAME_RE.test(name);
54
55
  }
55
56
  function isValidPath(path) {
56
- return path.length > 0 && path.length <= 512 && !path.startsWith("/") && path.split("/").every((s) => SEGMENT_RE.test(s) && s !== "." && s !== "..");
57
+ return path.length > 0 && path.length <= 512 && !path.startsWith("/") && path.split("/").every((s) => SEGMENT_RE.test(s) && s !== "." && s !== ".." && s !== PLUGIN_MANIFEST_FOLDER);
57
58
  }
58
59
  function frontmatterName(skillMd) {
59
60
  const block = /^---\r?\n([\s\S]*?)\r?\n---/.exec(skillMd);
@@ -14,13 +14,14 @@ import { existsSync } from "fs";
14
14
  import { homedir } from "os";
15
15
  import { dirname, join, relative, resolve, sep } from "path";
16
16
  var MANIFEST_FILE = ".systemdox-skill.json";
17
+ var PLUGIN_MANIFEST_FOLDER = ".claude-plugin";
17
18
  var MAX_FILES = 100;
18
19
  var MAX_FILE_BYTES = 256 * 1024;
19
20
  var MAX_TOTAL_BYTES = 1024 * 1024;
20
21
  var SEGMENT_RE = /^[A-Za-z0-9._-]+$/;
21
22
  var SKIPPED = /* @__PURE__ */ new Set([MANIFEST_FILE, ".git", "node_modules", "__pycache__", ".DS_Store"]);
22
23
  function isValidPath(path) {
23
- return path.length > 0 && path.length <= 512 && !path.startsWith("/") && path.split("/").every((s) => SEGMENT_RE.test(s) && s !== "." && s !== "..");
24
+ return path.length > 0 && path.length <= 512 && !path.startsWith("/") && path.split("/").every((s) => SEGMENT_RE.test(s) && s !== "." && s !== ".." && s !== PLUGIN_MANIFEST_FOLDER);
24
25
  }
25
26
  async function walk(root, { skipHidden }, dir = root, out = { files: [], links: [], hidden: [] }) {
26
27
  for (const entry of await readdir(dir, { withFileTypes: true })) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@systemdox/mcp-server",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
4
4
  "mcpName": "io.github.puglieseweb/systemdox",
5
5
  "type": "module",
6
6
  "description": "Give AI coding agents your architecture context over MCP — checks, specs, ADRs, project rules, and docs from SystemDox, delivered at write time",