contract-driven-delivery 2.1.0 → 2.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.1] - 2026-05-29
4
+
5
+ MCP tool access for graph/code-map exploration.
6
+
7
+ ### Added
8
+
9
+ - **`cdd-kit mcp`**: runs a stdio MCP server exposing graph and code-map tools
10
+ (`cdd_graph_status`, `cdd_graph_context`, `cdd_graph_query`,
11
+ `cdd_graph_impact`, `cdd_index_query`, `cdd_index_impact`) so AI agents can
12
+ use project exploration as native tools instead of shell-only commands.
13
+
3
14
  ## [2.1.0] - 2026-05-27
4
15
 
5
16
  Native code graph and symptom-driven bug-fix workflow.
package/README.md CHANGED
@@ -713,6 +713,31 @@ Use `--engine native` for the built-in graph, `--engine codemap` for the older
713
713
  code-map-only fallback, `--engine codegraph` to require external CodeGraph, or
714
714
  `CDD_CODEGRAPH_BIN=/path/to/codegraph` to point at a custom binary.
715
715
 
716
+ ### `cdd-kit mcp`
717
+
718
+ `cdd-kit mcp` runs a stdio MCP server so agents can call the graph/index layer
719
+ as tools instead of shelling out manually.
720
+
721
+ ```json
722
+ {
723
+ "mcpServers": {
724
+ "cdd-kit": {
725
+ "command": "cdd-kit",
726
+ "args": ["mcp"]
727
+ }
728
+ }
729
+ }
730
+ ```
731
+
732
+ Exposed tools:
733
+
734
+ - `cdd_graph_status`
735
+ - `cdd_graph_context`
736
+ - `cdd_graph_query`
737
+ - `cdd_graph_impact`
738
+ - `cdd_index_query`
739
+ - `cdd_index_impact`
740
+
716
741
  Large Python repos are scanned in chunks (`CDD_CODE_MAP_BATCH_SIZE`, default 400)
717
742
  so one slow batch cannot drop the whole language. Raise
718
743
  `CDD_CODE_MAP_TIMEOUT_MS` (default 30000) if a single batch still times out.
@@ -9,7 +9,16 @@ auto-refreshing `cdd-kit index ...` commands for that job.
9
9
 
10
10
  ## Preferred workflow: graph/query before reading
11
11
 
12
- Before reading source, use the graph layer when available:
12
+ Before reading source, use the graph layer when available. If the `cdd-kit`
13
+ MCP server is configured, prefer these tools:
14
+
15
+ - `cdd_graph_context`
16
+ - `cdd_graph_query`
17
+ - `cdd_graph_impact`
18
+ - `cdd_index_query`
19
+ - `cdd_index_impact`
20
+
21
+ If MCP tools are not available, use the equivalent CLI commands:
13
22
 
