@decionis/mcp 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 +13 -0
- package/README.md +233 -0
- package/dist/AgentHookCli.d.ts +2 -0
- package/dist/AgentHookCli.js +17 -0
- package/dist/AgentHookCli.js.map +1 -0
- package/dist/ManagedAgentHookCli.d.ts +2 -0
- package/dist/ManagedAgentHookCli.js +53678 -0
- package/dist/agent/AgentIndex.d.ts +226 -0
- package/dist/agent/AgentIndex.js +36 -0
- package/dist/agent/AgentIndex.js.map +1 -0
- package/dist/chunk-QSCP7MRQ.js +16944 -0
- package/dist/chunk-QSCP7MRQ.js.map +1 -0
- package/dist/chunk-UN67W5FH.js +479 -0
- package/dist/chunk-UN67W5FH.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +310 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
- package/templates/ClaudeSettings.json +17 -0
- package/templates/CodexHooks.json +18 -0
- package/templates/CopilotHooks.json +12 -0
- package/templates/managed/AgentGateConfig.example.json +6 -0
- package/templates/managed/AgentPolicyBundle.json +417 -0
- package/templates/managed/ClaudeManagedSettings.Windows.json +18 -0
- package/templates/managed/ClaudeManagedSettings.json +18 -0
- package/templates/managed/CodexRequirements.toml +18 -0
- package/templates/managed/CopilotPolicyHooks.Windows.json +12 -0
- package/templates/managed/CopilotPolicyHooks.json +12 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
LocalDecionisGateway,
|
|
4
|
+
PolicyFileRepository,
|
|
5
|
+
normalizeVerdict,
|
|
6
|
+
sha256Hex
|
|
7
|
+
} from "./chunk-QSCP7MRQ.js";
|
|
8
|
+
|
|
9
|
+
// src/Server.ts
|
|
10
|
+
import { createInterface } from "readline";
|
|
11
|
+
var SUPPORTED_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
12
|
+
var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
|
|
13
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14
|
+
function rpcResult(id, result) {
|
|
15
|
+
return { jsonrpc: "2.0", id, result };
|
|
16
|
+
}
|
|
17
|
+
function rpcError(id, code, message) {
|
|
18
|
+
return { jsonrpc: "2.0", id, error: { code, message } };
|
|
19
|
+
}
|
|
20
|
+
var McpMessageHandler = class {
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.options = options;
|
|
23
|
+
this.toolsByName = new Map(options.tools.map((tool) => [tool.name, tool]));
|
|
24
|
+
}
|
|
25
|
+
toolsByName;
|
|
26
|
+
async handle(message) {
|
|
27
|
+
if (!isPlainObject(message) || message.jsonrpc !== "2.0" || typeof message.method !== "string") {
|
|
28
|
+
const id2 = isPlainObject(message) && "id" in message ? message.id : null;
|
|
29
|
+
return rpcError(id2, -32600, "Invalid JSON-RPC 2.0 request");
|
|
30
|
+
}
|
|
31
|
+
const { method, id } = message;
|
|
32
|
+
const isNotification = !("id" in message);
|
|
33
|
+
const params = isPlainObject(message.params) ? message.params : {};
|
|
34
|
+
if (isNotification) return null;
|
|
35
|
+
switch (method) {
|
|
36
|
+
case "initialize": {
|
|
37
|
+
const requested = typeof params.protocolVersion === "string" ? params.protocolVersion : "";
|
|
38
|
+
const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : DEFAULT_PROTOCOL_VERSION;
|
|
39
|
+
return rpcResult(id, {
|
|
40
|
+
protocolVersion,
|
|
41
|
+
capabilities: { tools: { listChanged: false } },
|
|
42
|
+
serverInfo: this.options.serverInfo
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
case "ping":
|
|
46
|
+
return rpcResult(id, {});
|
|
47
|
+
case "tools/list":
|
|
48
|
+
return rpcResult(id, {
|
|
49
|
+
tools: this.options.tools.map(({ name, description, inputSchema }) => ({
|
|
50
|
+
name,
|
|
51
|
+
description,
|
|
52
|
+
inputSchema
|
|
53
|
+
}))
|
|
54
|
+
});
|
|
55
|
+
case "tools/call": {
|
|
56
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
57
|
+
const tool = this.toolsByName.get(name);
|
|
58
|
+
if (!tool) return rpcError(id, -32602, `Unknown tool: ${name || "(missing name)"}`);
|
|
59
|
+
const args = isPlainObject(params.arguments) ? params.arguments : {};
|
|
60
|
+
try {
|
|
61
|
+
const result = await tool.handler(args);
|
|
62
|
+
return rpcResult(id, { content: result.content, isError: result.isError ?? false });
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return rpcResult(id, {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: `Tool ${name} failed: ${err instanceof Error ? err.message : String(err)}`
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
isError: true
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
return rpcError(id, -32601, `Method not found: ${method}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var McpStdioServer = class {
|
|
81
|
+
static run(handler2, streams = {}) {
|
|
82
|
+
const input = streams.input ?? process.stdin;
|
|
83
|
+
const output = streams.output ?? process.stdout;
|
|
84
|
+
const rl = createInterface({ input, crlfDelay: Infinity });
|
|
85
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
rl.on("line", (line) => {
|
|
88
|
+
const trimmed = line.trim();
|
|
89
|
+
if (!trimmed) return;
|
|
90
|
+
const work = (async () => {
|
|
91
|
+
let message;
|
|
92
|
+
try {
|
|
93
|
+
message = JSON.parse(trimmed);
|
|
94
|
+
} catch {
|
|
95
|
+
output.write(`${JSON.stringify(rpcError(null, -32700, "Parse error"))}
|
|
96
|
+
`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const response = await handler2(message);
|
|
101
|
+
if (response !== null) output.write(`${JSON.stringify(response)}
|
|
102
|
+
`);
|
|
103
|
+
} catch (err) {
|
|
104
|
+
process.stderr.write(`decionis-mcp: handler error: ${String(err)}
|
|
105
|
+
`);
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
inFlight.add(work);
|
|
109
|
+
void work.finally(() => inFlight.delete(work));
|
|
110
|
+
});
|
|
111
|
+
rl.on("close", () => {
|
|
112
|
+
void Promise.allSettled([...inFlight]).then(() => resolve());
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
function createMcpHandler(options) {
|
|
118
|
+
const handler2 = new McpMessageHandler(options);
|
|
119
|
+
return async function handleMessage(message) {
|
|
120
|
+
return handler2.handle(message);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function runStdioServer(handler2, streams = {}) {
|
|
124
|
+
return McpStdioServer.run(handler2, streams);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/Tools.ts
|
|
128
|
+
var text = (value) => [
|
|
129
|
+
{ type: "text", text: typeof value === "string" ? value : JSON.stringify(value, null, 2) }
|
|
130
|
+
];
|
|
131
|
+
var isPlainObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
132
|
+
var VERDICT_HELP = `# Decionis verdicts and rule grammar
|
|
133
|
+
|
|
134
|
+
**Verdicts** (a rule's \`action\`): \`allow\` (execute), \`block\` (never execute),
|
|
135
|
+
\`restrain\` (hold for human review), \`escalate\` (require an authorized approver).
|
|
136
|
+
The protocol reports outcomes as APPROVE / REJECT / REVIEW / ESCALATE; this server
|
|
137
|
+
also returns the normalized verdict (allow / block / review / escalate). When no
|
|
138
|
+
rule matches, the platform holds the decision for review (outcome REVIEW).
|
|
139
|
+
|
|
140
|
+
**Rules block** (in DECIONIS_POLICY.md):
|
|
141
|
+
\`\`\`decionis
|
|
142
|
+
{ "version": 1, "rules": [
|
|
143
|
+
{ "name": "Block deploys during a change freeze",
|
|
144
|
+
"priority": 100, "domain": "*",
|
|
145
|
+
"all": [{ "field": "context.change_freeze", "op": "eq", "value": true }],
|
|
146
|
+
"action": "block" } ] }
|
|
147
|
+
\`\`\`
|
|
148
|
+
|
|
149
|
+
- Each rule has exactly one of \`all\` (AND) / \`any\` (OR).
|
|
150
|
+
- Operators: eq, ne/neq, gt, gte, lt, lte, in (values array), not_in (values array),
|
|
151
|
+
exists, contains, matches (case-insensitive regex). Equality coerces numbers,
|
|
152
|
+
booleans, and lowercased text; arrays match on any element.
|
|
153
|
+
- Fields resolve against the decision payload: \`context.<key>\` reads payload keys,
|
|
154
|
+
\`decision_type\` derives from the payload's \`action\` label, then the workflow key.
|
|
155
|
+
- Give every rule an explicit \`priority\` (higher evaluates first) and keep
|
|
156
|
+
\`"domain": "*"\` so it applies to every decision the repo gates.
|
|
157
|
+
|
|
158
|
+
**Before committing or running anything risky**, call \`decionis_evaluate\` with the
|
|
159
|
+
action you intend to take (e.g. {"action": "production-deploy", "agent_generated": true})
|
|
160
|
+
and abide by the verdict: allow \u2192 proceed; block \u2192 do not proceed; review/escalate \u2192
|
|
161
|
+
stop and ask a human.`;
|
|
162
|
+
var DecionisTools = class {
|
|
163
|
+
constructor(gateway2, policyFiles = new PolicyFileRepository()) {
|
|
164
|
+
this.gateway = gateway2;
|
|
165
|
+
this.policyFiles = policyFiles;
|
|
166
|
+
}
|
|
167
|
+
build() {
|
|
168
|
+
const gateway2 = this.gateway;
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
name: "decionis_read_policy",
|
|
172
|
+
description: "Read and compile the repo's DECIONIS_POLICY.md governance policy: path, sha256, and the enforceable rules (name, verdict, priority, domain) or compile errors. Use this to learn what this repository allows, blocks, restrains, or escalates.",
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: {
|
|
176
|
+
path: {
|
|
177
|
+
type: "string",
|
|
178
|
+
description: "Policy file path (default: $DECIONIS_POLICY_PATH or ./DECIONIS_POLICY.md)"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
additionalProperties: false
|
|
182
|
+
},
|
|
183
|
+
handler: async (args) => {
|
|
184
|
+
const file = await this.policyFiles.read(args.path);
|
|
185
|
+
if (!file.ok) return { content: text(file.message), isError: true };
|
|
186
|
+
const compiled = gateway2.compile(file.content);
|
|
187
|
+
return {
|
|
188
|
+
content: text({
|
|
189
|
+
path: file.path,
|
|
190
|
+
sha256: sha256Hex(file.content),
|
|
191
|
+
bytes: Buffer.byteLength(file.content, "utf8"),
|
|
192
|
+
rules: compiled === null ? "no ```decionis rules block \u2014 the file is prose-only documentation" : compiled.errors.length > 0 ? { compile_errors: compiled.errors } : compiled.rules.map((rule) => ({
|
|
193
|
+
name: rule.name,
|
|
194
|
+
verdict: rule.then.action,
|
|
195
|
+
priority: rule.priority,
|
|
196
|
+
domain: rule.decision_domain,
|
|
197
|
+
when: rule.when
|
|
198
|
+
}))
|
|
199
|
+
})
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: "decionis_evaluate",
|
|
205
|
+
description: "Evaluate a candidate action against the repo's DECIONIS_POLICY.md through the real Decionis protocol evaluator, entirely locally (no network, no credentials, nothing recorded). Call this BEFORE committing, deploying, migrating, or any risky action, and abide by the verdict: allow \u2192 proceed; block \u2192 do not proceed; review/escalate \u2192 stop and involve a human.",
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: "object",
|
|
208
|
+
required: ["payload"],
|
|
209
|
+
properties: {
|
|
210
|
+
payload: {
|
|
211
|
+
type: "object",
|
|
212
|
+
description: 'The candidate action, e.g. {"action": "production-deploy", "change_freeze": true, "agent_generated": true}'
|
|
213
|
+
},
|
|
214
|
+
workflow_key: {
|
|
215
|
+
type: "string",
|
|
216
|
+
description: "Optional workflow key for the gated surface."
|
|
217
|
+
},
|
|
218
|
+
mode: { type: "string", enum: ["shadow", "enforce"], description: "Default: shadow." },
|
|
219
|
+
path: { type: "string", description: "Policy file path override." }
|
|
220
|
+
},
|
|
221
|
+
additionalProperties: false
|
|
222
|
+
},
|
|
223
|
+
handler: async (args) => {
|
|
224
|
+
if (!isPlainObject2(args.payload)) {
|
|
225
|
+
return {
|
|
226
|
+
content: text("`payload` must be a JSON object describing the action."),
|
|
227
|
+
isError: true
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
const file = await this.policyFiles.read(args.path);
|
|
231
|
+
if (!file.ok) return { content: text(file.message), isError: true };
|
|
232
|
+
const workflowKey = typeof args.workflow_key === "string" ? args.workflow_key : null;
|
|
233
|
+
const published = await gateway2.publishPolicy(file.content, { workflowKey });
|
|
234
|
+
if (!published.ok) {
|
|
235
|
+
return {
|
|
236
|
+
content: text({
|
|
237
|
+
error: published.reason,
|
|
238
|
+
details: published.errors,
|
|
239
|
+
hint: published.reason === "no_rules_block" ? "Add a ```decionis rules block to make the policy enforceable \u2014 see decionis_verdict_help." : "Fix the rules block so it compiles; the platform enforces all-or-nothing."
|
|
240
|
+
}),
|
|
241
|
+
isError: true
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const evaluated = await gateway2.evaluate({
|
|
245
|
+
payload: args.payload,
|
|
246
|
+
workflowKey,
|
|
247
|
+
mode: args.mode === "enforce" ? "enforce" : "shadow"
|
|
248
|
+
});
|
|
249
|
+
if (evaluated.status !== 200) {
|
|
250
|
+
return {
|
|
251
|
+
content: text({
|
|
252
|
+
error: `protocol evaluation failed (HTTP ${evaluated.status})`,
|
|
253
|
+
body: evaluated.body
|
|
254
|
+
}),
|
|
255
|
+
isError: true
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
const body = evaluated.body;
|
|
259
|
+
const policyEvaluation = isPlainObject2(body.policy_evaluation) ? body.policy_evaluation : {};
|
|
260
|
+
const evaluatedRuleCount = typeof policyEvaluation.evaluated_rule_count === "number" ? policyEvaluation.evaluated_rule_count : null;
|
|
261
|
+
return {
|
|
262
|
+
content: text({
|
|
263
|
+
verdict: normalizeVerdict(body.outcome),
|
|
264
|
+
outcome: body.outcome,
|
|
265
|
+
resolution: policyEvaluation.resolution ?? null,
|
|
266
|
+
selected_rule: policyEvaluation.selected_rule_name ?? null,
|
|
267
|
+
matched_rule_count: policyEvaluation.matched_rule_count ?? null,
|
|
268
|
+
evaluated_rule_count: evaluatedRuleCount,
|
|
269
|
+
decision_domain: policyEvaluation.decision_domain ?? body.decision_domain ?? null,
|
|
270
|
+
policy_version: published.version,
|
|
271
|
+
policy_sha256: published.sha256,
|
|
272
|
+
confidence: body.confidence ?? null,
|
|
273
|
+
note: "Local sandbox evaluation \u2014 nothing was recorded and no signed dossier was minted. CI runs through decionis/govern produce the signed, verifiable record.",
|
|
274
|
+
...published.ruleCount > 0 && evaluatedRuleCount === 0 ? {
|
|
275
|
+
hint: `All ${published.ruleCount} compiled rule(s) were filtered out by the decision-domain match before evaluation. Add "domain": "*" to each rule so it applies to every decision this repo gates.`
|
|
276
|
+
} : {}
|
|
277
|
+
})
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
name: "decionis_verdict_help",
|
|
283
|
+
description: "Reference for Decionis verdicts (allow/block/restrain/escalate), the rules-block grammar and operators, and how an agent should behave on each verdict.",
|
|
284
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
285
|
+
handler: async () => ({ content: text(VERDICT_HELP) })
|
|
286
|
+
}
|
|
287
|
+
];
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
function createDecionisTools(gateway2) {
|
|
291
|
+
return new DecionisTools(gateway2).build();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// src/index.ts
|
|
295
|
+
var gateway = new LocalDecionisGateway();
|
|
296
|
+
var handler = createMcpHandler({
|
|
297
|
+
serverInfo: { name: "decionis-mcp", version: "0.1.0" },
|
|
298
|
+
tools: createDecionisTools(gateway)
|
|
299
|
+
});
|
|
300
|
+
runStdioServer(handler).then(async () => {
|
|
301
|
+
await gateway.close();
|
|
302
|
+
process.exit(0);
|
|
303
|
+
}).catch(async (err) => {
|
|
304
|
+
process.stderr.write(`decionis-mcp: fatal: ${String(err)}
|
|
305
|
+
`);
|
|
306
|
+
await gateway.close().catch(() => {
|
|
307
|
+
});
|
|
308
|
+
process.exit(1);
|
|
309
|
+
});
|
|
310
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Server.ts","../src/Tools.ts","../src/index.ts"],"sourcesContent":["/**\n * Minimal MCP (Model Context Protocol) server core: JSON-RPC 2.0 over\n * newline-delimited stdio. Hand-rolled (no SDK dependency), matching the\n * protocol service's hand-rolled remote MCP surface. The message handler is\n * transport-agnostic and unit-testable; the stdio loop is a thin shell.\n */\n\nimport { createInterface } from \"node:readline\";\n\nexport const SUPPORTED_PROTOCOL_VERSIONS = [\"2025-06-18\", \"2025-03-26\", \"2024-11-05\"];\nconst DEFAULT_PROTOCOL_VERSION = \"2025-06-18\";\n\nexport interface ToolContent {\n type: \"text\";\n text: string;\n}\n\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n handler: (\n args: Record<string, unknown>,\n ) => Promise<{ content: ToolContent[]; isError?: boolean }>;\n}\n\nexport interface ServerInfo {\n name: string;\n version: string;\n}\n\ntype JsonRpcResponse = Record<string, unknown>;\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\nfunction rpcResult(id: unknown, result: unknown): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, result };\n}\n\nfunction rpcError(id: unknown, code: number, message: string): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, error: { code, message } };\n}\n\n/**\n * The MCP message handler. Returns `null` for notifications (no reply) and\n * a JSON-RPC response object otherwise.\n */\nexport class McpMessageHandler {\n private readonly toolsByName: Map<string, ToolDefinition>;\n\n constructor(private readonly options: { serverInfo: ServerInfo; tools: ToolDefinition[] }) {\n this.toolsByName = new Map(options.tools.map((tool) => [tool.name, tool]));\n }\n\n async handle(message: unknown): Promise<JsonRpcResponse | null> {\n if (\n !isPlainObject(message) ||\n message.jsonrpc !== \"2.0\" ||\n typeof message.method !== \"string\"\n ) {\n const id = isPlainObject(message) && \"id\" in message ? message.id : null;\n return rpcError(id, -32600, \"Invalid JSON-RPC 2.0 request\");\n }\n const { method, id } = message;\n const isNotification = !(\"id\" in message);\n const params = isPlainObject(message.params) ? message.params : {};\n\n if (isNotification) return null; // notifications/initialized, cancellations, …\n\n switch (method) {\n case \"initialize\": {\n const requested = typeof params.protocolVersion === \"string\" ? params.protocolVersion : \"\";\n const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.includes(requested)\n ? requested\n : DEFAULT_PROTOCOL_VERSION;\n return rpcResult(id, {\n protocolVersion,\n capabilities: { tools: { listChanged: false } },\n serverInfo: this.options.serverInfo,\n });\n }\n case \"ping\":\n return rpcResult(id, {});\n case \"tools/list\":\n return rpcResult(id, {\n tools: this.options.tools.map(({ name, description, inputSchema }) => ({\n name,\n description,\n inputSchema,\n })),\n });\n case \"tools/call\": {\n const name = typeof params.name === \"string\" ? params.name : \"\";\n const tool = this.toolsByName.get(name);\n if (!tool) return rpcError(id, -32602, `Unknown tool: ${name || \"(missing name)\"}`);\n const args = isPlainObject(params.arguments) ? params.arguments : {};\n try {\n const result = await tool.handler(args);\n return rpcResult(id, { content: result.content, isError: result.isError ?? false });\n } catch (err) {\n return rpcResult(id, {\n content: [\n {\n type: \"text\",\n text: `Tool ${name} failed: ${err instanceof Error ? err.message : String(err)}`,\n },\n ],\n isError: true,\n });\n }\n }\n default:\n return rpcError(id, -32601, `Method not found: ${method}`);\n }\n }\n}\n\n/**\n * Runs a message handler over stdio: one JSON message per line in, one per\n * line out. Only protocol JSON is ever written to stdout; diagnostics go to\n * stderr.\n */\nexport class McpStdioServer {\n static run(\n handler: (message: unknown) => Promise<JsonRpcResponse | null>,\n streams: { input?: NodeJS.ReadableStream; output?: NodeJS.WritableStream } = {},\n ): Promise<void> {\n const input = streams.input ?? process.stdin;\n const output = streams.output ?? process.stdout;\n const rl = createInterface({ input, crlfDelay: Infinity });\n const inFlight = new Set<Promise<void>>();\n\n return new Promise((resolve) => {\n rl.on(\"line\", (line) => {\n const trimmed = line.trim();\n if (!trimmed) return;\n const work = (async () => {\n let message: unknown;\n try {\n message = JSON.parse(trimmed);\n } catch {\n output.write(`${JSON.stringify(rpcError(null, -32700, \"Parse error\"))}\\n`);\n return;\n }\n try {\n const response = await handler(message);\n if (response !== null) output.write(`${JSON.stringify(response)}\\n`);\n } catch (err) {\n process.stderr.write(`decionis-mcp: handler error: ${String(err)}\\n`);\n }\n })();\n inFlight.add(work);\n void work.finally(() => inFlight.delete(work));\n });\n rl.on(\"close\", () => {\n // stdin EOF: drain in-flight handlers so no response is lost.\n void Promise.allSettled([...inFlight]).then(() => resolve());\n });\n });\n }\n}\n\n/**\n * Build the message handler. Returns `null` for notifications (no reply) and\n * a JSON-RPC response object otherwise.\n */\nexport function createMcpHandler(options: { serverInfo: ServerInfo; tools: ToolDefinition[] }) {\n const handler = new McpMessageHandler(options);\n return async function handleMessage(message: unknown): Promise<JsonRpcResponse | null> {\n return handler.handle(message);\n };\n}\n\n/**\n * Run the handler over stdio: one JSON message per line in, one per line out.\n * Only protocol JSON is ever written to stdout; diagnostics go to stderr.\n */\nexport function runStdioServer(\n handler: (message: unknown) => Promise<JsonRpcResponse | null>,\n streams: { input?: NodeJS.ReadableStream; output?: NodeJS.WritableStream } = {},\n): Promise<void> {\n return McpStdioServer.run(handler, streams);\n}\n","/**\n * The Decionis MCP tools: read the repo's DECIONIS_POLICY.md, evaluate a\n * candidate action against it through the real protocol evaluator, and\n * explain the verdict vocabulary — so coding agents can check governance\n * constraints BEFORE committing or triggering anything.\n */\n\nimport { LocalDecionisGateway, normalizeVerdict } from \"./Gateway.js\";\nimport { PolicyFileRepository } from \"./agent/PolicyFileRepository.js\";\nimport { sha256Hex } from \"./RulesBlock.js\";\nimport type { ToolContent, ToolDefinition } from \"./Server.js\";\n\nconst text = (value: unknown): ToolContent[] => [\n { type: \"text\", text: typeof value === \"string\" ? value : JSON.stringify(value, null, 2) },\n];\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && !Array.isArray(v);\n\nconst VERDICT_HELP = `# Decionis verdicts and rule grammar\n\n**Verdicts** (a rule's \\`action\\`): \\`allow\\` (execute), \\`block\\` (never execute),\n\\`restrain\\` (hold for human review), \\`escalate\\` (require an authorized approver).\nThe protocol reports outcomes as APPROVE / REJECT / REVIEW / ESCALATE; this server\nalso returns the normalized verdict (allow / block / review / escalate). When no\nrule matches, the platform holds the decision for review (outcome REVIEW).\n\n**Rules block** (in DECIONIS_POLICY.md):\n\\`\\`\\`decionis\n{ \"version\": 1, \"rules\": [\n { \"name\": \"Block deploys during a change freeze\",\n \"priority\": 100, \"domain\": \"*\",\n \"all\": [{ \"field\": \"context.change_freeze\", \"op\": \"eq\", \"value\": true }],\n \"action\": \"block\" } ] }\n\\`\\`\\`\n\n- Each rule has exactly one of \\`all\\` (AND) / \\`any\\` (OR).\n- Operators: eq, ne/neq, gt, gte, lt, lte, in (values array), not_in (values array),\n exists, contains, matches (case-insensitive regex). Equality coerces numbers,\n booleans, and lowercased text; arrays match on any element.\n- Fields resolve against the decision payload: \\`context.<key>\\` reads payload keys,\n \\`decision_type\\` derives from the payload's \\`action\\` label, then the workflow key.\n- Give every rule an explicit \\`priority\\` (higher evaluates first) and keep\n \\`\"domain\": \"*\"\\` so it applies to every decision the repo gates.\n\n**Before committing or running anything risky**, call \\`decionis_evaluate\\` with the\naction you intend to take (e.g. {\"action\": \"production-deploy\", \"agent_generated\": true})\nand abide by the verdict: allow → proceed; block → do not proceed; review/escalate →\nstop and ask a human.`;\n\n/** Builds the Decionis tool set bound to a local gateway. */\nexport class DecionisTools {\n constructor(\n private readonly gateway: LocalDecionisGateway,\n private readonly policyFiles: PolicyFileRepository = new PolicyFileRepository(),\n ) {}\n\n build(): ToolDefinition[] {\n const gateway = this.gateway;\n return [\n {\n name: \"decionis_read_policy\",\n description:\n \"Read and compile the repo's DECIONIS_POLICY.md governance policy: path, sha256, and the \" +\n \"enforceable rules (name, verdict, priority, domain) or compile errors. Use this to learn \" +\n \"what this repository allows, blocks, restrains, or escalates.\",\n inputSchema: {\n type: \"object\",\n properties: {\n path: {\n type: \"string\",\n description:\n \"Policy file path (default: $DECIONIS_POLICY_PATH or ./DECIONIS_POLICY.md)\",\n },\n },\n additionalProperties: false,\n },\n handler: async (args) => {\n const file = await this.policyFiles.read(args.path);\n if (!file.ok) return { content: text(file.message), isError: true };\n const compiled = gateway.compile(file.content);\n return {\n content: text({\n path: file.path,\n sha256: sha256Hex(file.content),\n bytes: Buffer.byteLength(file.content, \"utf8\"),\n rules:\n compiled === null\n ? \"no ```decionis rules block — the file is prose-only documentation\"\n : compiled.errors.length > 0\n ? { compile_errors: compiled.errors }\n : compiled.rules.map((rule) => ({\n name: rule.name,\n verdict: rule.then.action,\n priority: rule.priority,\n domain: rule.decision_domain,\n when: rule.when,\n })),\n }),\n };\n },\n },\n {\n name: \"decionis_evaluate\",\n description:\n \"Evaluate a candidate action against the repo's DECIONIS_POLICY.md through the real Decionis \" +\n \"protocol evaluator, entirely locally (no network, no credentials, nothing recorded). Call this \" +\n \"BEFORE committing, deploying, migrating, or any risky action, and abide by the verdict: \" +\n \"allow → proceed; block → do not proceed; review/escalate → stop and involve a human.\",\n inputSchema: {\n type: \"object\",\n required: [\"payload\"],\n properties: {\n payload: {\n type: \"object\",\n description:\n 'The candidate action, e.g. {\"action\": \"production-deploy\", \"change_freeze\": true, \"agent_generated\": true}',\n },\n workflow_key: {\n type: \"string\",\n description: \"Optional workflow key for the gated surface.\",\n },\n mode: { type: \"string\", enum: [\"shadow\", \"enforce\"], description: \"Default: shadow.\" },\n path: { type: \"string\", description: \"Policy file path override.\" },\n },\n additionalProperties: false,\n },\n handler: async (args) => {\n if (!isPlainObject(args.payload)) {\n return {\n content: text(\"`payload` must be a JSON object describing the action.\"),\n isError: true,\n };\n }\n const file = await this.policyFiles.read(args.path);\n if (!file.ok) return { content: text(file.message), isError: true };\n const workflowKey = typeof args.workflow_key === \"string\" ? args.workflow_key : null;\n\n const published = await gateway.publishPolicy(file.content, { workflowKey });\n if (!published.ok) {\n return {\n content: text({\n error: published.reason,\n details: published.errors,\n hint:\n published.reason === \"no_rules_block\"\n ? \"Add a ```decionis rules block to make the policy enforceable — see decionis_verdict_help.\"\n : \"Fix the rules block so it compiles; the platform enforces all-or-nothing.\",\n }),\n isError: true,\n };\n }\n\n const evaluated = await gateway.evaluate({\n payload: args.payload,\n workflowKey,\n mode: args.mode === \"enforce\" ? \"enforce\" : \"shadow\",\n });\n if (evaluated.status !== 200) {\n return {\n content: text({\n error: `protocol evaluation failed (HTTP ${evaluated.status})`,\n body: evaluated.body,\n }),\n isError: true,\n };\n }\n\n const body = evaluated.body;\n const policyEvaluation = isPlainObject(body.policy_evaluation)\n ? body.policy_evaluation\n : {};\n const evaluatedRuleCount =\n typeof policyEvaluation.evaluated_rule_count === \"number\"\n ? policyEvaluation.evaluated_rule_count\n : null;\n\n return {\n content: text({\n verdict: normalizeVerdict(body.outcome),\n outcome: body.outcome,\n resolution: policyEvaluation.resolution ?? null,\n selected_rule: policyEvaluation.selected_rule_name ?? null,\n matched_rule_count: policyEvaluation.matched_rule_count ?? null,\n evaluated_rule_count: evaluatedRuleCount,\n decision_domain: policyEvaluation.decision_domain ?? body.decision_domain ?? null,\n policy_version: published.version,\n policy_sha256: published.sha256,\n confidence: body.confidence ?? null,\n note:\n \"Local sandbox evaluation — nothing was recorded and no signed dossier was minted. \" +\n \"CI runs through decionis/govern produce the signed, verifiable record.\",\n ...(published.ruleCount > 0 && evaluatedRuleCount === 0\n ? {\n hint:\n `All ${published.ruleCount} compiled rule(s) were filtered out by the decision-domain ` +\n 'match before evaluation. Add \"domain\": \"*\" to each rule so it applies to every ' +\n \"decision this repo gates.\",\n }\n : {}),\n }),\n };\n },\n },\n {\n name: \"decionis_verdict_help\",\n description:\n \"Reference for Decionis verdicts (allow/block/restrain/escalate), the rules-block grammar and \" +\n \"operators, and how an agent should behave on each verdict.\",\n inputSchema: { type: \"object\", properties: {}, additionalProperties: false },\n handler: async () => ({ content: text(VERDICT_HELP) }),\n },\n ];\n }\n}\n\n/** Functional alias for {@link DecionisTools.build}. */\nexport function createDecionisTools(gateway: LocalDecionisGateway): ToolDefinition[] {\n return new DecionisTools(gateway).build();\n}\n","// Decionis local MCP server — stdio entrypoint.\n// Lets AI coding agents (Claude Code, Cursor, …) read DECIONIS_POLICY.md and\n// evaluate candidate actions through the real @decionis/protocol evaluator\n// before they commit, deploy, or migrate anything.\n\nimport { LocalDecionisGateway } from \"./Gateway.js\";\nimport { createMcpHandler, runStdioServer } from \"./Server.js\";\nimport { createDecionisTools } from \"./Tools.js\";\n\nconst gateway = new LocalDecionisGateway();\nconst handler = createMcpHandler({\n serverInfo: { name: \"decionis-mcp\", version: \"0.1.0\" },\n tools: createDecionisTools(gateway),\n});\n\nrunStdioServer(handler)\n .then(async () => {\n await gateway.close();\n process.exit(0);\n })\n .catch(async (err) => {\n process.stderr.write(`decionis-mcp: fatal: ${String(err)}\\n`);\n await gateway.close().catch(() => {});\n process.exit(1);\n });\n"],"mappings":"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","names":["id","handler","isPlainObject","gateway"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@decionis/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Decionis MCP policy tools and native Codex, Copilot, and Claude execution hooks.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"decionis",
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol",
|
|
11
|
+
"ai-agents",
|
|
12
|
+
"agent-permissions",
|
|
13
|
+
"policy",
|
|
14
|
+
"guardrails",
|
|
15
|
+
"pretooluse",
|
|
16
|
+
"hooks",
|
|
17
|
+
"claude-code",
|
|
18
|
+
"codex",
|
|
19
|
+
"copilot"
|
|
20
|
+
],
|
|
21
|
+
"homepage": "https://decionis.com/docs/protocol-mcp",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/decionis/decionis.git",
|
|
25
|
+
"directory": "apps/mcp"
|
|
26
|
+
},
|
|
27
|
+
"bin": {
|
|
28
|
+
"decionis-mcp": "./dist/index.js",
|
|
29
|
+
"decionis-agent-hook": "./dist/AgentHookCli.js",
|
|
30
|
+
"decionis-managed-agent-hook": "./dist/ManagedAgentHookCli.js"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
"./agent": {
|
|
34
|
+
"types": "./dist/agent/AgentIndex.d.ts",
|
|
35
|
+
"import": "./dist/agent/AgentIndex.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"templates",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"ajv": "^8.17.1",
|
|
51
|
+
"ajv-formats": "^3.0.1",
|
|
52
|
+
"fast-json-stringify": "^7.0.1",
|
|
53
|
+
"fastify": "^5.10.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^20.11.30",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
|
58
|
+
"@typescript-eslint/parser": "^8.44.0",
|
|
59
|
+
"tsup": "^8.0.2",
|
|
60
|
+
"tsx": "^4.19.2",
|
|
61
|
+
"typescript": "^5.6.3",
|
|
62
|
+
"vitest": "^2.1.8",
|
|
63
|
+
"@decionis/protocol": "0.0.0",
|
|
64
|
+
"@decionis/shared": "0.0.0"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"dev": "tsx src/index.ts",
|
|
68
|
+
"agent-hook": "tsx src/AgentHookCli.ts",
|
|
69
|
+
"managed-agent-hook": "tsx src/managed/ManagedAgentHookCli.ts",
|
|
70
|
+
"build": "tsup",
|
|
71
|
+
"package:managed": "pnpm run build && node scripts/PackageManagedArtifacts.mjs",
|
|
72
|
+
"npm:smoke": "node scripts/NpmPackSmoke.mjs",
|
|
73
|
+
"start": "node dist/index.js",
|
|
74
|
+
"test": "vitest run",
|
|
75
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
76
|
+
"lint": "eslint .",
|
|
77
|
+
"format": "prettier --check . --ignore-path ../../.prettierignore",
|
|
78
|
+
"format:fix": "prettier --write . --ignore-path ../../.prettierignore"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Block Codex tool execution unless Decionis policy allows it.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "*",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "decionis-agent-hook codex",
|
|
11
|
+
"timeout": 10,
|
|
12
|
+
"statusMessage": "Checking Decionis policy"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|