@decionis/mcp 0.1.1 → 0.1.2

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.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AgentHookCommand
4
- } from "./chunk-5YBOX3WO.js";
5
- import "./chunk-56VFPJNL.js";
4
+ } from "./chunk-2C62WFX2.js";
5
+ import "./chunk-KY5AVRL6.js";
6
6
 
7
7
  // src/AgentHookCli.ts
8
8
  void AgentHookCommand.run(process.argv.slice(2)).then((exitCode) => {
@@ -36770,7 +36770,7 @@ var MCP_PROTOCOL_VERSIONS = [
36770
36770
  "2025-03-26",
36771
36771
  "2024-11-05"
36772
36772
  ];
36773
- var MCP_DEFAULT_PROTOCOL_VERSION = "2025-06-18";
36773
+ var MCP_DEFAULT_PROTOCOL_VERSION = "2025-11-25";
36774
36774
  var DEFAULT_PUBLIC_BASE_URL = "https://protocol.decionis.com";
36775
36775
  var MCP_HTTP_PATHS = ["/mcp", "/v1/protocol/mcp"];
36776
36776
 
@@ -36974,7 +36974,7 @@ var McpAuthGuard = class {
36974
36974
  return auth?.kind === "org_api_key";
36975
36975
  }
36976
36976
  static findTargetOrgIdForTool(name, args) {
36977
- if (name === "decionis.evaluate_decision" || name === "evaluate_decision" || name === "decionis.agentic_checkout_authorize" || name === "agentic_checkout_authorize" || name === "decionis.evaluate_webex_agent_intent" || name === "evaluate_webex_agent_intent" || name === "decionis.get_decision_dossier" || name === "get_decision_dossier" || name === "decionis.list_enforcement_rollouts" || name === "list_enforcement_rollouts" || name === "decionis.upsert_enforcement_rollout" || name === "upsert_enforcement_rollout" || name === "decionis.resolve_vertical_pack" || name === "resolve_vertical_pack" || name === "decionis.run_shadow_decisioning" || name === "run_shadow_decisioning") {
36977
+ if (name === "decionis.evaluate_decision" || name === "evaluate_decision" || name === "decionis.agentic_checkout_authorize" || name === "agentic_checkout_authorize" || name === "decionis.evaluate_webex_agent_intent" || name === "evaluate_webex_agent_intent" || name === "decionis.get_decision_dossier" || name === "get_decision_dossier" || name === "decionis.get_decision_chain" || name === "get_decision_chain" || name === "decionis.list_enforcement_rollouts" || name === "list_enforcement_rollouts" || name === "decionis.upsert_enforcement_rollout" || name === "upsert_enforcement_rollout" || name === "decionis.resolve_vertical_pack" || name === "resolve_vertical_pack" || name === "decionis.run_shadow_decisioning" || name === "run_shadow_decisioning") {
36978
36978
  return asString(args.org_id);
36979
36979
  }
36980
36980
  return null;
@@ -36983,7 +36983,7 @@ var McpAuthGuard = class {
36983
36983
  if (name === "decionis.evaluate_decision" || name === "evaluate_decision" || name === "decionis.agentic_checkout_authorize" || name === "agentic_checkout_authorize" || name === "decionis.evaluate_webex_agent_intent" || name === "evaluate_webex_agent_intent" || name === "decionis.run_shadow_decisioning" || name === "run_shadow_decisioning") {
36984
36984
  return ["decision:run", "decision:*", "org:*"];
36985
36985
  }
36986
- if (name === "decionis.get_decision_dossier" || name === "get_decision_dossier" || name === "decionis.list_enforcement_rollouts" || name === "list_enforcement_rollouts" || name === "decionis.resolve_vertical_pack" || name === "resolve_vertical_pack") {
36986
+ if (name === "decionis.get_decision_dossier" || name === "get_decision_dossier" || name === "decionis.get_decision_chain" || name === "get_decision_chain" || name === "decionis.list_enforcement_rollouts" || name === "list_enforcement_rollouts" || name === "decionis.resolve_vertical_pack" || name === "resolve_vertical_pack") {
36987
36987
  return ["decision:read", "org:read", "decision:*", "org:*"];
36988
36988
  }
36989
36989
  if (name === "decionis.upsert_enforcement_rollout" || name === "upsert_enforcement_rollout") {
@@ -38205,7 +38205,7 @@ var McpTools = class {
38205
38205
  return cart && typeof cart.amount === "number" ? cart.amount : void 0;
38206
38206
  }
38207
38207
  static buildTools(app) {
38208
- return [
38208
+ const tools = [
38209
38209
  {
38210
38210
  name: "decionis.evaluate_decision",
38211
38211
  aliases: ["evaluate_decision"],
@@ -38710,6 +38710,29 @@ var McpTools = class {
38710
38710
  }
38711
38711
  }
38712
38712
  ];
38713
+ const readOnlyTools = /* @__PURE__ */ new Set([
38714
+ "decionis.get_decision_dossier",
38715
+ "decionis.get_decision_chain",
38716
+ "decionis.list_enforcement_rollouts",
38717
+ "decionis.list_marketplace_targets",
38718
+ "decionis.get_marketplace_target",
38719
+ "decionis.list_marketplace_readiness",
38720
+ "decionis.list_vertical_packs",
38721
+ "decionis.resolve_vertical_pack"
38722
+ ]);
38723
+ const idempotentWriteTools = /* @__PURE__ */ new Set(["decionis.upsert_enforcement_rollout"]);
38724
+ return tools.map((tool) => {
38725
+ const readOnly = readOnlyTools.has(tool.name);
38726
+ return {
38727
+ ...tool,
38728
+ annotations: {
38729
+ readOnlyHint: readOnly,
38730
+ destructiveHint: false,
38731
+ idempotentHint: readOnly || idempotentWriteTools.has(tool.name),
38732
+ openWorldHint: false
38733
+ }
38734
+ };
38735
+ });
38713
38736
  }
38714
38737
  static buildTextToolResult(value, options) {
38715
38738
  const text = toPrettyText(value);
@@ -38763,6 +38786,37 @@ function findTool(tools, name) {
38763
38786
  }
38764
38787
 
38765
38788
  // ../protocol/src/mcp/McpRoutes.ts
38789
+ async function recordTelemetry(app, sink, event) {
38790
+ if (!sink) return;
38791
+ try {
38792
+ await sink.record(event);
38793
+ } catch (err) {
38794
+ app.log.warn({ err, event: event.event }, "MCP telemetry write failed");
38795
+ }
38796
+ }
38797
+ function canonicalAuthorizationOutcome(value) {
38798
+ const record = asRecord(value);
38799
+ const raw = asString(record?.outcome) ?? asString(record?.decision) ?? asString(record?.verdict);
38800
+ if (!raw) return null;
38801
+ switch (raw.trim().toUpperCase()) {
38802
+ case "ALLOW":
38803
+ case "APPROVE":
38804
+ case "AUTO_APPROVE":
38805
+ return "ALLOW";
38806
+ case "BLOCK":
38807
+ case "REJECT":
38808
+ case "AUTO_REJECT":
38809
+ return "BLOCK";
38810
+ case "ESCALATE":
38811
+ return "ESCALATE";
38812
+ case "REVIEW":
38813
+ case "RESTRAIN":
38814
+ case "REQUIRE_REVIEW":
38815
+ return "REVIEW";
38816
+ default:
38817
+ return null;
38818
+ }
38819
+ }
38766
38820
  function buildInitializeResult(serviceName, serviceVersion) {
38767
38821
  return {
38768
38822
  protocolVersion: MCP_DEFAULT_PROTOCOL_VERSION,
@@ -38776,7 +38830,7 @@ function buildInitializeResult(serviceName, serviceVersion) {
38776
38830
  title: "Decionis Protocol MCP",
38777
38831
  version: serviceVersion
38778
38832
  },
38779
- instructions: "Use Decionis Protocol as the deterministic execution-governance MCP server. Encode policy with evaluate_decision, stage enforcement with upsert_enforcement_rollout, and verify evidence through Decision Dossiers and audit-linked resources."
38833
+ instructions: "Use Decionis Protocol to evaluate a proposed action before execution and inspect its signed governance evidence. Evaluation tools record Decionis decisions but never perform the downstream mutation. Use read-only dossier, chain, marketplace, and vertical tools for inspection."
38780
38834
  };
38781
38835
  }
38782
38836
  async function handleJsonRpcRequest(app, requestBody, options) {
@@ -38814,6 +38868,16 @@ async function handleJsonRpcRequest(app, requestBody, options) {
38814
38868
  }
38815
38869
  const requestedVersion = asString(params.protocolVersion);
38816
38870
  const negotiatedVersion = requestedVersion && MCP_PROTOCOL_VERSIONS.includes(requestedVersion) ? requestedVersion : MCP_DEFAULT_PROTOCOL_VERSION;
38871
+ const clientInfo = asRecord(params.clientInfo);
38872
+ await recordTelemetry(app, options.telemetry, {
38873
+ event: "connection_succeeded",
38874
+ connectionId: options.connectionId,
38875
+ clientName: asString(clientInfo?.name),
38876
+ clientVersion: asString(clientInfo?.version),
38877
+ protocolVersion: negotiatedVersion,
38878
+ authMode: options.auth?.kind ?? "none",
38879
+ statusCode: 200
38880
+ });
38817
38881
  return {
38818
38882
  statusCode: 200,
38819
38883
  payload: jsonRpcSuccess(id, {
@@ -38829,6 +38893,12 @@ async function handleJsonRpcRequest(app, requestBody, options) {
38829
38893
  case "ping":
38830
38894
  return { statusCode: 200, payload: jsonRpcSuccess(id, {}) };
38831
38895
  case "tools/list":
38896
+ await recordTelemetry(app, options.telemetry, {
38897
+ event: "tools_listed",
38898
+ connectionId: options.connectionId,
38899
+ authMode: options.auth?.kind ?? "none",
38900
+ statusCode: 200
38901
+ });
38832
38902
  return {
38833
38903
  statusCode: 200,
38834
38904
  payload: jsonRpcSuccess(id, {
@@ -38837,7 +38907,8 @@ async function handleJsonRpcRequest(app, requestBody, options) {
38837
38907
  title: tool.title,
38838
38908
  description: tool.description,
38839
38909
  inputSchema: tool.inputSchema,
38840
- ...tool.outputSchema ? { outputSchema: tool.outputSchema } : {}
38910
+ ...tool.outputSchema ? { outputSchema: tool.outputSchema } : {},
38911
+ annotations: tool.annotations
38841
38912
  }))
38842
38913
  })
38843
38914
  };
@@ -38856,15 +38927,61 @@ async function handleJsonRpcRequest(app, requestBody, options) {
38856
38927
  payload: jsonRpcError(id, -32601, `Unknown tool '${name}'`)
38857
38928
  };
38858
38929
  }
38930
+ const toolStartedAt = process.hrtime.bigint();
38931
+ await recordTelemetry(app, options.telemetry, {
38932
+ event: "tool_called",
38933
+ connectionId: options.connectionId,
38934
+ toolName: tool.name,
38935
+ authMode: options.auth?.kind ?? "none"
38936
+ });
38859
38937
  const args = asRecord(params.arguments) ?? {};
38860
38938
  const authError = authorizeToolInvocation(options.auth, name, args);
38861
38939
  if (authError) {
38940
+ await recordTelemetry(app, options.telemetry, {
38941
+ event: "authorization_outcome",
38942
+ connectionId: options.connectionId,
38943
+ toolName: tool.name,
38944
+ outcome: "DENIED",
38945
+ authMode: options.auth?.kind ?? "none",
38946
+ statusCode: 403,
38947
+ durationMs: durationMs(toolStartedAt)
38948
+ });
38949
+ await recordTelemetry(app, options.telemetry, {
38950
+ event: "tool_failed",
38951
+ connectionId: options.connectionId,
38952
+ toolName: tool.name,
38953
+ outcome: "DENIED",
38954
+ authMode: options.auth?.kind ?? "none",
38955
+ statusCode: 403,
38956
+ durationMs: durationMs(toolStartedAt)
38957
+ });
38862
38958
  return {
38863
38959
  statusCode: 403,
38864
38960
  payload: jsonRpcError(id, authError.code, authError.message)
38865
38961
  };
38866
38962
  }
38867
38963
  const result = await handleToolCall(tool, args);
38964
+ const outcome = canonicalAuthorizationOutcome(result.structuredContent);
38965
+ await recordTelemetry(app, options.telemetry, {
38966
+ event: result.isError ? "tool_failed" : "tool_succeeded",
38967
+ connectionId: options.connectionId,
38968
+ toolName: tool.name,
38969
+ outcome,
38970
+ authMode: options.auth?.kind ?? "none",
38971
+ statusCode: 200,
38972
+ durationMs: durationMs(toolStartedAt)
38973
+ });
38974
+ if (outcome) {
38975
+ await recordTelemetry(app, options.telemetry, {
38976
+ event: "authorization_outcome",
38977
+ connectionId: options.connectionId,
38978
+ toolName: tool.name,
38979
+ outcome,
38980
+ authMode: options.auth?.kind ?? "none",
38981
+ statusCode: 200,
38982
+ durationMs: durationMs(toolStartedAt)
38983
+ });
38984
+ }
38868
38985
  return {
38869
38986
  statusCode: 200,
38870
38987
  payload: jsonRpcSuccess(id, result)
@@ -39048,6 +39165,11 @@ async function handleMcpHttpRequest(app, req, reply, options) {
39048
39165
  const auth = await authenticateMcpRequest(req, authLookup);
39049
39166
  const authDurationMs = durationMs(authStartedAt);
39050
39167
  if (!auth && isAuthenticationRequired(authLookup)) {
39168
+ await recordTelemetry(app, options.telemetry ?? null, {
39169
+ event: "authentication_failed",
39170
+ statusCode: 401,
39171
+ durationMs: authDurationMs
39172
+ });
39051
39173
  const maybeId = asRecord(req.body)?.id;
39052
39174
  const id = typeof maybeId === "string" || typeof maybeId === "number" ? maybeId : null;
39053
39175
  reply.header(
@@ -39057,6 +39179,10 @@ async function handleMcpHttpRequest(app, req, reply, options) {
39057
39179
  stages: { auth_ms: authDurationMs }
39058
39180
  })
39059
39181
  );
39182
+ reply.header(
39183
+ "www-authenticate",
39184
+ `Bearer resource_metadata="${options.publicBaseUrl}/.well-known/oauth-protected-resource", error="invalid_token"`
39185
+ );
39060
39186
  return reply.code(401).send(jsonRpcError(id, -32001, "Unauthorized MCP request"));
39061
39187
  }
39062
39188
  if (Array.isArray(req.body)) {
@@ -39071,7 +39197,35 @@ async function handleMcpHttpRequest(app, req, reply, options) {
39071
39197
  }
39072
39198
  if (isLegacyToolCall(req.body)) {
39073
39199
  const rpcStartedAt2 = process.hrtime.bigint();
39200
+ const connectionId2 = asString(req.headers["mcp-session-id"]);
39201
+ await recordTelemetry(app, options.telemetry ?? null, {
39202
+ event: "tool_called",
39203
+ connectionId: connectionId2,
39204
+ toolName: req.body.tool_name,
39205
+ authMode: auth?.kind ?? "none"
39206
+ });
39074
39207
  const payload = await handleLegacyToolCall(app, auth, req.body);
39208
+ const outcome = canonicalAuthorizationOutcome(payload.output);
39209
+ await recordTelemetry(app, options.telemetry ?? null, {
39210
+ event: payload.is_error || payload.error ? "tool_failed" : "tool_succeeded",
39211
+ connectionId: connectionId2,
39212
+ toolName: req.body.tool_name,
39213
+ outcome,
39214
+ authMode: auth?.kind ?? "none",
39215
+ statusCode: 200,
39216
+ durationMs: durationMs(rpcStartedAt2)
39217
+ });
39218
+ if (outcome) {
39219
+ await recordTelemetry(app, options.telemetry ?? null, {
39220
+ event: "authorization_outcome",
39221
+ connectionId: connectionId2,
39222
+ toolName: req.body.tool_name,
39223
+ outcome,
39224
+ authMode: auth?.kind ?? "none",
39225
+ statusCode: 200,
39226
+ durationMs: durationMs(rpcStartedAt2)
39227
+ });
39228
+ }
39075
39229
  reply.header(
39076
39230
  "server-timing",
39077
39231
  buildServerTimingHeader({
@@ -39096,13 +39250,21 @@ async function handleMcpHttpRequest(app, req, reply, options) {
39096
39250
  return reply.code(400).send(jsonRpcError(null, -32600, "JSON-RPC request body required"));
39097
39251
  }
39098
39252
  const rpcStartedAt = process.hrtime.bigint();
39253
+ const requestedMethod = asString(requestBody.method);
39254
+ const incomingSession = asString(req.headers["mcp-session-id"]);
39255
+ const connectionId = requestedMethod === "initialize" ? randomUUID2() : incomingSession;
39099
39256
  const result = await handleJsonRpcRequest(app, requestBody, {
39100
39257
  publicBaseUrl: options.publicBaseUrl,
39101
39258
  serviceName: options.serviceName,
39102
39259
  serviceVersion: options.serviceVersion,
39103
39260
  auth,
39104
- authLookup
39261
+ authLookup,
39262
+ telemetry: options.telemetry ?? null,
39263
+ connectionId
39105
39264
  });
39265
+ if (requestedMethod === "initialize" && result.statusCode === 200) {
39266
+ reply.header("mcp-session-id", connectionId);
39267
+ }
39106
39268
  reply.header(
39107
39269
  "server-timing",
39108
39270
  buildServerTimingHeader({
@@ -39132,8 +39294,21 @@ function registerProtocolMcpRoutes(app, options) {
39132
39294
  endpoint: `${publicBaseUrl}/v1/protocol/mcp`,
39133
39295
  endpoint_aliases: MCP_HTTP_PATHS,
39134
39296
  supported_protocol_versions: [...MCP_PROTOCOL_VERSIONS],
39135
- auth
39297
+ auth,
39298
+ oauth: {
39299
+ protected_resource_metadata: `${publicBaseUrl}/.well-known/oauth-protected-resource`,
39300
+ authorization_server_metadata: "https://api.decionis.com/.well-known/oauth-authorization-server"
39301
+ }
39136
39302
  };
39303
+ const oauthProtectedResource = {
39304
+ resource: `${publicBaseUrl}/mcp`,
39305
+ authorization_servers: ["https://api.decionis.com"],
39306
+ bearer_methods_supported: ["header"],
39307
+ scopes_supported: ["decision:read", "decision:run", "decision:write"],
39308
+ resource_documentation: "https://decionis.com/docs/protocol-mcp"
39309
+ };
39310
+ app.get("/.well-known/oauth-protected-resource", async () => oauthProtectedResource);
39311
+ app.get("/.well-known/oauth-protected-resource/mcp", async () => oauthProtectedResource);
39137
39312
  for (const path2 of MCP_HTTP_PATHS) {
39138
39313
  app.get(path2, async () => metadata);
39139
39314
  app.delete(path2, async (_req, reply) => reply.code(204).send());
@@ -39143,7 +39318,8 @@ function registerProtocolMcpRoutes(app, options) {
39143
39318
  publicBaseUrl,
39144
39319
  serviceName: options.serviceName,
39145
39320
  serviceVersion: options.serviceVersion,
39146
- authLookup
39321
+ authLookup,
39322
+ telemetry: options.telemetry ?? null
39147
39323
  })
39148
39324
  );
39149
39325
  }
@@ -53418,7 +53594,8 @@ function buildProtocolApp(options) {
53418
53594
  registerProtocolMcpRoutes(app, {
53419
53595
  serviceName: PROTOCOL_SERVICE,
53420
53596
  serviceVersion: PROTOCOL_VERSION,
53421
- authLookup: options?.mcpAuthLookup ?? null
53597
+ authLookup: options?.mcpAuthLookup ?? null,
53598
+ telemetry: options?.mcpTelemetry ?? null
53422
53599
  });
53423
53600
  const executionAuthority = createExecutionGatingService(options?.executionGating);
53424
53601
  registerExecutionGatingRoutes(app, {
@@ -13,10 +13,10 @@ import {
13
13
  CopilotHookAdapter,
14
14
  LocalAgentGate,
15
15
  RemoteAgentGate
16
- } from "../chunk-5YBOX3WO.js";
16
+ } from "../chunk-2C62WFX2.js";
17
17
  import {
18
18
  PolicyFileRepository
19
- } from "../chunk-56VFPJNL.js";
19
+ } from "../chunk-KY5AVRL6.js";
20
20
  export {
21
21
  AgentDecisionMapper,
22
22
  AgentGateConfigurationError,
@@ -3,7 +3,7 @@ import {
3
3
  LocalDecionisGateway,
4
4
  PolicyFileRepository,
5
5
  normalizeVerdict
6
- } from "./chunk-56VFPJNL.js";
6
+ } from "./chunk-KY5AVRL6.js";
7
7
 
8
8
  // src/agent/AgentContracts.ts
9
9
  var AgentHookInputError = class extends Error {
@@ -476,4 +476,4 @@ export {
476
476
  AgentHostRegistry,
477
477
  AgentHookCommand
478
478
  };
479
- //# sourceMappingURL=chunk-5YBOX3WO.js.map
479
+ //# sourceMappingURL=chunk-2C62WFX2.js.map