kcp-harness 0.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/LICENSE +201 -0
- package/dist/audit.d.ts +73 -0
- package/dist/audit.js +142 -0
- package/dist/budget-ledger.d.ts +85 -0
- package/dist/budget-ledger.js +100 -0
- package/dist/classifier.d.ts +35 -0
- package/dist/classifier.js +177 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +177 -0
- package/dist/config.d.ts +65 -0
- package/dist/config.js +91 -0
- package/dist/downstream.d.ts +50 -0
- package/dist/downstream.js +167 -0
- package/dist/governor.d.ts +34 -0
- package/dist/governor.js +201 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +21 -0
- package/dist/integrations/claude-code.d.ts +2 -0
- package/dist/integrations/claude-code.js +95 -0
- package/dist/integrations/cline.d.ts +2 -0
- package/dist/integrations/cline.js +70 -0
- package/dist/integrations/continue.d.ts +2 -0
- package/dist/integrations/continue.js +39 -0
- package/dist/integrations/copilot.d.ts +2 -0
- package/dist/integrations/copilot.js +69 -0
- package/dist/integrations/crush.d.ts +2 -0
- package/dist/integrations/crush.js +48 -0
- package/dist/integrations/cursor.d.ts +2 -0
- package/dist/integrations/cursor.js +65 -0
- package/dist/integrations/generate.d.ts +13 -0
- package/dist/integrations/generate.js +60 -0
- package/dist/integrations/openclaw.d.ts +2 -0
- package/dist/integrations/openclaw.js +67 -0
- package/dist/integrations/types.d.ts +51 -0
- package/dist/integrations/types.js +78 -0
- package/dist/integrations/windsurf.d.ts +2 -0
- package/dist/integrations/windsurf.js +67 -0
- package/dist/kcp-bridge.d.ts +2 -0
- package/dist/kcp-bridge.js +85 -0
- package/dist/proxy.d.ts +37 -0
- package/dist/proxy.js +394 -0
- package/dist/session.d.ts +50 -0
- package/dist/session.js +82 -0
- package/dist/temporal-watch.d.ts +63 -0
- package/dist/temporal-watch.js +147 -0
- package/package.json +56 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// GitHub Copilot integration — .vscode/mcp.json + .github/copilot-instructions.md
|
|
2
|
+
//
|
|
3
|
+
// IMPORTANT: VS Code Copilot uses "servers" as the top-level key,
|
|
4
|
+
// NOT "mcpServers" like every other agent. MCP tools are only
|
|
5
|
+
// available in Agent mode.
|
|
6
|
+
import { harnessServerEntry, governedPathsBlock, manifestRef } from "./generate.js";
|
|
7
|
+
export function generateCopilot(options) {
|
|
8
|
+
const server = harnessServerEntry(options);
|
|
9
|
+
const manifest = manifestRef(options);
|
|
10
|
+
// VS Code uses "servers" (not "mcpServers")
|
|
11
|
+
const vscodeMcp = {
|
|
12
|
+
path: ".vscode/mcp.json",
|
|
13
|
+
content: JSON.stringify({
|
|
14
|
+
servers: {
|
|
15
|
+
"kcp-harness": {
|
|
16
|
+
type: "stdio",
|
|
17
|
+
...server,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}, null, 2) + "\n",
|
|
21
|
+
commitToGit: true,
|
|
22
|
+
description: "VS Code MCP config — note: uses 'servers' key (not 'mcpServers'). Agent mode only.",
|
|
23
|
+
};
|
|
24
|
+
const instructions = {
|
|
25
|
+
path: ".github/copilot-instructions.md",
|
|
26
|
+
content: `# Knowledge Governance
|
|
27
|
+
|
|
28
|
+
This project uses the KCP Compliance Harness for deterministic knowledge governance.
|
|
29
|
+
|
|
30
|
+
## Governed Paths
|
|
31
|
+
|
|
32
|
+
${governedPathsBlock(options)}
|
|
33
|
+
|
|
34
|
+
These paths are governed by \`${manifest}\`. Use the kcp-harness MCP server to access them.
|
|
35
|
+
|
|
36
|
+
## Rules
|
|
37
|
+
|
|
38
|
+
1. Always call \`kcp_plan\` or \`kcp_load\` (via the kcp-harness MCP server) before reading governed files
|
|
39
|
+
2. The harness enforces budget ceilings, temporal validity, and access control
|
|
40
|
+
3. Use \`harness_status\` to check governance state
|
|
41
|
+
4. Direct file reads of governed paths may be blocked by the governance layer
|
|
42
|
+
|
|
43
|
+
## Available MCP Tools
|
|
44
|
+
|
|
45
|
+
- \`kcp_plan\` — deterministic load plan
|
|
46
|
+
- \`kcp_load\` — plan + load content
|
|
47
|
+
- \`kcp_trace\` — decision trace (13-gate cascade)
|
|
48
|
+
- \`harness_budget\` — session spend tracking
|
|
49
|
+
- \`harness_temporal_check\` — plan drift detection
|
|
50
|
+
`,
|
|
51
|
+
commitToGit: true,
|
|
52
|
+
description: "GitHub Copilot instructions — governance rules",
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
agent: "copilot",
|
|
56
|
+
name: "GitHub Copilot",
|
|
57
|
+
files: [vscodeMcp, instructions],
|
|
58
|
+
instructions: `## GitHub Copilot Integration
|
|
59
|
+
|
|
60
|
+
**IMPORTANT:** VS Code Copilot uses \`"servers"\` as the top-level key in \`.vscode/mcp.json\` — NOT \`"mcpServers"\`. MCP tools are only available in **Agent mode** (not Ask or Edit mode).
|
|
61
|
+
|
|
62
|
+
**Setup:**
|
|
63
|
+
1. Place \`.vscode/mcp.json\` in your project root
|
|
64
|
+
2. Place \`.github/copilot-instructions.md\` in your project root
|
|
65
|
+
3. In VS Code, switch Copilot Chat to Agent mode to access kcp-harness tools
|
|
66
|
+
|
|
67
|
+
For Copilot CLI, add to \`~/.copilot/mcp-config.json\` instead (uses \`mcpServers\` key + \`tools: ["*"]\`).`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Crush integration — MCP config + PrepareStep pattern documentation.
|
|
2
|
+
//
|
|
3
|
+
// Crush is a multi-model agent (30+ models) with native MCP support.
|
|
4
|
+
// The PrepareStep pattern lets Crush pre-load knowledge before the
|
|
5
|
+
// main task runs, ensuring governed knowledge is available in context.
|
|
6
|
+
import { harnessServerEntry, manifestRef } from "./generate.js";
|
|
7
|
+
export function generateCrush(options) {
|
|
8
|
+
const server = harnessServerEntry(options);
|
|
9
|
+
const manifest = manifestRef(options);
|
|
10
|
+
const crushJson = {
|
|
11
|
+
path: "crush.json",
|
|
12
|
+
content: JSON.stringify({
|
|
13
|
+
mcpServers: {
|
|
14
|
+
"kcp-harness": server,
|
|
15
|
+
},
|
|
16
|
+
prepareSteps: [
|
|
17
|
+
{
|
|
18
|
+
name: "load-knowledge",
|
|
19
|
+
description: "Pre-load governed knowledge via KCP harness",
|
|
20
|
+
tool: "kcp_plan",
|
|
21
|
+
arguments: {
|
|
22
|
+
task: "{{task}}",
|
|
23
|
+
manifest: manifest,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}, null, 2) + "\n",
|
|
28
|
+
commitToGit: true,
|
|
29
|
+
description: "Crush MCP config with PrepareStep for knowledge pre-loading",
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
agent: "crush",
|
|
33
|
+
name: "Crush",
|
|
34
|
+
files: [crushJson],
|
|
35
|
+
instructions: `## Crush Integration
|
|
36
|
+
|
|
37
|
+
**Setup:**
|
|
38
|
+
1. Place \`crush.json\` in your project root
|
|
39
|
+
2. Crush will auto-discover the kcp-harness MCP server
|
|
40
|
+
|
|
41
|
+
The \`prepareSteps\` configuration runs \`kcp_plan\` before each task, pre-loading the governance plan. This ensures:
|
|
42
|
+
- The harness has an approved plan before Crush accesses any files
|
|
43
|
+
- Plan-first mode kicks in for subsequent reads (fast path)
|
|
44
|
+
- Budget is tracked from the first tool call
|
|
45
|
+
|
|
46
|
+
The \`{{task}}\` placeholder is replaced with Crush's current task description.`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Cursor integration — .cursor/mcp.json + .cursor/rules/kcp-governance.mdc
|
|
2
|
+
import { harnessServerEntry, governedPathsBlock, manifestRef } from "./generate.js";
|
|
3
|
+
export function generateCursor(options) {
|
|
4
|
+
const server = harnessServerEntry(options);
|
|
5
|
+
const manifest = manifestRef(options);
|
|
6
|
+
const paths = options.paths ?? ["docs/", "src/"];
|
|
7
|
+
const mcpJson = {
|
|
8
|
+
path: ".cursor/mcp.json",
|
|
9
|
+
content: JSON.stringify({
|
|
10
|
+
mcpServers: {
|
|
11
|
+
"kcp-harness": server,
|
|
12
|
+
},
|
|
13
|
+
}, null, 2) + "\n",
|
|
14
|
+
commitToGit: true,
|
|
15
|
+
description: "Cursor MCP config — adds kcp-harness as governance proxy",
|
|
16
|
+
};
|
|
17
|
+
const rulesFile = {
|
|
18
|
+
path: ".cursor/rules/kcp-governance.mdc",
|
|
19
|
+
content: `---
|
|
20
|
+
globs: [${paths.map((p) => `"${p}**"`).join(", ")}]
|
|
21
|
+
alwaysApply: true
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# KCP Knowledge Governance
|
|
25
|
+
|
|
26
|
+
This project enforces deterministic knowledge governance via the KCP Compliance Harness.
|
|
27
|
+
|
|
28
|
+
## Governed Paths
|
|
29
|
+
|
|
30
|
+
${governedPathsBlock(options)}
|
|
31
|
+
|
|
32
|
+
These paths are governed by \`${manifest}\`. Access is controlled by the kcp-agent planner (13-gate cascade).
|
|
33
|
+
|
|
34
|
+
## Required Workflow
|
|
35
|
+
|
|
36
|
+
1. **Before reading governed files**, call \`kcp_plan\` or \`kcp_load\` via the kcp-harness MCP server
|
|
37
|
+
2. The harness will classify your tool calls and route knowledge-navigation through the planner
|
|
38
|
+
3. Direct file reads of governed paths will be blocked if no approved plan exists
|
|
39
|
+
|
|
40
|
+
## Available Tools (via kcp-harness MCP server)
|
|
41
|
+
|
|
42
|
+
- \`kcp_plan\` — produce a load plan without loading content
|
|
43
|
+
- \`kcp_load\` — plan + load content of eligible units
|
|
44
|
+
- \`kcp_trace\` — see the 13-gate decision trace
|
|
45
|
+
- \`harness_status\` — check governance state
|
|
46
|
+
- \`harness_budget\` — check remaining budget
|
|
47
|
+
- \`harness_temporal_check\` — verify plan temporal validity
|
|
48
|
+
`,
|
|
49
|
+
commitToGit: true,
|
|
50
|
+
description: "Cursor rules — governance instructions scoped to governed paths",
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
agent: "cursor",
|
|
54
|
+
name: "Cursor",
|
|
55
|
+
files: [mcpJson, rulesFile],
|
|
56
|
+
instructions: `## Cursor Integration
|
|
57
|
+
|
|
58
|
+
1. Place \`.cursor/mcp.json\` in your project root — Cursor loads MCP servers from here
|
|
59
|
+
2. Place \`.cursor/rules/kcp-governance.mdc\` — Cursor applies these rules when editing governed paths
|
|
60
|
+
|
|
61
|
+
**Setup:** Copy the generated files to your project root. Restart Cursor to pick up the MCP server.
|
|
62
|
+
|
|
63
|
+
The \`.mdc\` file uses glob-scoped rules so governance instructions only activate when working in governed directories.`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AgentTarget, IntegrationOutput, IntegrationOptions } from "./types.js";
|
|
2
|
+
/** Generate integration files for a specific agent. */
|
|
3
|
+
export declare function generate(agent: AgentTarget, options?: IntegrationOptions): IntegrationOutput;
|
|
4
|
+
/** Generate integration files for all agents. */
|
|
5
|
+
export declare function generateAll(options?: IntegrationOptions): IntegrationOutput[];
|
|
6
|
+
/** List all supported agent targets. */
|
|
7
|
+
export declare function listAgents(): AgentTarget[];
|
|
8
|
+
/** Build the MCP server entry for kcp-harness. */
|
|
9
|
+
export declare function harnessServerEntry(options: IntegrationOptions): Record<string, unknown>;
|
|
10
|
+
/** Build governed paths description for rules files. */
|
|
11
|
+
export declare function governedPathsBlock(options: IntegrationOptions): string;
|
|
12
|
+
/** Build manifest reference for rules files. */
|
|
13
|
+
export declare function manifestRef(options: IntegrationOptions): string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Integration generator — produce agent-specific configs from harness config.
|
|
2
|
+
//
|
|
3
|
+
// Each agent has its own MCP config format, rules file, and setup pattern.
|
|
4
|
+
// The generator takes a harness config and produces the files needed to
|
|
5
|
+
// integrate the harness with a specific agent.
|
|
6
|
+
import { generateClaudeCode } from "./claude-code.js";
|
|
7
|
+
import { generateCursor } from "./cursor.js";
|
|
8
|
+
import { generateWindsurf } from "./windsurf.js";
|
|
9
|
+
import { generateCline } from "./cline.js";
|
|
10
|
+
import { generateContinue } from "./continue.js";
|
|
11
|
+
import { generateCopilot } from "./copilot.js";
|
|
12
|
+
import { generateCrush } from "./crush.js";
|
|
13
|
+
import { generateOpenClaw } from "./openclaw.js";
|
|
14
|
+
const GENERATORS = {
|
|
15
|
+
"claude-code": generateClaudeCode,
|
|
16
|
+
cursor: generateCursor,
|
|
17
|
+
windsurf: generateWindsurf,
|
|
18
|
+
cline: generateCline,
|
|
19
|
+
continue: generateContinue,
|
|
20
|
+
copilot: generateCopilot,
|
|
21
|
+
"copilot-cli": generateCopilot, // Same format, different path
|
|
22
|
+
crush: generateCrush,
|
|
23
|
+
openclaw: generateOpenClaw,
|
|
24
|
+
};
|
|
25
|
+
/** Generate integration files for a specific agent. */
|
|
26
|
+
export function generate(agent, options = {}) {
|
|
27
|
+
const gen = GENERATORS[agent];
|
|
28
|
+
if (!gen)
|
|
29
|
+
throw new Error(`unsupported agent: ${agent}`);
|
|
30
|
+
return gen(options);
|
|
31
|
+
}
|
|
32
|
+
/** Generate integration files for all agents. */
|
|
33
|
+
export function generateAll(options = {}) {
|
|
34
|
+
return Object.keys(GENERATORS).map((agent) => generate(agent, options));
|
|
35
|
+
}
|
|
36
|
+
/** List all supported agent targets. */
|
|
37
|
+
export function listAgents() {
|
|
38
|
+
return Object.keys(GENERATORS);
|
|
39
|
+
}
|
|
40
|
+
// -- Shared helpers for generators ------------------------------------------
|
|
41
|
+
/** Build the MCP server entry for kcp-harness. */
|
|
42
|
+
export function harnessServerEntry(options) {
|
|
43
|
+
return {
|
|
44
|
+
command: options.harnessCommand ?? "npx",
|
|
45
|
+
args: options.harnessArgs ?? [
|
|
46
|
+
"kcp-harness",
|
|
47
|
+
"serve",
|
|
48
|
+
...(options.harnessConfig ? ["--config", options.harnessConfig] : []),
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Build governed paths description for rules files. */
|
|
53
|
+
export function governedPathsBlock(options) {
|
|
54
|
+
const paths = options.paths ?? ["docs/", "src/"];
|
|
55
|
+
return paths.map((p) => ` - \`${p}\``).join("\n");
|
|
56
|
+
}
|
|
57
|
+
/** Build manifest reference for rules files. */
|
|
58
|
+
export function manifestRef(options) {
|
|
59
|
+
return options.manifest ?? "./knowledge.yaml";
|
|
60
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// OpenClaw integration — openclaw.json + plugin hooks documentation.
|
|
2
|
+
//
|
|
3
|
+
// OpenClaw is an open-source multi-channel agent with plugin hooks:
|
|
4
|
+
// - before_prompt_build: inject kcp-loaded knowledge into prompt
|
|
5
|
+
// - before_agent_finalize: post-synthesis claim verification
|
|
6
|
+
//
|
|
7
|
+
// OpenClaw's MCP support uses the standard mcpServers key.
|
|
8
|
+
import { harnessServerEntry, manifestRef } from "./generate.js";
|
|
9
|
+
export function generateOpenClaw(options) {
|
|
10
|
+
const server = harnessServerEntry(options);
|
|
11
|
+
const manifest = manifestRef(options);
|
|
12
|
+
const openclawJson = {
|
|
13
|
+
path: "openclaw.json",
|
|
14
|
+
content: JSON.stringify({
|
|
15
|
+
mcpServers: {
|
|
16
|
+
"kcp-harness": server,
|
|
17
|
+
},
|
|
18
|
+
plugins: {
|
|
19
|
+
"kcp-governance": {
|
|
20
|
+
hooks: {
|
|
21
|
+
before_prompt_build: {
|
|
22
|
+
tool: "kcp_load",
|
|
23
|
+
arguments: {
|
|
24
|
+
task: "{{task}}",
|
|
25
|
+
manifest: manifest,
|
|
26
|
+
},
|
|
27
|
+
description: "Load governed knowledge via KCP harness before prompt assembly",
|
|
28
|
+
},
|
|
29
|
+
before_agent_finalize: {
|
|
30
|
+
tool: "kcp_trace",
|
|
31
|
+
arguments: {
|
|
32
|
+
task: "{{task}}",
|
|
33
|
+
manifest: manifest,
|
|
34
|
+
},
|
|
35
|
+
description: "Run decision trace for audit trail before finalizing agent response",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
}, null, 2) + "\n",
|
|
41
|
+
commitToGit: true,
|
|
42
|
+
description: "OpenClaw MCP config with plugin hooks for knowledge governance",
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
agent: "openclaw",
|
|
46
|
+
name: "OpenClaw",
|
|
47
|
+
files: [openclawJson],
|
|
48
|
+
instructions: `## OpenClaw Integration
|
|
49
|
+
|
|
50
|
+
**Setup:**
|
|
51
|
+
1. Place \`openclaw.json\` in your project root
|
|
52
|
+
2. OpenClaw will auto-discover the kcp-harness MCP server
|
|
53
|
+
|
|
54
|
+
**Plugin Hooks:**
|
|
55
|
+
- \`before_prompt_build\` — calls \`kcp_load\` to inject governed knowledge before the prompt is assembled. This ensures the model sees governed knowledge as part of its context, not as a separate tool call.
|
|
56
|
+
- \`before_agent_finalize\` — calls \`kcp_trace\` after the agent produces its response, creating a decision trace for the audit log.
|
|
57
|
+
|
|
58
|
+
The \`{{task}}\` placeholder is replaced with OpenClaw's current task description.
|
|
59
|
+
|
|
60
|
+
**Available MCP Tools:**
|
|
61
|
+
- \`kcp_plan\` — deterministic load plan
|
|
62
|
+
- \`kcp_load\` — plan + load content
|
|
63
|
+
- \`kcp_trace\` — 13-gate decision trace
|
|
64
|
+
- \`harness_budget\` — session spend tracking
|
|
65
|
+
- \`harness_temporal_check\` — plan drift detection`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Supported agent targets for integration generation. */
|
|
2
|
+
export type AgentTarget = "claude-code" | "cursor" | "windsurf" | "cline" | "continue" | "copilot" | "copilot-cli" | "crush" | "openclaw";
|
|
3
|
+
/** Integration output — generated files for a specific agent. */
|
|
4
|
+
export interface IntegrationOutput {
|
|
5
|
+
/** Which agent this integration is for. */
|
|
6
|
+
agent: AgentTarget;
|
|
7
|
+
/** Display name. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Files to write (path → content). */
|
|
10
|
+
files: IntegrationFile[];
|
|
11
|
+
/** Human-readable setup instructions (markdown). */
|
|
12
|
+
instructions: string;
|
|
13
|
+
}
|
|
14
|
+
/** A file to write as part of the integration. */
|
|
15
|
+
export interface IntegrationFile {
|
|
16
|
+
/** Relative path from project root. */
|
|
17
|
+
path: string;
|
|
18
|
+
/** File content. */
|
|
19
|
+
content: string;
|
|
20
|
+
/** Whether this file should be committed to git. */
|
|
21
|
+
commitToGit: boolean;
|
|
22
|
+
/** Description of what this file does. */
|
|
23
|
+
description: string;
|
|
24
|
+
}
|
|
25
|
+
/** Options for generating an integration. */
|
|
26
|
+
export interface IntegrationOptions {
|
|
27
|
+
/** Path to the harness YAML config. */
|
|
28
|
+
harnessConfig?: string;
|
|
29
|
+
/** Governed knowledge.yaml path. */
|
|
30
|
+
manifest?: string;
|
|
31
|
+
/** Governed path prefixes. */
|
|
32
|
+
paths?: string[];
|
|
33
|
+
/** Project root (for relative path resolution). */
|
|
34
|
+
projectRoot?: string;
|
|
35
|
+
/** Custom harness command (default: npx kcp-harness serve). */
|
|
36
|
+
harnessCommand?: string;
|
|
37
|
+
/** Custom harness args. */
|
|
38
|
+
harnessArgs?: string[];
|
|
39
|
+
}
|
|
40
|
+
/** Agent metadata. */
|
|
41
|
+
export interface AgentInfo {
|
|
42
|
+
target: AgentTarget;
|
|
43
|
+
name: string;
|
|
44
|
+
mcpSupport: boolean;
|
|
45
|
+
configFile: string;
|
|
46
|
+
rulesFile?: string;
|
|
47
|
+
topLevelKey: string;
|
|
48
|
+
notes?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Registry of all supported agents. */
|
|
51
|
+
export declare const AGENTS: Record<AgentTarget, AgentInfo>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// Integration types — shared across all agent integration packages.
|
|
2
|
+
/** Registry of all supported agents. */
|
|
3
|
+
export const AGENTS = {
|
|
4
|
+
"claude-code": {
|
|
5
|
+
target: "claude-code",
|
|
6
|
+
name: "Claude Code",
|
|
7
|
+
mcpSupport: true,
|
|
8
|
+
configFile: ".mcp.json",
|
|
9
|
+
rulesFile: "CLAUDE.md",
|
|
10
|
+
topLevelKey: "mcpServers",
|
|
11
|
+
notes: "First-class MCP + hooks (PreToolUse)",
|
|
12
|
+
},
|
|
13
|
+
cursor: {
|
|
14
|
+
target: "cursor",
|
|
15
|
+
name: "Cursor",
|
|
16
|
+
mcpSupport: true,
|
|
17
|
+
configFile: ".cursor/mcp.json",
|
|
18
|
+
rulesFile: ".cursor/rules/kcp-governance.mdc",
|
|
19
|
+
topLevelKey: "mcpServers",
|
|
20
|
+
},
|
|
21
|
+
windsurf: {
|
|
22
|
+
target: "windsurf",
|
|
23
|
+
name: "Windsurf",
|
|
24
|
+
mcpSupport: true,
|
|
25
|
+
configFile: "~/.codeium/windsurf/mcp_config.json",
|
|
26
|
+
rulesFile: ".windsurfrules",
|
|
27
|
+
topLevelKey: "mcpServers",
|
|
28
|
+
notes: "Global config only (no per-project MCP file)",
|
|
29
|
+
},
|
|
30
|
+
cline: {
|
|
31
|
+
target: "cline",
|
|
32
|
+
name: "Cline",
|
|
33
|
+
mcpSupport: true,
|
|
34
|
+
configFile: "cline_mcp_settings.json",
|
|
35
|
+
rulesFile: ".clinerules",
|
|
36
|
+
topLevelKey: "mcpServers",
|
|
37
|
+
notes: "Config managed via VS Code extension UI",
|
|
38
|
+
},
|
|
39
|
+
continue: {
|
|
40
|
+
target: "continue",
|
|
41
|
+
name: "Continue",
|
|
42
|
+
mcpSupport: true,
|
|
43
|
+
configFile: ".continue/mcpServers/kcp-harness.yaml",
|
|
44
|
+
topLevelKey: "mcpServers",
|
|
45
|
+
},
|
|
46
|
+
copilot: {
|
|
47
|
+
target: "copilot",
|
|
48
|
+
name: "GitHub Copilot",
|
|
49
|
+
mcpSupport: true,
|
|
50
|
+
configFile: ".vscode/mcp.json",
|
|
51
|
+
rulesFile: ".github/copilot-instructions.md",
|
|
52
|
+
topLevelKey: "servers",
|
|
53
|
+
notes: "Uses 'servers' not 'mcpServers'. Agent mode only.",
|
|
54
|
+
},
|
|
55
|
+
"copilot-cli": {
|
|
56
|
+
target: "copilot-cli",
|
|
57
|
+
name: "GitHub Copilot CLI",
|
|
58
|
+
mcpSupport: true,
|
|
59
|
+
configFile: "~/.copilot/mcp-config.json",
|
|
60
|
+
topLevelKey: "mcpServers",
|
|
61
|
+
},
|
|
62
|
+
crush: {
|
|
63
|
+
target: "crush",
|
|
64
|
+
name: "Crush",
|
|
65
|
+
mcpSupport: true,
|
|
66
|
+
configFile: "crush.json",
|
|
67
|
+
topLevelKey: "mcpServers",
|
|
68
|
+
notes: "PrepareStep pattern for knowledge pre-loading",
|
|
69
|
+
},
|
|
70
|
+
openclaw: {
|
|
71
|
+
target: "openclaw",
|
|
72
|
+
name: "OpenClaw",
|
|
73
|
+
mcpSupport: true,
|
|
74
|
+
configFile: "openclaw.json",
|
|
75
|
+
topLevelKey: "mcpServers",
|
|
76
|
+
notes: "Plugin hooks: before_prompt_build, before_agent_finalize",
|
|
77
|
+
},
|
|
78
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Windsurf (Codeium) integration — global MCP config + .windsurfrules
|
|
2
|
+
import { harnessServerEntry, governedPathsBlock, manifestRef } from "./generate.js";
|
|
3
|
+
export function generateWindsurf(options) {
|
|
4
|
+
const server = harnessServerEntry(options);
|
|
5
|
+
const manifest = manifestRef(options);
|
|
6
|
+
// Windsurf uses a GLOBAL config — we generate the snippet to add
|
|
7
|
+
const mcpSnippet = {
|
|
8
|
+
path: "windsurf-mcp-snippet.json",
|
|
9
|
+
content: JSON.stringify({
|
|
10
|
+
"kcp-harness": server,
|
|
11
|
+
}, null, 2) + "\n",
|
|
12
|
+
commitToGit: false,
|
|
13
|
+
description: "MCP snippet to add to ~/.codeium/windsurf/mcp_config.json (global config)",
|
|
14
|
+
};
|
|
15
|
+
const rulesFile = {
|
|
16
|
+
path: ".windsurfrules",
|
|
17
|
+
content: `# KCP Knowledge Governance
|
|
18
|
+
|
|
19
|
+
This project uses the KCP Compliance Harness for deterministic knowledge access control.
|
|
20
|
+
|
|
21
|
+
## Governed Paths
|
|
22
|
+
|
|
23
|
+
${governedPathsBlock(options)}
|
|
24
|
+
|
|
25
|
+
These paths are governed by \`${manifest}\`.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
1. Always call \`kcp_plan\` or \`kcp_load\` (via the kcp-harness MCP server) before reading governed files
|
|
30
|
+
2. The harness intercepts tool calls and routes knowledge access through the kcp-agent planner
|
|
31
|
+
3. Budget and temporal governance are enforced automatically
|
|
32
|
+
4. Use \`harness_status\` to check the current governance state
|
|
33
|
+
|
|
34
|
+
## Available MCP Tools
|
|
35
|
+
|
|
36
|
+
- \`kcp_plan\` — deterministic load plan (no content)
|
|
37
|
+
- \`kcp_load\` — plan + load eligible unit content
|
|
38
|
+
- \`kcp_trace\` — 13-gate decision trace
|
|
39
|
+
- \`harness_budget\` — session spend tracking
|
|
40
|
+
- \`harness_temporal_check\` — plan drift detection
|
|
41
|
+
`,
|
|
42
|
+
commitToGit: true,
|
|
43
|
+
description: "Windsurf rules — governance instructions for Cascade",
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
agent: "windsurf",
|
|
47
|
+
name: "Windsurf",
|
|
48
|
+
files: [mcpSnippet, rulesFile],
|
|
49
|
+
instructions: `## Windsurf Integration
|
|
50
|
+
|
|
51
|
+
Windsurf uses a **global** MCP config (not per-project).
|
|
52
|
+
|
|
53
|
+
**Setup:**
|
|
54
|
+
1. Add the kcp-harness entry to \`~/.codeium/windsurf/mcp_config.json\`:
|
|
55
|
+
\`\`\`json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"kcp-harness": { ... } // ← merge from windsurf-mcp-snippet.json
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
\`\`\`
|
|
62
|
+
2. Place \`.windsurfrules\` in your project root
|
|
63
|
+
3. Restart Windsurf
|
|
64
|
+
|
|
65
|
+
The \`.windsurfrules\` file instructs Cascade to use kcp_load for governed knowledge access.`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// KCP bridge — call kcp-agent's planner functions from the harness.
|
|
2
|
+
//
|
|
3
|
+
// Instead of importing kcp-agent's internal MCP handler (which isn't part
|
|
4
|
+
// of the public API), we use the exported planner functions directly.
|
|
5
|
+
// This gives us the same results with type safety and a stable API surface.
|
|
6
|
+
import { planTree, plans, loadPlannedUnits, loadManifest, trace as traceDecision, validateLocation, dedupeLoaded, } from "kcp-agent";
|
|
7
|
+
/** Accept a JSON array or a comma-separated string — MCP callers send both. */
|
|
8
|
+
function toList(v) {
|
|
9
|
+
if (Array.isArray(v))
|
|
10
|
+
return v.map(String);
|
|
11
|
+
if (typeof v === "string")
|
|
12
|
+
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
/** Map MCP-style arguments to kcp-agent's FollowOptions. */
|
|
16
|
+
function toFollowOptions(args) {
|
|
17
|
+
const methods = toList(args["methods"]);
|
|
18
|
+
const credentials = toList(args["credentials"]);
|
|
19
|
+
const planOptions = {
|
|
20
|
+
env: args["env"] === undefined ? undefined : String(args["env"]),
|
|
21
|
+
asOf: args["as_of"] === undefined ? undefined : String(args["as_of"]),
|
|
22
|
+
maxUnits: args["max_units"] === undefined ? undefined : Number(args["max_units"]),
|
|
23
|
+
strict: args["strict"] === true,
|
|
24
|
+
budget: args["budget"] === undefined
|
|
25
|
+
? undefined
|
|
26
|
+
: { amount: Number(args["budget"]), currency: args["currency"] === undefined ? undefined : String(args["currency"]) },
|
|
27
|
+
contextBudget: args["context_budget"] === undefined ? undefined : Number(args["context_budget"]),
|
|
28
|
+
capabilities: {
|
|
29
|
+
...(args["role"] === undefined ? {} : { role: String(args["role"]) }),
|
|
30
|
+
...(methods ? { paymentMethods: methods } : {}),
|
|
31
|
+
...(credentials ? { credentials } : {}),
|
|
32
|
+
...(args["attest"] === undefined ? {} : { attestationProvider: String(args["attest"]) }),
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
return {
|
|
36
|
+
planOptions,
|
|
37
|
+
maxDepth: args["follow"] === true ? (args["max_depth"] === undefined ? 1 : Number(args["max_depth"])) : 0,
|
|
38
|
+
maxNodes: args["max_nodes"] === undefined ? undefined : Number(args["max_nodes"]),
|
|
39
|
+
fetchGuard: { allowPrivate: args["allow_private_hosts"] === true },
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Call a KCP tool and return the result as a JSON string. */
|
|
43
|
+
export async function callKcpTool(name, args) {
|
|
44
|
+
switch (name) {
|
|
45
|
+
case "kcp_plan": {
|
|
46
|
+
const tree = await planTree(String(args["manifest"] ?? ""), String(args["task"] ?? ""), toFollowOptions(args));
|
|
47
|
+
if (tree.error)
|
|
48
|
+
throw new Error(`${tree.location}: ${tree.error}`);
|
|
49
|
+
return JSON.stringify(tree, null, 2);
|
|
50
|
+
}
|
|
51
|
+
case "kcp_load": {
|
|
52
|
+
const follow = toFollowOptions(args);
|
|
53
|
+
const tree = await planTree(String(args["manifest"] ?? ""), String(args["task"] ?? ""), follow);
|
|
54
|
+
if (tree.error)
|
|
55
|
+
throw new Error(`${tree.location}: ${tree.error}`);
|
|
56
|
+
const loaded = [];
|
|
57
|
+
const unavailable = [];
|
|
58
|
+
for (const p of plans(tree)) {
|
|
59
|
+
const r = await loadPlannedUnits(p, follow.fetchGuard);
|
|
60
|
+
loaded.push(...r.loaded);
|
|
61
|
+
unavailable.push(...r.unavailable);
|
|
62
|
+
}
|
|
63
|
+
const { units, deduped, bytesSaved } = dedupeLoaded(loaded, args["known"]);
|
|
64
|
+
return JSON.stringify({ plan: tree, units, unavailable, deduped, bytesSaved }, null, 2);
|
|
65
|
+
}
|
|
66
|
+
case "kcp_trace": {
|
|
67
|
+
const follow = toFollowOptions(args);
|
|
68
|
+
const manifest = await loadManifest(String(args["manifest"] ?? ""), follow.fetchGuard);
|
|
69
|
+
const t = traceDecision(manifest, String(args["task"] ?? ""), follow.planOptions);
|
|
70
|
+
return JSON.stringify(t, null, 2);
|
|
71
|
+
}
|
|
72
|
+
case "kcp_validate": {
|
|
73
|
+
const guard = { allowPrivate: args["allow_private_hosts"] === true };
|
|
74
|
+
const report = await validateLocation(String(args["manifest"] ?? ""), guard);
|
|
75
|
+
return JSON.stringify(report, null, 2);
|
|
76
|
+
}
|
|
77
|
+
case "kcp_replay": {
|
|
78
|
+
// Replay requires importing the replay function — use dynamic import
|
|
79
|
+
// to keep the bridge lightweight for non-replay use cases.
|
|
80
|
+
throw new Error("kcp_replay not yet bridged — call kcp-agent directly");
|
|
81
|
+
}
|
|
82
|
+
default:
|
|
83
|
+
throw new Error(`unknown KCP tool: ${name}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { HarnessConfig } from "./config.js";
|
|
2
|
+
import { type AuditWriter } from "./audit.js";
|
|
3
|
+
import { type SessionState } from "./session.js";
|
|
4
|
+
interface JsonRpcRequest {
|
|
5
|
+
jsonrpc?: string;
|
|
6
|
+
id?: number | string | null;
|
|
7
|
+
method?: string;
|
|
8
|
+
params?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface ProxyOptions {
|
|
11
|
+
config: HarnessConfig;
|
|
12
|
+
audit?: AuditWriter;
|
|
13
|
+
}
|
|
14
|
+
export declare class HarnessProxy {
|
|
15
|
+
private readonly config;
|
|
16
|
+
private readonly downstream;
|
|
17
|
+
private readonly audit;
|
|
18
|
+
private readonly session;
|
|
19
|
+
constructor(options: ProxyOptions);
|
|
20
|
+
/** Start the proxy: spawn downstream servers and begin serving. */
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/** Shut down the proxy and all downstream connections. */
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
/** Handle one JSON-RPC message from the agent. */
|
|
25
|
+
handleMessage(msg: JsonRpcRequest): Promise<object | null>;
|
|
26
|
+
/** List all available tools (downstream + harness + KCP). */
|
|
27
|
+
private listTools;
|
|
28
|
+
/** Handle a tool call through the governance pipeline. */
|
|
29
|
+
private handleToolCall;
|
|
30
|
+
/** Handle harness-internal tools. */
|
|
31
|
+
private handleHarnessTool;
|
|
32
|
+
/** Expose session for testing. */
|
|
33
|
+
getSession(): SessionState;
|
|
34
|
+
}
|
|
35
|
+
/** Serve the harness proxy over stdio until stdin closes. */
|
|
36
|
+
export declare function serveProxy(config: HarnessConfig): Promise<void>;
|
|
37
|
+
export {};
|