14
23
  ```bash
15
24
  cdd-kit graph context "fix login redirect bug"
package/dist/cli/index.js CHANGED
@@ -11816,6 +11816,315 @@ var init_graph = __esm({
11816
11816
  }
11817
11817
  });
11818
11818
 
11819
+ // src/mcp/server.ts
11820
+ var server_exports = {};
11821
+ __export(server_exports, {
11822
+ runMcpServer: () => runMcpServer
11823
+ });
11824
+ import { spawnSync as spawnSync4 } from "child_process";
11825
+ import { fileURLToPath as fileURLToPath3 } from "url";
11826
+ import { createInterface } from "readline";
11827
+ async function runMcpServer(opts) {
11828
+ const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
11829
+ for await (const line of rl) {
11830
+ if (!line.trim())
11831
+ continue;
11832
+ let request;
11833
+ try {
11834
+ request = JSON.parse(line);
11835
+ } catch (err) {
11836
+ writeError(null, -32700, `Parse error: ${err.message}`);
11837
+ continue;
11838
+ }
11839
+ if (!request.method) {
11840
+ if ("id" in request)
11841
+ writeError(request.id ?? null, -32600, "Invalid Request: missing method");
11842
+ continue;
11843
+ }
11844
+ try {
11845
+ const result = await handleRequest(request, opts);
11846
+ if ("id" in request)
11847
+ writeResult(request.id ?? null, result);
11848
+ } catch (err) {
11849
+ if ("id" in request)
11850
+ writeError(request.id ?? null, -32e3, err.message);
11851
+ }
11852
+ }
11853
+ }
11854
+ async function handleRequest(request, opts) {
11855
+ switch (request.method) {
11856
+ case "initialize": {
11857
+ const params = asObject(request.params);
11858
+ return {
11859
+ protocolVersion: typeof params.protocolVersion === "string" ? params.protocolVersion : "2024-11-05",
11860
+ capabilities: {
11861
+ tools: { listChanged: false },
11862
+ resources: {},
11863
+ prompts: {}
11864
+ },
11865
+ serverInfo: {
11866
+ name: "cdd-kit",
11867
+ version: opts.version
11868
+ }
11869
+ };
11870
+ }
11871
+ case "ping":
11872
+ return {};
11873
+ case "tools/list":
11874
+ return { tools };
11875
+ case "tools/call": {
11876
+ const params = asObject(request.params);
11877
+ const name = requireString(params, "name");
11878
+ const args = asObject(params.arguments);
11879
+ return callTool(name, args);
11880
+ }
11881
+ case "resources/list":
11882
+ return { resources: [] };
11883
+ case "prompts/list":
11884
+ return { prompts: [] };
11885
+ case "notifications/initialized":
11886
+ return {};
11887
+ default:
11888
+ throw new Error(`Method not found: ${request.method}`);
11889
+ }
11890
+ }
11891
+ function callTool(name, args) {
11892
+ switch (name) {
11893
+ case "cdd_graph_status":
11894
+ return runCddJson([
11895
+ "graph",
11896
+ "status",
11897
+ "--engine",
11898
+ optionalString(args.engine, "auto"),
11899
+ "--map",
11900
+ optionalString(args.map, DEFAULT_MAP),
11901
+ "--json"
11902
+ ]);
11903
+ case "cdd_graph_query":
11904
+ return runCddJson([
11905
+ "graph",
11906
+ "query",
11907
+ requireString(args, "query"),
11908
+ "--engine",
11909
+ optionalString(args.engine, "auto"),
11910
+ "--map",
11911
+ optionalString(args.map, DEFAULT_MAP),
11912
+ "--limit",
11913
+ String(optionalInt(args.limit, 10)),
11914
+ "--json",
11915
+ ...refreshArgs(args)
11916
+ ]);
11917
+ case "cdd_graph_context":
11918
+ return runCddJson([
11919
+ "graph",
11920
+ "context",
11921
+ requireString(args, "task"),
11922
+ "--engine",
11923
+ optionalString(args.engine, "auto"),
11924
+ "--map",
11925
+ optionalString(args.map, DEFAULT_MAP),
11926
+ "--max-nodes",
11927
+ String(optionalInt(args.maxNodes, 20)),
11928
+ "--json",
11929
+ ...refreshArgs(args)
11930
+ ]);
11931
+ case "cdd_graph_impact":
11932
+ return runCddJson([
11933
+ "graph",
11934
+ "impact",
11935
+ requireString(args, "target"),
11936
+ "--engine",
11937
+ optionalString(args.engine, "auto"),
11938
+ "--map",
11939
+ optionalString(args.map, DEFAULT_MAP),
11940
+ "--limit",
11941
+ String(optionalInt(args.limit, 20)),
11942
+ "--depth",
11943
+ String(optionalInt(args.depth, 2)),
11944
+ "--json",
11945
+ ...refreshArgs(args)
11946
+ ]);
11947
+ case "cdd_index_query":
11948
+ return runCddJson([
11949
+ "index",
11950
+ "query",
11951
+ requireString(args, "query"),
11952
+ "--map",
11953
+ optionalString(args.map, DEFAULT_MAP),
11954
+ "--limit",
11955
+ String(optionalInt(args.limit, 10)),
11956
+ "--json",
11957
+ ...refreshArgs(args)
11958
+ ]);
11959
+ case "cdd_index_impact":
11960
+ return runCddJson([
11961
+ "index",
11962
+ "impact",
11963
+ requireString(args, "target"),
11964
+ "--map",
11965
+ optionalString(args.map, DEFAULT_MAP),
11966
+ "--limit",
11967
+ String(optionalInt(args.limit, 20)),
11968
+ "--json",
11969
+ ...refreshArgs(args)
11970
+ ]);
11971
+ default:
11972
+ return {
11973
+ isError: true,
11974
+ content: [{ type: "text", text: `Unknown tool: ${name}` }]
11975
+ };
11976
+ }
11977
+ }
11978
+ function runCddJson(args) {
11979
+ const cliPath = process.argv[1] || fileURLToPath3(import.meta.url);
11980
+ const result = spawnSync4(process.execPath, [cliPath, ...args], {
11981
+ cwd: process.cwd(),
11982
+ env: process.env,
11983
+ encoding: "utf8"
11984
+ });
11985
+ const stdout = result.stdout?.trim() ?? "";
11986
+ const stderr = result.stderr?.trim() ?? "";
11987
+ const isError = !!result.error || (result.status ?? 1) !== 0;
11988
+ if (stdout) {
11989
+ return {
11990
+ isError: isError || void 0,
11991
+ content: [{ type: "text", text: stdout }]
11992
+ };
11993
+ }
11994
+ return {
11995
+ isError: true,
11996
+ content: [{ type: "text", text: result.error?.message || stderr || `cdd-kit exited with status ${result.status}` }]
11997
+ };
11998
+ }
11999
+ function refreshArgs(args) {
12000
+ return args.refresh === false ? ["--no-refresh"] : [];
12001
+ }
12002
+ function asObject(value) {
12003
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
12004
+ }
12005
+ function requireString(args, key) {
12006
+ const value = args[key];
12007
+ if (typeof value !== "string" || value.trim() === "") {
12008
+ throw new Error(`Missing required string argument: ${key}`);
12009
+ }
12010
+ return value;
12011
+ }
12012
+ function optionalString(value, fallback) {
12013
+ return typeof value === "string" && value.trim() ? value : fallback;
12014
+ }
12015
+ function optionalInt(value, fallback) {
12016
+ const parsed = typeof value === "number" ? value : typeof value === "string" ? Number.parseInt(value, 10) : fallback;
12017
+ return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
12018
+ }
12019
+ function writeResult(id, result) {
12020
+ process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id, result })}
12021
+ `);
12022
+ }
12023
+ function writeError(id, code, message) {
12024
+ process.stdout.write(`${JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } })}
12025
+ `);
12026
+ }
12027
+ var DEFAULT_MAP, tools;
12028
+ var init_server = __esm({
12029
+ "src/mcp/server.ts"() {
12030
+ "use strict";
12031
+ DEFAULT_MAP = ".cdd/code-map.yml";
12032
+ tools = [
12033
+ {
12034
+ name: "cdd_graph_status",
12035
+ description: "Show the active cdd-kit graph engine and code-map/code-graph freshness for the current workspace.",
12036
+ inputSchema: {
12037
+ type: "object",
12038
+ properties: {
12039
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12040
+ engine: { type: "string", enum: ["auto", "native", "codegraph", "codemap"], default: "auto" }
12041
+ },
12042
+ additionalProperties: false
12043
+ }
12044
+ },
12045
+ {
12046
+ name: "cdd_graph_query",
12047
+ description: "Search native graph symbols/files and return candidate nodes with line ranges.",
12048
+ inputSchema: {
12049
+ type: "object",
12050
+ properties: {
12051
+ query: { type: "string", description: "Symbol, file path, file stem, class, function, component, or route term." },
12052
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
12053
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12054
+ engine: { type: "string", enum: ["auto", "native", "codegraph", "codemap"], default: "auto" },
12055
+ refresh: { type: "boolean", default: true }
12056
+ },
12057
+ required: ["query"],
12058
+ additionalProperties: false
12059
+ }
12060
+ },
12061
+ {
12062
+ name: "cdd_graph_context",
12063
+ description: "Build graph-first task context from a task, symptom, or known feature term.",
12064
+ inputSchema: {
12065
+ type: "object",
12066
+ properties: {
12067
+ task: { type: "string", description: "Task, bug symptom, feature name, screen name, or domain term." },
12068
+ maxNodes: { type: "integer", minimum: 1, maximum: 100, default: 20 },
12069
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12070
+ engine: { type: "string", enum: ["auto", "native", "codegraph", "codemap"], default: "auto" },
12071
+ refresh: { type: "boolean", default: true }
12072
+ },
12073
+ required: ["task"],
12074
+ additionalProperties: false
12075
+ }
12076
+ },
12077
+ {
12078
+ name: "cdd_graph_impact",
12079
+ description: "Analyze callers, callees, imports, references, and dependents for a file or symbol before editing.",
12080
+ inputSchema: {
12081
+ type: "object",
12082
+ properties: {
12083
+ target: { type: "string", description: "Candidate file path, symbol, graph node id, or qualified name." },
12084
+ depth: { type: "integer", minimum: 1, maximum: 10, default: 2 },
12085
+ limit: { type: "integer", minimum: 1, maximum: 200, default: 20 },
12086
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12087
+ engine: { type: "string", enum: ["auto", "native", "codegraph", "codemap"], default: "auto" },
12088
+ refresh: { type: "boolean", default: true }
12089
+ },
12090
+ required: ["target"],
12091
+ additionalProperties: false
12092
+ }
12093
+ },
12094
+ {
12095
+ name: "cdd_index_query",
12096
+ description: "Fallback code-map query for files, symbols, imports, and line ranges.",
12097
+ inputSchema: {
12098
+ type: "object",
12099
+ properties: {
12100
+ query: { type: "string", description: "Symbol, file path, import module, enum member, or substring." },
12101
+ limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
12102
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12103
+ refresh: { type: "boolean", default: true }
12104
+ },
12105
+ required: ["query"],
12106
+ additionalProperties: false
12107
+ }
12108
+ },
12109
+ {
12110
+ name: "cdd_index_impact",
12111
+ description: "Fallback code-map impact query for local imports and direct dependents.",
12112
+ inputSchema: {
12113
+ type: "object",
12114
+ properties: {
12115
+ target: { type: "string", description: "File path or unique symbol." },
12116
+ limit: { type: "integer", minimum: 1, maximum: 200, default: 20 },
12117
+ map: { type: "string", description: "Code-map YAML path.", default: DEFAULT_MAP },
12118
+ refresh: { type: "boolean", default: true }
12119
+ },
12120
+ required: ["target"],
12121
+ additionalProperties: false
12122
+ }
12123
+ }
12124
+ ];
12125
+ }
12126
+ });
12127
+
11819
12128
  // src/commands/archive.ts
11820
12129
  var archive_exports = {};
11821
12130
  __export(archive_exports, {
@@ -12358,7 +12667,7 @@ var init_context = __esm({
12358
12667
  // src/cli/index.ts
12359
12668
  import { readFileSync as readFileSync31 } from "fs";
12360
12669
  import os from "os";
12361
- import { fileURLToPath as fileURLToPath3 } from "url";
12670
+ import { fileURLToPath as fileURLToPath4 } from "url";
12362
12671
  import { dirname as dirname7, join as join30 } from "path";
12363
12672
  import { Command } from "commander";
12364
12673
 
@@ -13464,7 +13773,7 @@ async function installHooks() {
13464
13773
  }
13465
13774
 
13466
13775
  // src/cli/index.ts
13467
- var __dirname2 = dirname7(fileURLToPath3(import.meta.url));
13776
+ var __dirname2 = dirname7(fileURLToPath4(import.meta.url));
13468
13777
  var pkg = JSON.parse(readFileSync31(join30(__dirname2, "..", "..", "package.json"), "utf8"));
13469
13778
  var program = new Command();
13470
13779
  program.name("cdd-kit").description("Contract-Driven Delivery Kit CLI").version(pkg.version);
@@ -13622,6 +13931,10 @@ graph.command("context <task>").description("Build task context with native grap
13622
13931
  });
13623
13932
  process.exit(exit);
13624
13933
  });
13934
+ program.command("mcp").description("Run the cdd-kit MCP stdio server exposing graph and code-map tools").action(async () => {
13935
+ const { runMcpServer: runMcpServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
13936
+ await runMcpServer2({ version: pkg.version });
13937
+ });
13625
13938
  program.command("gate <change-id>").description("Run delivery-quality gate for a change (required artifacts, tasks, tier, contracts)").option("--strict", "Treat pending tasks (except section 7) as errors", false).action(async (id, opts) => {
13626
13939
  await gate(id, { strict: opts.strict });
13627
13940
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contract-driven-delivery",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Contract-driven delivery kit for AI coding agents with deterministic context indexes, manifest-backed read-scope governance, and orchestrated contracts-first delivery.",
5
5
  "keywords": [
6
6
  "contract-driven",