@shipfox/api-integration-core 12.5.0 → 12.6.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.
Files changed (31) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +12 -0
  3. package/dist/metrics/instance.d.ts +5 -0
  4. package/dist/metrics/instance.d.ts.map +1 -1
  5. package/dist/metrics/instance.js +21 -1
  6. package/dist/metrics/instance.js.map +1 -1
  7. package/dist/presentation/routes/agent-tools-gateway/audit.d.ts +4 -1
  8. package/dist/presentation/routes/agent-tools-gateway/audit.d.ts.map +1 -1
  9. package/dist/presentation/routes/agent-tools-gateway/audit.js +6 -1
  10. package/dist/presentation/routes/agent-tools-gateway/audit.js.map +1 -1
  11. package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts +2 -0
  12. package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts.map +1 -1
  13. package/dist/presentation/routes/agent-tools-gateway/dispatch.js +31 -7
  14. package/dist/presentation/routes/agent-tools-gateway/dispatch.js.map +1 -1
  15. package/dist/presentation/routes/agent-tools-gateway/index.d.ts.map +1 -1
  16. package/dist/presentation/routes/agent-tools-gateway/index.js +6 -5
  17. package/dist/presentation/routes/agent-tools-gateway/index.js.map +1 -1
  18. package/dist/presentation/routes/agent-tools-gateway/mcp-server.d.ts.map +1 -1
  19. package/dist/presentation/routes/agent-tools-gateway/mcp-server.js +27 -5
  20. package/dist/presentation/routes/agent-tools-gateway/mcp-server.js.map +1 -1
  21. package/dist/tsconfig.test.tsbuildinfo +1 -1
  22. package/package.json +3 -3
  23. package/src/metrics/instance.ts +40 -1
  24. package/src/presentation/routes/agent-tools-gateway/audit.test.ts +51 -0
  25. package/src/presentation/routes/agent-tools-gateway/audit.ts +8 -0
  26. package/src/presentation/routes/agent-tools-gateway/dispatch.test.ts +62 -2
  27. package/src/presentation/routes/agent-tools-gateway/dispatch.ts +47 -13
  28. package/src/presentation/routes/agent-tools-gateway/index.ts +3 -4
  29. package/src/presentation/routes/agent-tools-gateway/mcp-server.test.ts +41 -4
  30. package/src/presentation/routes/agent-tools-gateway/mcp-server.ts +35 -1
  31. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 54 files with swc (819.4ms)
3
- 2026-08-09T17:51:34.556Z [INFO] asset workflow-bundle-e0d869d865fd59433325.js 3.17 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 54 files with swc (470.87ms)
3
+ 2026-08-10T11:40:57.271Z [INFO] asset workflow-bundle-e0d869d865fd59433325.js 3.17 MiB [emitted] [immutable] (name: main)
4
4
  orphan modules 33.5 KiB [orphan] 21 modules
5
5
  runtime modules 1.13 KiB 5 modules
6
6
  modules by path ../../../../node_modules/.pnpm/ 970 KiB 196 modules
@@ -15,6 +15,6 @@ optional modules 30 bytes [optional]
15
15
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
16
16
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
17
17
  ../../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
18
- webpack 5.107.2 compiled successfully in 14751 ms
19
- 2026-08-09T17:51:34.577Z [INFO] Workflow bundle created { size: '3.17MB' }
18
+ webpack 5.107.2 compiled successfully in 7525 ms
19
+ 2026-08-10T11:40:57.305Z [INFO] Workflow bundle created { size: '3.17MB' }
20
20
  /home/runner/work/shipfox/shipfox/libs/api/integration/core/dist/temporal/workflows/index.js: 3328998 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @shipfox/api-integration-core
2
2
 
3
+ ## 12.6.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 8aaed9e: Record bounded integration tool error details in audit logs and metrics.
8
+ - Updated dependencies [8aaed9e]
9
+ - Updated dependencies [4848ad7]
10
+ - Updated dependencies [594cdbe]
11
+ - Updated dependencies [53b87f0]
12
+ - @shipfox/api-integration-github@12.6.0
13
+ - @shipfox/api-workflows-dto@12.6.0
14
+
3
15
  ## 12.5.0
4
16
 
5
17
  ### Patch Changes
@@ -1,8 +1,13 @@
1
+ import type { IntegrationProviderErrorReason } from '@shipfox/api-integration-spi';
1
2
  export type IntegrationAgentToolCallOutcome = 'success' | 'tool-error' | 'invalid-request' | 'exception';
3
+ export type IntegrationAgentToolCallErrorCode = 'invalid-request' | 'unknown' | 'provider-timeout' | 'credentials-unavailable' | IntegrationProviderErrorReason;
4
+ export type IntegrationAgentToolCallErrorLabel = IntegrationAgentToolCallErrorCode | 'none';
2
5
  export declare function recordIntegrationAgentToolCall(params: {
3
6
  provider: string;
4
7
  tool: string;
5
8
  method: string;
6
9
  outcome: IntegrationAgentToolCallOutcome;
10
+ error_code: IntegrationAgentToolCallErrorLabel;
7
11
  }): void;
12
+ export declare function normalizeIntegrationAgentToolCallErrorCode(value: unknown): IntegrationAgentToolCallErrorCode;
8
13
  //# sourceMappingURL=instance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/metrics/instance.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,+BAA+B,GACvC,SAAS,GACT,YAAY,GACZ,iBAAiB,GACjB,WAAW,CAAC;AAmBhB,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,+BAA+B,CAAC;CAC1C,GAAG,IAAI,CAEP"}
1
+ {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/metrics/instance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,8BAA8B,CAAC;AAKjF,MAAM,MAAM,+BAA+B,GACvC,SAAS,GACT,YAAY,GACZ,iBAAiB,GACjB,WAAW,CAAC;AAEhB,MAAM,MAAM,iCAAiC,GACzC,iBAAiB,GACjB,SAAS,GACT,kBAAkB,GAClB,yBAAyB,GACzB,8BAA8B,CAAC;AAEnC,MAAM,MAAM,kCAAkC,GAAG,iCAAiC,GAAG,MAAM,CAAC;AAuC5F,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,+BAA+B,CAAC;IACzC,UAAU,EAAE,kCAAkC,CAAC;CAChD,GAAG,IAAI,CAEP;AAED,wBAAgB,0CAA0C,CACxD,KAAK,EAAE,OAAO,GACb,iCAAiC,CAInC"}
@@ -1,7 +1,24 @@
1
1
  import { instanceMetrics } from '@shipfox/node-opentelemetry';
2
2
  const meter = instanceMetrics.getMeter('integrations');
3
+ const integrationAgentToolCallErrorCodes = new Set([
4
+ 'invalid-request',
5
+ 'unknown',
6
+ 'provider-timeout',
7
+ 'credentials-unavailable',
8
+ 'repository-not-found',
9
+ 'installation-not-found',
10
+ 'file-not-found',
11
+ 'access-denied',
12
+ 'rate-limited',
13
+ 'timeout',
14
+ 'provider-unavailable',
15
+ 'provider-rejected',
16
+ 'malformed-provider-response',
17
+ 'content-too-large',
18
+ 'too-many-files'
19
+ ]);
3
20
  const agentToolCallCount = meter.createCounter('integrations_agent_tool_call', {
4
- description: 'Integration agent tool calls by provider, tool, method, and outcome'
21
+ description: 'Integration agent tool calls by provider, tool, method, outcome, and bounded error code'
5
22
  });
6
23
  function recordMetric(record) {
7
24
  try {
@@ -13,5 +30,8 @@ function recordMetric(record) {
13
30
  export function recordIntegrationAgentToolCall(params) {
14
31
  recordMetric(()=>agentToolCallCount.add(1, params));
15
32
  }
33
+ export function normalizeIntegrationAgentToolCallErrorCode(value) {
34
+ return typeof value === 'string' && integrationAgentToolCallErrorCodes.has(value) ? value : 'unknown';
35
+ }
16
36
 
17
37
  //# sourceMappingURL=instance.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/instance.ts"],"sourcesContent":["import {instanceMetrics} from '@shipfox/node-opentelemetry';\n\nconst meter = instanceMetrics.getMeter('integrations');\n\nexport type IntegrationAgentToolCallOutcome =\n | 'success'\n | 'tool-error'\n | 'invalid-request'\n | 'exception';\n\nconst agentToolCallCount = meter.createCounter<{\n provider: string;\n tool: string;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n}>('integrations_agent_tool_call', {\n description: 'Integration agent tool calls by provider, tool, method, and outcome',\n});\n\nfunction recordMetric(record: () => void): void {\n try {\n record();\n } catch {\n // Metrics must not affect integration tool call outcomes.\n }\n}\n\nexport function recordIntegrationAgentToolCall(params: {\n provider: string;\n tool: string;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n}): void {\n recordMetric(() => agentToolCallCount.add(1, params));\n}\n"],"names":["instanceMetrics","meter","getMeter","agentToolCallCount","createCounter","description","recordMetric","record","recordIntegrationAgentToolCall","params","add"],"mappings":"AAAA,SAAQA,eAAe,QAAO,8BAA8B;AAE5D,MAAMC,QAAQD,gBAAgBE,QAAQ,CAAC;AAQvC,MAAMC,qBAAqBF,MAAMG,aAAa,CAK3C,gCAAgC;IACjCC,aAAa;AACf;AAEA,SAASC,aAAaC,MAAkB;IACtC,IAAI;QACFA;IACF,EAAE,OAAM;IACN,0DAA0D;IAC5D;AACF;AAEA,OAAO,SAASC,+BAA+BC,MAK9C;IACCH,aAAa,IAAMH,mBAAmBO,GAAG,CAAC,GAAGD;AAC/C"}
1
+ {"version":3,"sources":["../../src/metrics/instance.ts"],"sourcesContent":["import type {IntegrationProviderErrorReason} from '@shipfox/api-integration-spi';\nimport {instanceMetrics} from '@shipfox/node-opentelemetry';\n\nconst meter = instanceMetrics.getMeter('integrations');\n\nexport type IntegrationAgentToolCallOutcome =\n | 'success'\n | 'tool-error'\n | 'invalid-request'\n | 'exception';\n\nexport type IntegrationAgentToolCallErrorCode =\n | 'invalid-request'\n | 'unknown'\n | 'provider-timeout'\n | 'credentials-unavailable'\n | IntegrationProviderErrorReason;\n\nexport type IntegrationAgentToolCallErrorLabel = IntegrationAgentToolCallErrorCode | 'none';\n\nconst integrationAgentToolCallErrorCodes = new Set<string>([\n 'invalid-request',\n 'unknown',\n 'provider-timeout',\n 'credentials-unavailable',\n 'repository-not-found',\n 'installation-not-found',\n 'file-not-found',\n 'access-denied',\n 'rate-limited',\n 'timeout',\n 'provider-unavailable',\n 'provider-rejected',\n 'malformed-provider-response',\n 'content-too-large',\n 'too-many-files',\n]);\n\nconst agentToolCallCount = meter.createCounter<{\n provider: string;\n tool: string;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n error_code: IntegrationAgentToolCallErrorLabel;\n}>('integrations_agent_tool_call', {\n description:\n 'Integration agent tool calls by provider, tool, method, outcome, and bounded error code',\n});\n\nfunction recordMetric(record: () => void): void {\n try {\n record();\n } catch {\n // Metrics must not affect integration tool call outcomes.\n }\n}\n\nexport function recordIntegrationAgentToolCall(params: {\n provider: string;\n tool: string;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n error_code: IntegrationAgentToolCallErrorLabel;\n}): void {\n recordMetric(() => agentToolCallCount.add(1, params));\n}\n\nexport function normalizeIntegrationAgentToolCallErrorCode(\n value: unknown,\n): IntegrationAgentToolCallErrorCode {\n return typeof value === 'string' && integrationAgentToolCallErrorCodes.has(value)\n ? (value as IntegrationAgentToolCallErrorCode)\n : 'unknown';\n}\n"],"names":["instanceMetrics","meter","getMeter","integrationAgentToolCallErrorCodes","Set","agentToolCallCount","createCounter","description","recordMetric","record","recordIntegrationAgentToolCall","params","add","normalizeIntegrationAgentToolCallErrorCode","value","has"],"mappings":"AACA,SAAQA,eAAe,QAAO,8BAA8B;AAE5D,MAAMC,QAAQD,gBAAgBE,QAAQ,CAAC;AAiBvC,MAAMC,qCAAqC,IAAIC,IAAY;IACzD;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,MAAMC,qBAAqBJ,MAAMK,aAAa,CAM3C,gCAAgC;IACjCC,aACE;AACJ;AAEA,SAASC,aAAaC,MAAkB;IACtC,IAAI;QACFA;IACF,EAAE,OAAM;IACN,0DAA0D;IAC5D;AACF;AAEA,OAAO,SAASC,+BAA+BC,MAM9C;IACCH,aAAa,IAAMH,mBAAmBO,GAAG,CAAC,GAAGD;AAC/C;AAEA,OAAO,SAASE,2CACdC,KAAc;IAEd,OAAO,OAAOA,UAAU,YAAYX,mCAAmCY,GAAG,CAACD,SACtEA,QACD;AACN"}
@@ -1,6 +1,7 @@
1
1
  import type { LeasedJobContext } from '@shipfox/api-auth-context';
2
- import { type IntegrationAgentToolCallOutcome, recordIntegrationAgentToolCall } from '#metrics/index.js';
2
+ import { type IntegrationAgentToolCallErrorLabel, type IntegrationAgentToolCallOutcome, recordIntegrationAgentToolCall } from '#metrics/index.js';
3
3
  import type { AuthorizedIntegrationTool } from './resolve-authorized-tools.js';
4
+ export type { IntegrationAgentToolCallErrorCode } from '#metrics/index.js';
4
5
  export declare const UNKNOWN_TOOL_LABEL = "unknown";
5
6
  export declare const NO_METHOD_LABEL = "none";
6
7
  export declare const INVALID_METHOD_LABEL = "invalid";
@@ -13,6 +14,8 @@ export interface IntegrationToolCallAuditRecord {
13
14
  arguments: unknown;
14
15
  method: string;
15
16
  outcome: IntegrationAgentToolCallOutcome;
17
+ errorCode: IntegrationAgentToolCallErrorLabel;
18
+ providerStatus?: number | undefined;
16
19
  }
17
20
  export type IntegrationToolCallRecorder = (record: IntegrationToolCallAuditRecord) => void;
18
21
  export interface CreateIntegrationToolCallRecorderOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EACL,KAAK,+BAA+B,EACpC,8BAA8B,EAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,+BAA+B,CAAC;AAE7E,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,8BAA8B;IAC7C,cAAc,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,+BAA+B,CAAC;CAC1C;AAED,MAAM,MAAM,2BAA2B,GAAG,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;AAE3F,MAAM,WAAW,wCAAwC;IACvD,YAAY,CAAC,EAAE,OAAO,8BAA8B,GAAG,SAAS,CAAC;IACjE,OAAO,CAAC,EACJ,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC,GACtF,SAAS,CAAC;CACf;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,gBAAgB,EACvB,OAAO,GAAE,wCAA6C,GACrD,2BAA2B,CAkC7B;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,OAAO,GAAG,8BAA8B,CAKhG"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EACL,KAAK,kCAAkC,EACvC,KAAK,+BAA+B,EACpC,8BAA8B,EAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,+BAA+B,CAAC;AAE7E,YAAY,EAAC,iCAAiC,EAAC,MAAM,mBAAmB,CAAC;AAEzE,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,MAAM,WAAW,8BAA8B;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,8BAA8B;IAC7C,cAAc,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,+BAA+B,CAAC;IACzC,SAAS,EAAE,kCAAkC,CAAC;IAC9C,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,MAAM,2BAA2B,GAAG,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;AAE3F,MAAM,WAAW,wCAAwC;IACvD,YAAY,CAAC,EAAE,OAAO,8BAA8B,GAAG,SAAS,CAAC;IACjE,OAAO,CAAC,EACJ,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,+BAA+B,KAAK,IAAI,CAAC,GACtF,SAAS,CAAC;CACf;AAED,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,gBAAgB,EACvB,OAAO,GAAE,wCAA6C,GACrD,2BAA2B,CAqC7B;AAED,wBAAgB,iCAAiC,CAAC,KAAK,EAAE,OAAO,GAAG,8BAA8B,CAKhG"}
@@ -13,7 +13,8 @@ export function createIntegrationToolCallRecorder(lease, options = {}) {
13
13
  provider,
14
14
  tool: toolId,
15
15
  method: record.method,
16
- outcome: record.outcome
16
+ outcome: record.outcome,
17
+ error_code: record.errorCode
17
18
  });
18
19
  logInfo({
19
20
  jobId: lease.jobId,
@@ -28,6 +29,10 @@ export function createIntegrationToolCallRecorder(lease, options = {}) {
28
29
  toolId,
29
30
  method: record.method,
30
31
  outcome: record.outcome,
32
+ errorCode: record.errorCode,
33
+ ...record.providerStatus === undefined ? {} : {
34
+ providerStatus: record.providerStatus
35
+ },
31
36
  argumentSummary: summarizeIntegrationToolArguments(record.arguments)
32
37
  }, 'integration tool call audited');
33
38
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/audit.ts"],"sourcesContent":["import type {LeasedJobContext} from '@shipfox/api-auth-context';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {\n type IntegrationAgentToolCallOutcome,\n recordIntegrationAgentToolCall,\n} from '#metrics/index.js';\nimport type {AuthorizedIntegrationTool} from './resolve-authorized-tools.js';\n\nexport const UNKNOWN_TOOL_LABEL = 'unknown';\nexport const NO_METHOD_LABEL = 'none';\nexport const INVALID_METHOD_LABEL = 'invalid';\n\nexport interface IntegrationToolArgumentSummary {\n keys: string[];\n serializedSizeBytes: number;\n}\n\nexport interface IntegrationToolCallAuditRecord {\n authorizedTool?: AuthorizedIntegrationTool | undefined;\n arguments: unknown;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n}\n\nexport type IntegrationToolCallRecorder = (record: IntegrationToolCallAuditRecord) => void;\n\nexport interface CreateIntegrationToolCallRecorderOptions {\n recordMetric?: typeof recordIntegrationAgentToolCall | undefined;\n logInfo?:\n | ((context: Record<string, unknown>, message: 'integration tool call audited') => void)\n | undefined;\n}\n\nexport function createIntegrationToolCallRecorder(\n lease: LeasedJobContext,\n options: CreateIntegrationToolCallRecorderOptions = {},\n): IntegrationToolCallRecorder {\n const recordMetric = options.recordMetric ?? recordIntegrationAgentToolCall;\n const logInfo = options.logInfo ?? ((context, message) => logger().info(context, message));\n\n return (record) => {\n const provider = record.authorizedTool?.integration.provider ?? UNKNOWN_TOOL_LABEL;\n const toolId = record.authorizedTool?.tool.id ?? UNKNOWN_TOOL_LABEL;\n\n recordMetric({\n provider,\n tool: toolId,\n method: record.method,\n outcome: record.outcome,\n });\n\n logInfo(\n {\n jobId: lease.jobId,\n jobExecutionId: lease.jobExecutionId,\n workflowRunId: lease.workflowRunId,\n workflowRunAttemptId: lease.workflowRunAttemptId,\n workspaceId: lease.workspaceId,\n currentStepId: lease.currentStepId,\n currentStepAttempt: lease.currentStepAttempt,\n connectionId: record.authorizedTool?.connection.id,\n provider,\n toolId,\n method: record.method,\n outcome: record.outcome,\n argumentSummary: summarizeIntegrationToolArguments(record.arguments),\n },\n 'integration tool call audited',\n );\n };\n}\n\nexport function summarizeIntegrationToolArguments(value: unknown): IntegrationToolArgumentSummary {\n return {\n keys: isRecord(value) ? Object.keys(value).sort() : [],\n serializedSizeBytes: serializedSize(value),\n };\n}\n\nfunction serializedSize(value: unknown): number {\n try {\n return Buffer.byteLength(JSON.stringify(value) ?? '', 'utf8');\n } catch {\n return 0;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["logger","recordIntegrationAgentToolCall","UNKNOWN_TOOL_LABEL","NO_METHOD_LABEL","INVALID_METHOD_LABEL","createIntegrationToolCallRecorder","lease","options","recordMetric","logInfo","context","message","info","record","provider","authorizedTool","integration","toolId","tool","id","method","outcome","jobId","jobExecutionId","workflowRunId","workflowRunAttemptId","workspaceId","currentStepId","currentStepAttempt","connectionId","connection","argumentSummary","summarizeIntegrationToolArguments","arguments","value","keys","isRecord","Object","sort","serializedSizeBytes","serializedSize","Buffer","byteLength","JSON","stringify","Array","isArray"],"mappings":"AACA,SAAQA,MAAM,QAAO,8BAA8B;AACnD,SAEEC,8BAA8B,QACzB,oBAAoB;AAG3B,OAAO,MAAMC,qBAAqB,UAAU;AAC5C,OAAO,MAAMC,kBAAkB,OAAO;AACtC,OAAO,MAAMC,uBAAuB,UAAU;AAuB9C,OAAO,SAASC,kCACdC,KAAuB,EACvBC,UAAoD,CAAC,CAAC;IAEtD,MAAMC,eAAeD,QAAQC,YAAY,IAAIP;IAC7C,MAAMQ,UAAUF,QAAQE,OAAO,IAAK,CAAA,CAACC,SAASC,UAAYX,SAASY,IAAI,CAACF,SAASC,QAAO;IAExF,OAAO,CAACE;QACN,MAAMC,WAAWD,OAAOE,cAAc,EAAEC,YAAYF,YAAYZ;QAChE,MAAMe,SAASJ,OAAOE,cAAc,EAAEG,KAAKC,MAAMjB;QAEjDM,aAAa;YACXM;YACAI,MAAMD;YACNG,QAAQP,OAAOO,MAAM;YACrBC,SAASR,OAAOQ,OAAO;QACzB;QAEAZ,QACE;YACEa,OAAOhB,MAAMgB,KAAK;YAClBC,gBAAgBjB,MAAMiB,cAAc;YACpCC,eAAelB,MAAMkB,aAAa;YAClCC,sBAAsBnB,MAAMmB,oBAAoB;YAChDC,aAAapB,MAAMoB,WAAW;YAC9BC,eAAerB,MAAMqB,aAAa;YAClCC,oBAAoBtB,MAAMsB,kBAAkB;YAC5CC,cAAchB,OAAOE,cAAc,EAAEe,WAAWX;YAChDL;YACAG;YACAG,QAAQP,OAAOO,MAAM;YACrBC,SAASR,OAAOQ,OAAO;YACvBU,iBAAiBC,kCAAkCnB,OAAOoB,SAAS;QACrE,GACA;IAEJ;AACF;AAEA,OAAO,SAASD,kCAAkCE,KAAc;IAC9D,OAAO;QACLC,MAAMC,SAASF,SAASG,OAAOF,IAAI,CAACD,OAAOI,IAAI,KAAK,EAAE;QACtDC,qBAAqBC,eAAeN;IACtC;AACF;AAEA,SAASM,eAAeN,KAAc;IACpC,IAAI;QACF,OAAOO,OAAOC,UAAU,CAACC,KAAKC,SAAS,CAACV,UAAU,IAAI;IACxD,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASE,SAASF,KAAc;IAC9B,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACW,MAAMC,OAAO,CAACZ;AACvE"}
1
+ {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/audit.ts"],"sourcesContent":["import type {LeasedJobContext} from '@shipfox/api-auth-context';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {\n type IntegrationAgentToolCallErrorLabel,\n type IntegrationAgentToolCallOutcome,\n recordIntegrationAgentToolCall,\n} from '#metrics/index.js';\nimport type {AuthorizedIntegrationTool} from './resolve-authorized-tools.js';\n\nexport type {IntegrationAgentToolCallErrorCode} from '#metrics/index.js';\n\nexport const UNKNOWN_TOOL_LABEL = 'unknown';\nexport const NO_METHOD_LABEL = 'none';\nexport const INVALID_METHOD_LABEL = 'invalid';\n\nexport interface IntegrationToolArgumentSummary {\n keys: string[];\n serializedSizeBytes: number;\n}\n\nexport interface IntegrationToolCallAuditRecord {\n authorizedTool?: AuthorizedIntegrationTool | undefined;\n arguments: unknown;\n method: string;\n outcome: IntegrationAgentToolCallOutcome;\n errorCode: IntegrationAgentToolCallErrorLabel;\n providerStatus?: number | undefined;\n}\n\nexport type IntegrationToolCallRecorder = (record: IntegrationToolCallAuditRecord) => void;\n\nexport interface CreateIntegrationToolCallRecorderOptions {\n recordMetric?: typeof recordIntegrationAgentToolCall | undefined;\n logInfo?:\n | ((context: Record<string, unknown>, message: 'integration tool call audited') => void)\n | undefined;\n}\n\nexport function createIntegrationToolCallRecorder(\n lease: LeasedJobContext,\n options: CreateIntegrationToolCallRecorderOptions = {},\n): IntegrationToolCallRecorder {\n const recordMetric = options.recordMetric ?? recordIntegrationAgentToolCall;\n const logInfo = options.logInfo ?? ((context, message) => logger().info(context, message));\n\n return (record) => {\n const provider = record.authorizedTool?.integration.provider ?? UNKNOWN_TOOL_LABEL;\n const toolId = record.authorizedTool?.tool.id ?? UNKNOWN_TOOL_LABEL;\n\n recordMetric({\n provider,\n tool: toolId,\n method: record.method,\n outcome: record.outcome,\n error_code: record.errorCode,\n });\n\n logInfo(\n {\n jobId: lease.jobId,\n jobExecutionId: lease.jobExecutionId,\n workflowRunId: lease.workflowRunId,\n workflowRunAttemptId: lease.workflowRunAttemptId,\n workspaceId: lease.workspaceId,\n currentStepId: lease.currentStepId,\n currentStepAttempt: lease.currentStepAttempt,\n connectionId: record.authorizedTool?.connection.id,\n provider,\n toolId,\n method: record.method,\n outcome: record.outcome,\n errorCode: record.errorCode,\n ...(record.providerStatus === undefined ? {} : {providerStatus: record.providerStatus}),\n argumentSummary: summarizeIntegrationToolArguments(record.arguments),\n },\n 'integration tool call audited',\n );\n };\n}\n\nexport function summarizeIntegrationToolArguments(value: unknown): IntegrationToolArgumentSummary {\n return {\n keys: isRecord(value) ? Object.keys(value).sort() : [],\n serializedSizeBytes: serializedSize(value),\n };\n}\n\nfunction serializedSize(value: unknown): number {\n try {\n return Buffer.byteLength(JSON.stringify(value) ?? '', 'utf8');\n } catch {\n return 0;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["logger","recordIntegrationAgentToolCall","UNKNOWN_TOOL_LABEL","NO_METHOD_LABEL","INVALID_METHOD_LABEL","createIntegrationToolCallRecorder","lease","options","recordMetric","logInfo","context","message","info","record","provider","authorizedTool","integration","toolId","tool","id","method","outcome","error_code","errorCode","jobId","jobExecutionId","workflowRunId","workflowRunAttemptId","workspaceId","currentStepId","currentStepAttempt","connectionId","connection","providerStatus","undefined","argumentSummary","summarizeIntegrationToolArguments","arguments","value","keys","isRecord","Object","sort","serializedSizeBytes","serializedSize","Buffer","byteLength","JSON","stringify","Array","isArray"],"mappings":"AACA,SAAQA,MAAM,QAAO,8BAA8B;AACnD,SAGEC,8BAA8B,QACzB,oBAAoB;AAK3B,OAAO,MAAMC,qBAAqB,UAAU;AAC5C,OAAO,MAAMC,kBAAkB,OAAO;AACtC,OAAO,MAAMC,uBAAuB,UAAU;AAyB9C,OAAO,SAASC,kCACdC,KAAuB,EACvBC,UAAoD,CAAC,CAAC;IAEtD,MAAMC,eAAeD,QAAQC,YAAY,IAAIP;IAC7C,MAAMQ,UAAUF,QAAQE,OAAO,IAAK,CAAA,CAACC,SAASC,UAAYX,SAASY,IAAI,CAACF,SAASC,QAAO;IAExF,OAAO,CAACE;QACN,MAAMC,WAAWD,OAAOE,cAAc,EAAEC,YAAYF,YAAYZ;QAChE,MAAMe,SAASJ,OAAOE,cAAc,EAAEG,KAAKC,MAAMjB;QAEjDM,aAAa;YACXM;YACAI,MAAMD;YACNG,QAAQP,OAAOO,MAAM;YACrBC,SAASR,OAAOQ,OAAO;YACvBC,YAAYT,OAAOU,SAAS;QAC9B;QAEAd,QACE;YACEe,OAAOlB,MAAMkB,KAAK;YAClBC,gBAAgBnB,MAAMmB,cAAc;YACpCC,eAAepB,MAAMoB,aAAa;YAClCC,sBAAsBrB,MAAMqB,oBAAoB;YAChDC,aAAatB,MAAMsB,WAAW;YAC9BC,eAAevB,MAAMuB,aAAa;YAClCC,oBAAoBxB,MAAMwB,kBAAkB;YAC5CC,cAAclB,OAAOE,cAAc,EAAEiB,WAAWb;YAChDL;YACAG;YACAG,QAAQP,OAAOO,MAAM;YACrBC,SAASR,OAAOQ,OAAO;YACvBE,WAAWV,OAAOU,SAAS;YAC3B,GAAIV,OAAOoB,cAAc,KAAKC,YAAY,CAAC,IAAI;gBAACD,gBAAgBpB,OAAOoB,cAAc;YAAA,CAAC;YACtFE,iBAAiBC,kCAAkCvB,OAAOwB,SAAS;QACrE,GACA;IAEJ;AACF;AAEA,OAAO,SAASD,kCAAkCE,KAAc;IAC9D,OAAO;QACLC,MAAMC,SAASF,SAASG,OAAOF,IAAI,CAACD,OAAOI,IAAI,KAAK,EAAE;QACtDC,qBAAqBC,eAAeN;IACtC;AACF;AAEA,SAASM,eAAeN,KAAc;IACpC,IAAI;QACF,OAAOO,OAAOC,UAAU,CAACC,KAAKC,SAAS,CAACV,UAAU,IAAI;IACxD,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,SAASE,SAASF,KAAc;IAC9B,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACW,MAAMC,OAAO,CAACZ;AACvE"}
@@ -1,9 +1,11 @@
1
+ import type { LeasedJobContext } from '@shipfox/api-auth-context';
1
2
  import { reportError } from '@shipfox/node-error-monitoring';
2
3
  import { logger } from '@shipfox/node-opentelemetry';
3
4
  import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
4
5
  import type { IntegrationToolDispatcher } from './mcp-server.js';
5
6
  export interface CreateIntegrationToolDispatcherParams {
6
7
  registry: IntegrationProviderRegistry;
8
+ lease?: LeasedJobContext | undefined;
7
9
  }
8
10
  export interface IntegrationToolDispatcherDependencies {
9
11
  logger?: typeof logger;
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAC,MAAM,EAAC,MAAM,6BAA6B,CAAC;AAQnD,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,yBAAyB,EAA+B,MAAM,iBAAiB,CAAC;AAE7F,MAAM,WAAW,qCAAqC;IACpD,QAAQ,EAAE,2BAA2B,CAAC;CACvC;AAED,MAAM,WAAW,qCAAqC;IACpD,MAAM,CAAC,EAAE,OAAO,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,WAAW,CAAC;CAClC;AAKD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,qCAAqC,EAC7C,YAAY,GAAE,qCAA0C,GACvD,yBAAyB,CAQ3B"}
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAC,WAAW,EAAC,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAC,MAAM,EAAC,MAAM,6BAA6B,CAAC;AAQnD,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAG7E,OAAO,KAAK,EAAC,yBAAyB,EAA+B,MAAM,iBAAiB,CAAC;AAE7F,MAAM,WAAW,qCAAqC;IACpD,QAAQ,EAAE,2BAA2B,CAAC;IACtC,KAAK,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,qCAAqC;IACpD,MAAM,CAAC,EAAE,OAAO,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,WAAW,CAAC;CAClC;AAMD,wBAAgB,+BAA+B,CAC7C,MAAM,EAAE,qCAAqC,EAC7C,YAAY,GAAE,qCAA0C,GACvD,yBAAyB,CAS3B"}
@@ -1,12 +1,15 @@
1
1
  import { reportError } from '@shipfox/node-error-monitoring';
2
2
  import { logger } from '@shipfox/node-opentelemetry';
3
3
  import { IntegrationProviderError } from '#core/errors.js';
4
- const timeoutErrorPattern = /timed?\s*out|timeout/i;
4
+ import { NO_METHOD_LABEL } from './audit.js';
5
+ const timeoutErrorNamePattern = /timed?\s*out|timeout/i;
6
+ const mcpRequestTimeoutMessagePattern = /^MCP error -32001:\s*Request timed out\b/i;
5
7
  const credentialErrorNamePattern = /Token|Credential|Secret|AccessToken/;
6
8
  export function createIntegrationToolDispatcher(params, dependencies = {}) {
7
9
  return (input)=>dispatchIntegrationToolCall({
8
10
  ...input,
9
11
  registry: params.registry,
12
+ lease: params.lease,
10
13
  logger: dependencies.logger ?? logger,
11
14
  reportError: dependencies.reportError ?? reportError
12
15
  });
@@ -28,11 +31,15 @@ async function dispatchIntegrationToolCall(input) {
28
31
  });
29
32
  } catch (error) {
30
33
  const result = errorResult(error);
31
- if (result.code === 'provider-unavailable') {
34
+ if (result.code === 'provider-unavailable' || result.code === 'unknown') {
32
35
  input.logger().error({
36
+ ...toolCallLogContext(input),
33
37
  err: error,
34
- provider: input.authorizedTool.integration.provider
35
- }, 'Integration agent tool provider was unavailable');
38
+ errorCode: result.code,
39
+ ...result.status === undefined ? {} : {
40
+ providerStatus: result.status
41
+ }
42
+ }, result.code === 'provider-unavailable' ? 'Integration agent tool provider was unavailable' : 'Integration agent tool call failed');
36
43
  input.reportError(error, {
37
44
  boundary: 'integration.agent-tool'
38
45
  });
@@ -42,6 +49,23 @@ async function dispatchIntegrationToolCall(input) {
42
49
  await closeSession(session, input.logger, input.reportError);
43
50
  }
44
51
  }
52
+ function toolCallLogContext(input) {
53
+ return {
54
+ ...input.lease === undefined ? {} : {
55
+ jobId: input.lease.jobId,
56
+ jobExecutionId: input.lease.jobExecutionId,
57
+ workflowRunId: input.lease.workflowRunId,
58
+ workflowRunAttemptId: input.lease.workflowRunAttemptId,
59
+ workspaceId: input.lease.workspaceId,
60
+ currentStepId: input.lease.currentStepId,
61
+ currentStepAttempt: input.lease.currentStepAttempt
62
+ },
63
+ connectionId: input.authorizedTool.connection.id,
64
+ provider: input.authorizedTool.integration.provider,
65
+ toolId: input.authorizedTool.tool.id,
66
+ method: input.method ?? NO_METHOD_LABEL
67
+ };
68
+ }
45
69
  function agentToolCatalogEntry(input) {
46
70
  const { tool, description, inputSchema, outputSchema } = input.authorizedTool;
47
71
  return {
@@ -105,13 +129,13 @@ function errorResult(error) {
105
129
  };
106
130
  }
107
131
  return {
108
- code: 'provider-unavailable',
109
- message: 'Integration provider call failed'
132
+ code: 'unknown',
133
+ message: 'Integration tool call failed'
110
134
  };
111
135
  }
112
136
  function isTimeoutError(error) {
113
137
  if (!(error instanceof Error)) return false;
114
- return error.name === 'AbortError' || timeoutErrorPattern.test(error.name) || timeoutErrorPattern.test(error.message);
138
+ return error.name === 'AbortError' || timeoutErrorNamePattern.test(error.name) || error.name === 'McpError' && mcpRequestTimeoutMessagePattern.test(error.message);
115
139
  }
116
140
  function isCredentialError(error) {
117
141
  if (!(error instanceof Error)) return false;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/dispatch.ts"],"sourcesContent":["import type {CallToolResult} from '@modelcontextprotocol/sdk/types.js';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {IntegrationProviderError} from '#core/errors.js';\nimport type {\n AgentToolCatalogEntry,\n AgentToolCatalogMethod,\n AgentToolSession,\n AgentToolsProvider,\n} from '#core/providers/agent-tools.js';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {IntegrationToolDispatcher, IntegrationToolDispatchInput} from './mcp-server.js';\n\nexport interface CreateIntegrationToolDispatcherParams {\n registry: IntegrationProviderRegistry;\n}\n\nexport interface IntegrationToolDispatcherDependencies {\n logger?: typeof logger;\n reportError?: typeof reportError;\n}\n\nconst timeoutErrorPattern = /timed?\\s*out|timeout/i;\nconst credentialErrorNamePattern = /Token|Credential|Secret|AccessToken/;\n\nexport function createIntegrationToolDispatcher(\n params: CreateIntegrationToolDispatcherParams,\n dependencies: IntegrationToolDispatcherDependencies = {},\n): IntegrationToolDispatcher {\n return (input) =>\n dispatchIntegrationToolCall({\n ...input,\n registry: params.registry,\n logger: dependencies.logger ?? logger,\n reportError: dependencies.reportError ?? reportError,\n });\n}\n\nasync function dispatchIntegrationToolCall(\n input: IntegrationToolDispatchInput & {\n registry: IntegrationProviderRegistry;\n logger: typeof logger;\n reportError: typeof reportError;\n },\n): Promise<CallToolResult> {\n let session: AgentToolSession<CallToolResult> | undefined;\n\n try {\n const adapter = input.registry.getAdapter(\n input.authorizedTool.integration.provider,\n 'agent_tools',\n ) as AgentToolsProvider<\n typeof input.authorizedTool.connection,\n unknown,\n typeof input.authorizedTool.integration,\n CallToolResult\n >;\n session = await adapter.openSession({\n connection: input.authorizedTool.connection,\n tools: [agentToolCatalogEntry(input)],\n scope: input.authorizedTool.integration,\n });\n\n return await session.call({\n toolId: input.authorizedTool.tool.id,\n arguments: input.arguments,\n });\n } catch (error) {\n const result = errorResult(error);\n if (result.code === 'provider-unavailable') {\n input\n .logger()\n .error(\n {err: error, provider: input.authorizedTool.integration.provider},\n 'Integration agent tool provider was unavailable',\n );\n input.reportError(error, {boundary: 'integration.agent-tool'});\n }\n return toolError(result);\n } finally {\n await closeSession(session, input.logger, input.reportError);\n }\n}\n\nfunction agentToolCatalogEntry(input: IntegrationToolDispatchInput): AgentToolCatalogEntry {\n const {tool, description, inputSchema, outputSchema} = input.authorizedTool;\n return {\n id: tool.id,\n description,\n sensitivity: tool.sensitivity,\n sensitive: tool.sensitive,\n requiredScope: tool.requiredScope,\n inputSchema,\n ...(outputSchema === undefined ? {} : {outputSchema}),\n ...(tool.methods === undefined\n ? {}\n : {\n methods: tool.methods.map(\n (method): AgentToolCatalogMethod => ({\n id: method.id,\n description: method.description ?? method.token,\n sensitivity: method.sensitivity,\n sensitive: method.sensitive,\n requiredScope: method.requiredScope,\n }),\n ),\n }),\n };\n}\n\nasync function closeSession(\n session: {close?(): Promise<void>} | undefined,\n loggerFactory: typeof logger,\n reportErrorFn: typeof reportError,\n): Promise<void> {\n try {\n await session?.close?.();\n } catch (error) {\n // Cleanup must not mask the tool result returned to the runner.\n loggerFactory().error({err: error}, 'Failed to close integration agent tool session');\n reportErrorFn(error, {boundary: 'integration.agent-tool', operation: 'close-session'});\n }\n}\n\ninterface IntegrationToolError {\n code: string;\n message: string;\n retryAfterSeconds?: number | undefined;\n status?: number | undefined;\n}\n\nfunction errorResult(error: unknown): IntegrationToolError {\n if (error instanceof IntegrationProviderError) {\n return {\n code: error.reason,\n message: error.message,\n ...(error.retryAfterSeconds === undefined\n ? {}\n : {retryAfterSeconds: error.retryAfterSeconds}),\n ...(error.status === undefined ? {} : {status: error.status}),\n };\n }\n\n if (isTimeoutError(error)) {\n return {\n code: 'provider-timeout',\n message: 'Integration provider timed out',\n };\n }\n\n if (isCredentialError(error)) {\n return {\n code: 'credentials-unavailable',\n message: 'Integration provider credentials are unavailable',\n };\n }\n\n return {\n code: 'provider-unavailable',\n message: 'Integration provider call failed',\n };\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.name === 'AbortError' ||\n timeoutErrorPattern.test(error.name) ||\n timeoutErrorPattern.test(error.message)\n );\n}\n\nfunction isCredentialError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return credentialErrorNamePattern.test(error.name);\n}\n\nfunction toolError(params: IntegrationToolError): CallToolResult {\n return {\n isError: true,\n content: [{type: 'text', text: params.message}],\n structuredContent: {\n code: params.code,\n ...(params.retryAfterSeconds === undefined\n ? {}\n : {retryAfterSeconds: params.retryAfterSeconds}),\n ...(params.status === undefined ? {} : {status: params.status}),\n },\n };\n}\n"],"names":["reportError","logger","IntegrationProviderError","timeoutErrorPattern","credentialErrorNamePattern","createIntegrationToolDispatcher","params","dependencies","input","dispatchIntegrationToolCall","registry","session","adapter","getAdapter","authorizedTool","integration","provider","openSession","connection","tools","agentToolCatalogEntry","scope","call","toolId","tool","id","arguments","error","result","errorResult","code","err","boundary","toolError","closeSession","description","inputSchema","outputSchema","sensitivity","sensitive","requiredScope","undefined","methods","map","method","token","loggerFactory","reportErrorFn","close","operation","reason","message","retryAfterSeconds","status","isTimeoutError","isCredentialError","Error","name","test","isError","content","type","text","structuredContent"],"mappings":"AACA,SAAQA,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,MAAM,QAAO,8BAA8B;AACnD,SAAQC,wBAAwB,QAAO,kBAAkB;AAmBzD,MAAMC,sBAAsB;AAC5B,MAAMC,6BAA6B;AAEnC,OAAO,SAASC,gCACdC,MAA6C,EAC7CC,eAAsD,CAAC,CAAC;IAExD,OAAO,CAACC,QACNC,4BAA4B;YAC1B,GAAGD,KAAK;YACRE,UAAUJ,OAAOI,QAAQ;YACzBT,QAAQM,aAAaN,MAAM,IAAIA;YAC/BD,aAAaO,aAAaP,WAAW,IAAIA;QAC3C;AACJ;AAEA,eAAeS,4BACbD,KAIC;IAED,IAAIG;IAEJ,IAAI;QACF,MAAMC,UAAUJ,MAAME,QAAQ,CAACG,UAAU,CACvCL,MAAMM,cAAc,CAACC,WAAW,CAACC,QAAQ,EACzC;QAOFL,UAAU,MAAMC,QAAQK,WAAW,CAAC;YAClCC,YAAYV,MAAMM,cAAc,CAACI,UAAU;YAC3CC,OAAO;gBAACC,sBAAsBZ;aAAO;YACrCa,OAAOb,MAAMM,cAAc,CAACC,WAAW;QACzC;QAEA,OAAO,MAAMJ,QAAQW,IAAI,CAAC;YACxBC,QAAQf,MAAMM,cAAc,CAACU,IAAI,CAACC,EAAE;YACpCC,WAAWlB,MAAMkB,SAAS;QAC5B;IACF,EAAE,OAAOC,OAAO;QACd,MAAMC,SAASC,YAAYF;QAC3B,IAAIC,OAAOE,IAAI,KAAK,wBAAwB;YAC1CtB,MACGP,MAAM,GACN0B,KAAK,CACJ;gBAACI,KAAKJ;gBAAOX,UAAUR,MAAMM,cAAc,CAACC,WAAW,CAACC,QAAQ;YAAA,GAChE;YAEJR,MAAMR,WAAW,CAAC2B,OAAO;gBAACK,UAAU;YAAwB;QAC9D;QACA,OAAOC,UAAUL;IACnB,SAAU;QACR,MAAMM,aAAavB,SAASH,MAAMP,MAAM,EAAEO,MAAMR,WAAW;IAC7D;AACF;AAEA,SAASoB,sBAAsBZ,KAAmC;IAChE,MAAM,EAACgB,IAAI,EAAEW,WAAW,EAAEC,WAAW,EAAEC,YAAY,EAAC,GAAG7B,MAAMM,cAAc;IAC3E,OAAO;QACLW,IAAID,KAAKC,EAAE;QACXU;QACAG,aAAad,KAAKc,WAAW;QAC7BC,WAAWf,KAAKe,SAAS;QACzBC,eAAehB,KAAKgB,aAAa;QACjCJ;QACA,GAAIC,iBAAiBI,YAAY,CAAC,IAAI;YAACJ;QAAY,CAAC;QACpD,GAAIb,KAAKkB,OAAO,KAAKD,YACjB,CAAC,IACD;YACEC,SAASlB,KAAKkB,OAAO,CAACC,GAAG,CACvB,CAACC,SAAoC,CAAA;oBACnCnB,IAAImB,OAAOnB,EAAE;oBACbU,aAAaS,OAAOT,WAAW,IAAIS,OAAOC,KAAK;oBAC/CP,aAAaM,OAAON,WAAW;oBAC/BC,WAAWK,OAAOL,SAAS;oBAC3BC,eAAeI,OAAOJ,aAAa;gBACrC,CAAA;QAEJ,CAAC;IACP;AACF;AAEA,eAAeN,aACbvB,OAA8C,EAC9CmC,aAA4B,EAC5BC,aAAiC;IAEjC,IAAI;QACF,MAAMpC,SAASqC;IACjB,EAAE,OAAOrB,OAAO;QACd,gEAAgE;QAChEmB,gBAAgBnB,KAAK,CAAC;YAACI,KAAKJ;QAAK,GAAG;QACpCoB,cAAcpB,OAAO;YAACK,UAAU;YAA0BiB,WAAW;QAAe;IACtF;AACF;AASA,SAASpB,YAAYF,KAAc;IACjC,IAAIA,iBAAiBzB,0BAA0B;QAC7C,OAAO;YACL4B,MAAMH,MAAMuB,MAAM;YAClBC,SAASxB,MAAMwB,OAAO;YACtB,GAAIxB,MAAMyB,iBAAiB,KAAKX,YAC5B,CAAC,IACD;gBAACW,mBAAmBzB,MAAMyB,iBAAiB;YAAA,CAAC;YAChD,GAAIzB,MAAM0B,MAAM,KAAKZ,YAAY,CAAC,IAAI;gBAACY,QAAQ1B,MAAM0B,MAAM;YAAA,CAAC;QAC9D;IACF;IAEA,IAAIC,eAAe3B,QAAQ;QACzB,OAAO;YACLG,MAAM;YACNqB,SAAS;QACX;IACF;IAEA,IAAII,kBAAkB5B,QAAQ;QAC5B,OAAO;YACLG,MAAM;YACNqB,SAAS;QACX;IACF;IAEA,OAAO;QACLrB,MAAM;QACNqB,SAAS;IACX;AACF;AAEA,SAASG,eAAe3B,KAAc;IACpC,IAAI,CAAEA,CAAAA,iBAAiB6B,KAAI,GAAI,OAAO;IACtC,OACE7B,MAAM8B,IAAI,KAAK,gBACftD,oBAAoBuD,IAAI,CAAC/B,MAAM8B,IAAI,KACnCtD,oBAAoBuD,IAAI,CAAC/B,MAAMwB,OAAO;AAE1C;AAEA,SAASI,kBAAkB5B,KAAc;IACvC,IAAI,CAAEA,CAAAA,iBAAiB6B,KAAI,GAAI,OAAO;IACtC,OAAOpD,2BAA2BsD,IAAI,CAAC/B,MAAM8B,IAAI;AACnD;AAEA,SAASxB,UAAU3B,MAA4B;IAC7C,OAAO;QACLqD,SAAS;QACTC,SAAS;YAAC;gBAACC,MAAM;gBAAQC,MAAMxD,OAAO6C,OAAO;YAAA;SAAE;QAC/CY,mBAAmB;YACjBjC,MAAMxB,OAAOwB,IAAI;YACjB,GAAIxB,OAAO8C,iBAAiB,KAAKX,YAC7B,CAAC,IACD;gBAACW,mBAAmB9C,OAAO8C,iBAAiB;YAAA,CAAC;YACjD,GAAI9C,OAAO+C,MAAM,KAAKZ,YAAY,CAAC,IAAI;gBAACY,QAAQ/C,OAAO+C,MAAM;YAAA,CAAC;QAChE;IACF;AACF"}
1
+ {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/dispatch.ts"],"sourcesContent":["import type {CallToolResult} from '@modelcontextprotocol/sdk/types.js';\nimport type {LeasedJobContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {IntegrationProviderError} from '#core/errors.js';\nimport type {\n AgentToolCatalogEntry,\n AgentToolCatalogMethod,\n AgentToolSession,\n AgentToolsProvider,\n} from '#core/providers/agent-tools.js';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {IntegrationAgentToolCallErrorCode} from '#metrics/index.js';\nimport {NO_METHOD_LABEL} from './audit.js';\nimport type {IntegrationToolDispatcher, IntegrationToolDispatchInput} from './mcp-server.js';\n\nexport interface CreateIntegrationToolDispatcherParams {\n registry: IntegrationProviderRegistry;\n lease?: LeasedJobContext | undefined;\n}\n\nexport interface IntegrationToolDispatcherDependencies {\n logger?: typeof logger;\n reportError?: typeof reportError;\n}\n\nconst timeoutErrorNamePattern = /timed?\\s*out|timeout/i;\nconst mcpRequestTimeoutMessagePattern = /^MCP error -32001:\\s*Request timed out\\b/i;\nconst credentialErrorNamePattern = /Token|Credential|Secret|AccessToken/;\n\nexport function createIntegrationToolDispatcher(\n params: CreateIntegrationToolDispatcherParams,\n dependencies: IntegrationToolDispatcherDependencies = {},\n): IntegrationToolDispatcher {\n return (input) =>\n dispatchIntegrationToolCall({\n ...input,\n registry: params.registry,\n lease: params.lease,\n logger: dependencies.logger ?? logger,\n reportError: dependencies.reportError ?? reportError,\n });\n}\n\nasync function dispatchIntegrationToolCall(\n input: IntegrationToolDispatchInput & {\n registry: IntegrationProviderRegistry;\n lease?: LeasedJobContext | undefined;\n logger: typeof logger;\n reportError: typeof reportError;\n },\n): Promise<CallToolResult> {\n let session: AgentToolSession<CallToolResult> | undefined;\n\n try {\n const adapter = input.registry.getAdapter(\n input.authorizedTool.integration.provider,\n 'agent_tools',\n ) as AgentToolsProvider<\n typeof input.authorizedTool.connection,\n unknown,\n typeof input.authorizedTool.integration,\n CallToolResult\n >;\n session = await adapter.openSession({\n connection: input.authorizedTool.connection,\n tools: [agentToolCatalogEntry(input)],\n scope: input.authorizedTool.integration,\n });\n\n return await session.call({\n toolId: input.authorizedTool.tool.id,\n arguments: input.arguments,\n });\n } catch (error) {\n const result = errorResult(error);\n if (result.code === 'provider-unavailable' || result.code === 'unknown') {\n input.logger().error(\n {\n ...toolCallLogContext(input),\n err: error,\n errorCode: result.code,\n ...(result.status === undefined ? {} : {providerStatus: result.status}),\n },\n result.code === 'provider-unavailable'\n ? 'Integration agent tool provider was unavailable'\n : 'Integration agent tool call failed',\n );\n input.reportError(error, {boundary: 'integration.agent-tool'});\n }\n return toolError(result);\n } finally {\n await closeSession(session, input.logger, input.reportError);\n }\n}\n\nfunction toolCallLogContext(\n input: IntegrationToolDispatchInput & {lease?: LeasedJobContext | undefined},\n): Record<string, unknown> {\n return {\n ...(input.lease === undefined\n ? {}\n : {\n jobId: input.lease.jobId,\n jobExecutionId: input.lease.jobExecutionId,\n workflowRunId: input.lease.workflowRunId,\n workflowRunAttemptId: input.lease.workflowRunAttemptId,\n workspaceId: input.lease.workspaceId,\n currentStepId: input.lease.currentStepId,\n currentStepAttempt: input.lease.currentStepAttempt,\n }),\n connectionId: input.authorizedTool.connection.id,\n provider: input.authorizedTool.integration.provider,\n toolId: input.authorizedTool.tool.id,\n method: input.method ?? NO_METHOD_LABEL,\n };\n}\n\nfunction agentToolCatalogEntry(input: IntegrationToolDispatchInput): AgentToolCatalogEntry {\n const {tool, description, inputSchema, outputSchema} = input.authorizedTool;\n return {\n id: tool.id,\n description,\n sensitivity: tool.sensitivity,\n sensitive: tool.sensitive,\n requiredScope: tool.requiredScope,\n inputSchema,\n ...(outputSchema === undefined ? {} : {outputSchema}),\n ...(tool.methods === undefined\n ? {}\n : {\n methods: tool.methods.map(\n (method): AgentToolCatalogMethod => ({\n id: method.id,\n description: method.description ?? method.token,\n sensitivity: method.sensitivity,\n sensitive: method.sensitive,\n requiredScope: method.requiredScope,\n }),\n ),\n }),\n };\n}\n\nasync function closeSession(\n session: {close?(): Promise<void>} | undefined,\n loggerFactory: typeof logger,\n reportErrorFn: typeof reportError,\n): Promise<void> {\n try {\n await session?.close?.();\n } catch (error) {\n // Cleanup must not mask the tool result returned to the runner.\n loggerFactory().error({err: error}, 'Failed to close integration agent tool session');\n reportErrorFn(error, {boundary: 'integration.agent-tool', operation: 'close-session'});\n }\n}\n\ninterface IntegrationToolError {\n code: IntegrationAgentToolCallErrorCode;\n message: string;\n retryAfterSeconds?: number | undefined;\n status?: number | undefined;\n}\n\nfunction errorResult(error: unknown): IntegrationToolError {\n if (error instanceof IntegrationProviderError) {\n return {\n code: error.reason,\n message: error.message,\n ...(error.retryAfterSeconds === undefined\n ? {}\n : {retryAfterSeconds: error.retryAfterSeconds}),\n ...(error.status === undefined ? {} : {status: error.status}),\n };\n }\n\n if (isTimeoutError(error)) {\n return {\n code: 'provider-timeout',\n message: 'Integration provider timed out',\n };\n }\n\n if (isCredentialError(error)) {\n return {\n code: 'credentials-unavailable',\n message: 'Integration provider credentials are unavailable',\n };\n }\n\n return {\n code: 'unknown',\n message: 'Integration tool call failed',\n };\n}\n\nfunction isTimeoutError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.name === 'AbortError' ||\n timeoutErrorNamePattern.test(error.name) ||\n (error.name === 'McpError' && mcpRequestTimeoutMessagePattern.test(error.message))\n );\n}\n\nfunction isCredentialError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return credentialErrorNamePattern.test(error.name);\n}\n\nfunction toolError(params: IntegrationToolError): CallToolResult {\n return {\n isError: true,\n content: [{type: 'text', text: params.message}],\n structuredContent: {\n code: params.code,\n ...(params.retryAfterSeconds === undefined\n ? {}\n : {retryAfterSeconds: params.retryAfterSeconds}),\n ...(params.status === undefined ? {} : {status: params.status}),\n },\n };\n}\n"],"names":["reportError","logger","IntegrationProviderError","NO_METHOD_LABEL","timeoutErrorNamePattern","mcpRequestTimeoutMessagePattern","credentialErrorNamePattern","createIntegrationToolDispatcher","params","dependencies","input","dispatchIntegrationToolCall","registry","lease","session","adapter","getAdapter","authorizedTool","integration","provider","openSession","connection","tools","agentToolCatalogEntry","scope","call","toolId","tool","id","arguments","error","result","errorResult","code","toolCallLogContext","err","errorCode","status","undefined","providerStatus","boundary","toolError","closeSession","jobId","jobExecutionId","workflowRunId","workflowRunAttemptId","workspaceId","currentStepId","currentStepAttempt","connectionId","method","description","inputSchema","outputSchema","sensitivity","sensitive","requiredScope","methods","map","token","loggerFactory","reportErrorFn","close","operation","reason","message","retryAfterSeconds","isTimeoutError","isCredentialError","Error","name","test","isError","content","type","text","structuredContent"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEnE,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAIvE,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAC,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAC,oCAAoC,EAAC,MAAM,+BAA+B,CAAC;AAEnF,MAAM,WAAW,mCAAmC;IAClD,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,EAAE,2BAA2B,CAAC;IACtC,4BAA4B,EAAE,8BAA8B,CAAC;CAC9D;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,mCAAmC,GAC1C,UAAU,CAiDZ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEnE,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAC,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAIvE,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAC,qBAAqB,EAAC,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAC,oCAAoC,EAAC,MAAM,+BAA+B,CAAC;AAEnF,MAAM,WAAW,mCAAmC;IAClD,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,EAAE,2BAA2B,CAAC;IACtC,4BAA4B,EAAE,8BAA8B,CAAC;CAC9D;AAED,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,mCAAmC,GAC1C,UAAU,CAgDZ"}
@@ -9,9 +9,6 @@ import { buildAgentToolsMcpServer } from './mcp-server.js';
9
9
  import { resolveAuthorizedIntegrationTools } from './resolve-authorized-tools.js';
10
10
  export { createWorkflowsLeasedAgentStepLoader } from './resolve-authorized-tools.js';
11
11
  export function createAgentToolsGatewayRoutes(params) {
12
- const dispatchIntegrationToolCall = createIntegrationToolDispatcher({
13
- registry: params.registry
14
- });
15
12
  return {
16
13
  prefix: '/runs/jobs/current/integration-tools',
17
14
  auth: AUTH_LEASED_JOB,
@@ -21,6 +18,7 @@ export function createAgentToolsGatewayRoutes(params) {
21
18
  path: '/mcp',
22
19
  description: 'Gateway MCP endpoint for integration-backed agent tools',
23
20
  handler: async (request, reply)=>{
21
+ const lease = requireLeasedJobContext(request);
24
22
  const authorizedTools = await resolveAuthorizedIntegrationTools({
25
23
  request,
26
24
  loadLeasedAgentStep: params.loadLeasedAgentStep,
@@ -29,8 +27,11 @@ export function createAgentToolsGatewayRoutes(params) {
29
27
  });
30
28
  const server = buildAgentToolsMcpServer({
31
29
  authorizedTools,
32
- dispatch: dispatchIntegrationToolCall,
33
- recordCall: createIntegrationToolCallRecorder(requireLeasedJobContext(request))
30
+ dispatch: createIntegrationToolDispatcher({
31
+ registry: params.registry,
32
+ lease
33
+ }),
34
+ recordCall: createIntegrationToolCallRecorder(lease)
34
35
  });
35
36
  const transport = new StreamableHTTPServerTransport();
36
37
  await server.connect(transport);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {AUTH_LEASED_JOB, requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {createIntegrationToolCallRecorder} from './audit.js';\nimport {createIntegrationToolDispatcher} from './dispatch.js';\nimport {buildAgentToolsMcpServer} from './mcp-server.js';\nimport {\n type LeasedAgentStepLoader,\n resolveAuthorizedIntegrationTools,\n} from './resolve-authorized-tools.js';\n\nexport type {LeasedAgentStepLoader} from './resolve-authorized-tools.js';\nexport {createWorkflowsLeasedAgentStepLoader} from './resolve-authorized-tools.js';\n\nexport interface CreateAgentToolsGatewayRoutesParams {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport function createAgentToolsGatewayRoutes(\n params: CreateAgentToolsGatewayRoutesParams,\n): RouteGroup {\n const dispatchIntegrationToolCall = createIntegrationToolDispatcher({registry: params.registry});\n\n return {\n prefix: '/runs/jobs/current/integration-tools',\n auth: AUTH_LEASED_JOB,\n routes: [\n defineRoute({\n method: 'POST',\n path: '/mcp',\n description: 'Gateway MCP endpoint for integration-backed agent tools',\n handler: async (request, reply) => {\n const authorizedTools = await resolveAuthorizedIntegrationTools({\n request,\n loadLeasedAgentStep: params.loadLeasedAgentStep,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const server = buildAgentToolsMcpServer({\n authorizedTools,\n dispatch: dispatchIntegrationToolCall,\n recordCall: createIntegrationToolCallRecorder(requireLeasedJobContext(request)),\n });\n const transport = new StreamableHTTPServerTransport();\n\n await server.connect(transport as unknown as Transport);\n reply.raw.on('close', () => {\n void transport.close().catch((error) => {\n logger().error({err: error}, 'Failed to close integration agent tool transport');\n reportError(error, {\n boundary: 'integration.agent-tool',\n operation: 'close-transport',\n });\n });\n void server.close().catch((error) => {\n logger().error({err: error}, 'Failed to close integration agent tool server');\n reportError(error, {\n boundary: 'integration.agent-tool',\n operation: 'close-server',\n });\n });\n });\n\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n },\n }),\n ],\n };\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_LEASED_JOB","requireLeasedJobContext","reportError","defineRoute","logger","createIntegrationToolCallRecorder","createIntegrationToolDispatcher","buildAgentToolsMcpServer","resolveAuthorizedIntegrationTools","createWorkflowsLeasedAgentStepLoader","createAgentToolsGatewayRoutes","params","dispatchIntegrationToolCall","registry","prefix","auth","routes","method","path","description","handler","request","reply","authorizedTools","loadLeasedAgentStep","getIntegrationConnectionById","server","dispatch","recordCall","transport","connect","raw","on","close","catch","error","err","boundary","operation","hijack","handleRequest","body"],"mappings":"AAAA,SAAQA,6BAA6B,QAAO,qDAAqD;AAEjG,SAAQC,eAAe,EAAEC,uBAAuB,QAAO,4BAA4B;AACnF,SAAQC,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,WAAW,QAAwB,wBAAwB;AACnE,SAAQC,MAAM,QAAO,8BAA8B;AAGnD,SAAQC,iCAAiC,QAAO,aAAa;AAC7D,SAAQC,+BAA+B,QAAO,gBAAgB;AAC9D,SAAQC,wBAAwB,QAAO,kBAAkB;AACzD,SAEEC,iCAAiC,QAC5B,gCAAgC;AAGvC,SAAQC,oCAAoC,QAAO,gCAAgC;AAQnF,OAAO,SAASC,8BACdC,MAA2C;IAE3C,MAAMC,8BAA8BN,gCAAgC;QAACO,UAAUF,OAAOE,QAAQ;IAAA;IAE9F,OAAO;QACLC,QAAQ;QACRC,MAAMf;QACNgB,QAAQ;YACNb,YAAY;gBACVc,QAAQ;gBACRC,MAAM;gBACNC,aAAa;gBACbC,SAAS,OAAOC,SAASC;oBACvB,MAAMC,kBAAkB,MAAMf,kCAAkC;wBAC9Da;wBACAG,qBAAqBb,OAAOa,mBAAmB;wBAC/CX,UAAUF,OAAOE,QAAQ;wBACzBY,8BAA8Bd,OAAOc,4BAA4B;oBACnE;oBACA,MAAMC,SAASnB,yBAAyB;wBACtCgB;wBACAI,UAAUf;wBACVgB,YAAYvB,kCAAkCJ,wBAAwBoB;oBACxE;oBACA,MAAMQ,YAAY,IAAI9B;oBAEtB,MAAM2B,OAAOI,OAAO,CAACD;oBACrBP,MAAMS,GAAG,CAACC,EAAE,CAAC,SAAS;wBACpB,KAAKH,UAAUI,KAAK,GAAGC,KAAK,CAAC,CAACC;4BAC5B/B,SAAS+B,KAAK,CAAC;gCAACC,KAAKD;4BAAK,GAAG;4BAC7BjC,YAAYiC,OAAO;gCACjBE,UAAU;gCACVC,WAAW;4BACb;wBACF;wBACA,KAAKZ,OAAOO,KAAK,GAAGC,KAAK,CAAC,CAACC;4BACzB/B,SAAS+B,KAAK,CAAC;gCAACC,KAAKD;4BAAK,GAAG;4BAC7BjC,YAAYiC,OAAO;gCACjBE,UAAU;gCACVC,WAAW;4BACb;wBACF;oBACF;oBAEAhB,MAAMiB,MAAM;oBACZ,MAAMV,UAAUW,aAAa,CAACnB,QAAQU,GAAG,EAAET,MAAMS,GAAG,EAAEV,QAAQoB,IAAI;gBACpE;YACF;SACD;IACH;AACF"}
1
+ {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/index.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {AUTH_LEASED_JOB, requireLeasedJobContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {defineRoute, type RouteGroup} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport type {IntegrationProviderRegistry} from '#core/providers/registry.js';\nimport type {GetIntegrationConnectionByIdFn} from '#db/connections.js';\nimport {createIntegrationToolCallRecorder} from './audit.js';\nimport {createIntegrationToolDispatcher} from './dispatch.js';\nimport {buildAgentToolsMcpServer} from './mcp-server.js';\nimport {\n type LeasedAgentStepLoader,\n resolveAuthorizedIntegrationTools,\n} from './resolve-authorized-tools.js';\n\nexport type {LeasedAgentStepLoader} from './resolve-authorized-tools.js';\nexport {createWorkflowsLeasedAgentStepLoader} from './resolve-authorized-tools.js';\n\nexport interface CreateAgentToolsGatewayRoutesParams {\n loadLeasedAgentStep: LeasedAgentStepLoader;\n registry: IntegrationProviderRegistry;\n getIntegrationConnectionById: GetIntegrationConnectionByIdFn;\n}\n\nexport function createAgentToolsGatewayRoutes(\n params: CreateAgentToolsGatewayRoutesParams,\n): RouteGroup {\n return {\n prefix: '/runs/jobs/current/integration-tools',\n auth: AUTH_LEASED_JOB,\n routes: [\n defineRoute({\n method: 'POST',\n path: '/mcp',\n description: 'Gateway MCP endpoint for integration-backed agent tools',\n handler: async (request, reply) => {\n const lease = requireLeasedJobContext(request);\n const authorizedTools = await resolveAuthorizedIntegrationTools({\n request,\n loadLeasedAgentStep: params.loadLeasedAgentStep,\n registry: params.registry,\n getIntegrationConnectionById: params.getIntegrationConnectionById,\n });\n const server = buildAgentToolsMcpServer({\n authorizedTools,\n dispatch: createIntegrationToolDispatcher({registry: params.registry, lease}),\n recordCall: createIntegrationToolCallRecorder(lease),\n });\n const transport = new StreamableHTTPServerTransport();\n\n await server.connect(transport as unknown as Transport);\n reply.raw.on('close', () => {\n void transport.close().catch((error) => {\n logger().error({err: error}, 'Failed to close integration agent tool transport');\n reportError(error, {\n boundary: 'integration.agent-tool',\n operation: 'close-transport',\n });\n });\n void server.close().catch((error) => {\n logger().error({err: error}, 'Failed to close integration agent tool server');\n reportError(error, {\n boundary: 'integration.agent-tool',\n operation: 'close-server',\n });\n });\n });\n\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n },\n }),\n ],\n };\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_LEASED_JOB","requireLeasedJobContext","reportError","defineRoute","logger","createIntegrationToolCallRecorder","createIntegrationToolDispatcher","buildAgentToolsMcpServer","resolveAuthorizedIntegrationTools","createWorkflowsLeasedAgentStepLoader","createAgentToolsGatewayRoutes","params","prefix","auth","routes","method","path","description","handler","request","reply","lease","authorizedTools","loadLeasedAgentStep","registry","getIntegrationConnectionById","server","dispatch","recordCall","transport","connect","raw","on","close","catch","error","err","boundary","operation","hijack","handleRequest","body"],"mappings":"AAAA,SAAQA,6BAA6B,QAAO,qDAAqD;AAEjG,SAAQC,eAAe,EAAEC,uBAAuB,QAAO,4BAA4B;AACnF,SAAQC,WAAW,QAAO,iCAAiC;AAC3D,SAAQC,WAAW,QAAwB,wBAAwB;AACnE,SAAQC,MAAM,QAAO,8BAA8B;AAGnD,SAAQC,iCAAiC,QAAO,aAAa;AAC7D,SAAQC,+BAA+B,QAAO,gBAAgB;AAC9D,SAAQC,wBAAwB,QAAO,kBAAkB;AACzD,SAEEC,iCAAiC,QAC5B,gCAAgC;AAGvC,SAAQC,oCAAoC,QAAO,gCAAgC;AAQnF,OAAO,SAASC,8BACdC,MAA2C;IAE3C,OAAO;QACLC,QAAQ;QACRC,MAAMb;QACNc,QAAQ;YACNX,YAAY;gBACVY,QAAQ;gBACRC,MAAM;gBACNC,aAAa;gBACbC,SAAS,OAAOC,SAASC;oBACvB,MAAMC,QAAQpB,wBAAwBkB;oBACtC,MAAMG,kBAAkB,MAAMd,kCAAkC;wBAC9DW;wBACAI,qBAAqBZ,OAAOY,mBAAmB;wBAC/CC,UAAUb,OAAOa,QAAQ;wBACzBC,8BAA8Bd,OAAOc,4BAA4B;oBACnE;oBACA,MAAMC,SAASnB,yBAAyB;wBACtCe;wBACAK,UAAUrB,gCAAgC;4BAACkB,UAAUb,OAAOa,QAAQ;4BAAEH;wBAAK;wBAC3EO,YAAYvB,kCAAkCgB;oBAChD;oBACA,MAAMQ,YAAY,IAAI9B;oBAEtB,MAAM2B,OAAOI,OAAO,CAACD;oBACrBT,MAAMW,GAAG,CAACC,EAAE,CAAC,SAAS;wBACpB,KAAKH,UAAUI,KAAK,GAAGC,KAAK,CAAC,CAACC;4BAC5B/B,SAAS+B,KAAK,CAAC;gCAACC,KAAKD;4BAAK,GAAG;4BAC7BjC,YAAYiC,OAAO;gCACjBE,UAAU;gCACVC,WAAW;4BACb;wBACF;wBACA,KAAKZ,OAAOO,KAAK,GAAGC,KAAK,CAAC,CAACC;4BACzB/B,SAAS+B,KAAK,CAAC;gCAACC,KAAKD;4BAAK,GAAG;4BAC7BjC,YAAYiC,OAAO;gCACjBE,UAAU;gCACVC,WAAW;4BACb;wBACF;oBACF;oBAEAlB,MAAMmB,MAAM;oBACZ,MAAMV,UAAUW,aAAa,CAACrB,QAAQY,GAAG,EAAEX,MAAMW,GAAG,EAAEZ,QAAQsB,IAAI;gBACpE;YACF;SACD;IACH;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AACjE,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAuB,KAAK,2BAA2B,EAAkB,MAAM,YAAY,CAAC;AACnG,OAAO,KAAK,EACV,yBAAyB,EACzB,4BAA4B,EAC7B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,yBAAyB,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,4BAA4B,KAChC,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,4BAA4B,CAAC;IAC9C,QAAQ,EAAE,yBAAyB,CAAC;IACpC,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACtD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,8BAA8B,GAAG,MAAM,CAqFvF"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AACjE,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,oCAAoC,CAAC;AAI5C,OAAO,EAGL,KAAK,2BAA2B,EAEjC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,yBAAyB,EACzB,4BAA4B,EAC7B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,4BAA4B;IAC3C,cAAc,EAAE,yBAAyB,CAAC;IAC1C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,4BAA4B,KAChC,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,WAAW,8BAA8B;IAC7C,eAAe,EAAE,4BAA4B,CAAC;IAC9C,QAAQ,EAAE,yBAAyB,CAAC;IACpC,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACtD;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,8BAA8B,GAAG,MAAM,CA0FvF"}
@@ -2,6 +2,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
3
3
  import { reportError } from '@shipfox/node-error-monitoring';
4
4
  import { logger } from '@shipfox/node-opentelemetry';
5
+ import { normalizeIntegrationAgentToolCallErrorCode } from '#metrics/index.js';
5
6
  import { INVALID_METHOD_LABEL, NO_METHOD_LABEL } from './audit.js';
6
7
  export function buildAgentToolsMcpServer(params) {
7
8
  const server = new Server({
@@ -30,7 +31,8 @@ export function buildAgentToolsMcpServer(params) {
30
31
  recordToolCall(params.recordCall, {
31
32
  arguments: request.params.arguments ?? {},
32
33
  method: NO_METHOD_LABEL,
33
- outcome: 'invalid-request'
34
+ outcome: 'invalid-request',
35
+ errorCode: 'invalid-request'
34
36
  });
35
37
  return toolError(`Unknown integration tool: ${request.params.name}`);
36
38
  }
@@ -40,7 +42,8 @@ export function buildAgentToolsMcpServer(params) {
40
42
  authorizedTool,
41
43
  arguments: args,
42
44
  method: NO_METHOD_LABEL,
43
- outcome: 'invalid-request'
45
+ outcome: 'invalid-request',
46
+ errorCode: 'invalid-request'
44
47
  });
45
48
  return toolError('Tool arguments must be an object');
46
49
  }
@@ -50,7 +53,8 @@ export function buildAgentToolsMcpServer(params) {
50
53
  authorizedTool,
51
54
  arguments: args,
52
55
  method: INVALID_METHOD_LABEL,
53
- outcome: 'invalid-request'
56
+ outcome: 'invalid-request',
57
+ errorCode: 'invalid-request'
54
58
  });
55
59
  return toolError(methodValidation.message);
56
60
  }
@@ -65,7 +69,8 @@ export function buildAgentToolsMcpServer(params) {
65
69
  authorizedTool,
66
70
  arguments: args,
67
71
  method,
68
- outcome: result.isError === true ? 'tool-error' : 'success'
72
+ outcome: result.isError === true ? 'tool-error' : 'success',
73
+ ...toolCallErrorDetails(result)
69
74
  });
70
75
  return result;
71
76
  } catch (error) {
@@ -73,13 +78,27 @@ export function buildAgentToolsMcpServer(params) {
73
78
  authorizedTool,
74
79
  arguments: args,
75
80
  method,
76
- outcome: 'exception'
81
+ outcome: 'exception',
82
+ errorCode: 'unknown'
77
83
  });
78
84
  throw error;
79
85
  }
80
86
  });
81
87
  return server;
82
88
  }
89
+ function toolCallErrorDetails(result) {
90
+ if (result.isError !== true) return {
91
+ errorCode: 'none'
92
+ };
93
+ const structuredContent = isRecord(result.structuredContent) ? result.structuredContent : undefined;
94
+ const providerStatus = statusCode(structuredContent?.status);
95
+ return {
96
+ errorCode: normalizeIntegrationAgentToolCallErrorCode(structuredContent?.code),
97
+ ...providerStatus === undefined ? {} : {
98
+ providerStatus
99
+ }
100
+ };
101
+ }
83
102
  function recordToolCall(recordCall, record) {
84
103
  try {
85
104
  recordCall?.(record);
@@ -131,5 +150,8 @@ function toolError(message) {
131
150
  function isRecord(value) {
132
151
  return typeof value === 'object' && value !== null && !Array.isArray(value);
133
152
  }
153
+ function statusCode(value) {
154
+ return typeof value === 'number' && Number.isInteger(value) && value >= 100 && value <= 599 ? value : undefined;
155
+ }
134
156
 
135
157
  //# sourceMappingURL=mcp-server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/mcp-server.ts"],"sourcesContent":["import {Server} from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {INVALID_METHOD_LABEL, type IntegrationToolCallRecorder, NO_METHOD_LABEL} from './audit.js';\nimport type {\n AuthorizedIntegrationTool,\n AuthorizedIntegrationToolMap,\n} from './resolve-authorized-tools.js';\n\nexport interface IntegrationToolDispatchInput {\n authorizedTool: AuthorizedIntegrationTool;\n arguments: Record<string, unknown>;\n method?: string | undefined;\n}\n\nexport type IntegrationToolDispatcher = (\n input: IntegrationToolDispatchInput,\n) => Promise<CallToolResult>;\n\nexport interface BuildAgentToolsMcpServerParams {\n authorizedTools: AuthorizedIntegrationToolMap;\n dispatch: IntegrationToolDispatcher;\n recordCall?: IntegrationToolCallRecorder | undefined;\n}\n\nexport function buildAgentToolsMcpServer(params: BuildAgentToolsMcpServerParams): Server {\n const server = new Server(\n {name: 'shipfox-integration-tools', version: '0.0.0'},\n {capabilities: {tools: {}}},\n );\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: [...params.authorizedTools.values()].map((authorizedTool) => ({\n name: authorizedTool.mcpName,\n description: authorizedTool.description,\n inputSchema: authorizedTool.inputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n ...(authorizedTool.outputSchema\n ? {\n outputSchema: authorizedTool.outputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n }\n : {}),\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const authorizedTool = params.authorizedTools.get(request.params.name);\n if (!authorizedTool) {\n recordToolCall(params.recordCall, {\n arguments: request.params.arguments ?? {},\n method: NO_METHOD_LABEL,\n outcome: 'invalid-request',\n });\n return toolError(`Unknown integration tool: ${request.params.name}`);\n }\n\n const args = request.params.arguments ?? {};\n if (!isRecord(args)) {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method: NO_METHOD_LABEL,\n outcome: 'invalid-request',\n });\n return toolError('Tool arguments must be an object');\n }\n\n const methodValidation = validateMethod(authorizedTool, args);\n if (methodValidation.kind === 'error') {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method: INVALID_METHOD_LABEL,\n outcome: 'invalid-request',\n });\n return toolError(methodValidation.message);\n }\n const method = methodValidation.method ?? NO_METHOD_LABEL;\n\n try {\n const result = await params.dispatch({\n authorizedTool,\n arguments: args,\n method: methodValidation.method,\n });\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method,\n outcome: result.isError === true ? 'tool-error' : 'success',\n });\n return result;\n } catch (error) {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method,\n outcome: 'exception',\n });\n throw error;\n }\n });\n\n return server;\n}\n\nfunction recordToolCall(\n recordCall: IntegrationToolCallRecorder | undefined,\n record: Parameters<IntegrationToolCallRecorder>[0],\n): void {\n try {\n recordCall?.(record);\n } catch (error) {\n // Audit and metrics must not affect MCP responses.\n logger().error({err: error}, 'Failed to record integration agent tool audit event');\n reportError(error, {boundary: 'integration.agent-tool', operation: 'audit'});\n }\n}\n\nfunction validateMethod(\n authorizedTool: AuthorizedIntegrationTool,\n args: Record<string, unknown>,\n): {kind: 'ok'; method?: string | undefined} | {kind: 'error'; message: string} {\n if (!authorizedTool.tool.methods) return {kind: 'ok'};\n\n const method = args.method;\n if (typeof method !== 'string') {\n return {kind: 'error', message: 'Method-family tools require a string method argument'};\n }\n\n const allowedMethods = new Set(authorizedTool.tool.methods.map((candidate) => candidate.id));\n if (!allowedMethods.has(method)) {\n return {kind: 'error', message: `Unauthorized integration tool method: ${method}`};\n }\n\n return {kind: 'ok', method};\n}\n\nfunction toolError(message: string): CallToolResult {\n return {\n isError: true,\n content: [{type: 'text', text: message}],\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["Server","CallToolRequestSchema","ListToolsRequestSchema","reportError","logger","INVALID_METHOD_LABEL","NO_METHOD_LABEL","buildAgentToolsMcpServer","params","server","name","version","capabilities","tools","setRequestHandler","authorizedTools","values","map","authorizedTool","mcpName","description","inputSchema","outputSchema","request","get","recordToolCall","recordCall","arguments","method","outcome","toolError","args","isRecord","methodValidation","validateMethod","kind","message","result","dispatch","isError","error","record","err","boundary","operation","tool","methods","allowedMethods","Set","candidate","id","has","content","type","text","value","Array","isArray"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/presentation/routes/agent-tools-gateway/mcp-server.ts"],"sourcesContent":["import {Server} from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {normalizeIntegrationAgentToolCallErrorCode} from '#metrics/index.js';\nimport {\n INVALID_METHOD_LABEL,\n type IntegrationAgentToolCallErrorCode,\n type IntegrationToolCallRecorder,\n NO_METHOD_LABEL,\n} from './audit.js';\nimport type {\n AuthorizedIntegrationTool,\n AuthorizedIntegrationToolMap,\n} from './resolve-authorized-tools.js';\n\nexport interface IntegrationToolDispatchInput {\n authorizedTool: AuthorizedIntegrationTool;\n arguments: Record<string, unknown>;\n method?: string | undefined;\n}\n\nexport type IntegrationToolDispatcher = (\n input: IntegrationToolDispatchInput,\n) => Promise<CallToolResult>;\n\nexport interface BuildAgentToolsMcpServerParams {\n authorizedTools: AuthorizedIntegrationToolMap;\n dispatch: IntegrationToolDispatcher;\n recordCall?: IntegrationToolCallRecorder | undefined;\n}\n\nexport function buildAgentToolsMcpServer(params: BuildAgentToolsMcpServerParams): Server {\n const server = new Server(\n {name: 'shipfox-integration-tools', version: '0.0.0'},\n {capabilities: {tools: {}}},\n );\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: [...params.authorizedTools.values()].map((authorizedTool) => ({\n name: authorizedTool.mcpName,\n description: authorizedTool.description,\n inputSchema: authorizedTool.inputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n ...(authorizedTool.outputSchema\n ? {\n outputSchema: authorizedTool.outputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n }\n : {}),\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const authorizedTool = params.authorizedTools.get(request.params.name);\n if (!authorizedTool) {\n recordToolCall(params.recordCall, {\n arguments: request.params.arguments ?? {},\n method: NO_METHOD_LABEL,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n });\n return toolError(`Unknown integration tool: ${request.params.name}`);\n }\n\n const args = request.params.arguments ?? {};\n if (!isRecord(args)) {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method: NO_METHOD_LABEL,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n });\n return toolError('Tool arguments must be an object');\n }\n\n const methodValidation = validateMethod(authorizedTool, args);\n if (methodValidation.kind === 'error') {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method: INVALID_METHOD_LABEL,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n });\n return toolError(methodValidation.message);\n }\n const method = methodValidation.method ?? NO_METHOD_LABEL;\n\n try {\n const result = await params.dispatch({\n authorizedTool,\n arguments: args,\n method: methodValidation.method,\n });\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method,\n outcome: result.isError === true ? 'tool-error' : 'success',\n ...toolCallErrorDetails(result),\n });\n return result;\n } catch (error) {\n recordToolCall(params.recordCall, {\n authorizedTool,\n arguments: args,\n method,\n outcome: 'exception',\n errorCode: 'unknown',\n });\n throw error;\n }\n });\n\n return server;\n}\n\nfunction toolCallErrorDetails(result: CallToolResult): {\n errorCode: IntegrationAgentToolCallErrorCode | 'none';\n providerStatus?: number | undefined;\n} {\n if (result.isError !== true) return {errorCode: 'none'};\n\n const structuredContent = isRecord(result.structuredContent)\n ? result.structuredContent\n : undefined;\n const providerStatus = statusCode(structuredContent?.status);\n\n return {\n errorCode: normalizeIntegrationAgentToolCallErrorCode(structuredContent?.code),\n ...(providerStatus === undefined ? {} : {providerStatus}),\n };\n}\n\nfunction recordToolCall(\n recordCall: IntegrationToolCallRecorder | undefined,\n record: Parameters<IntegrationToolCallRecorder>[0],\n): void {\n try {\n recordCall?.(record);\n } catch (error) {\n // Audit and metrics must not affect MCP responses.\n logger().error({err: error}, 'Failed to record integration agent tool audit event');\n reportError(error, {boundary: 'integration.agent-tool', operation: 'audit'});\n }\n}\n\nfunction validateMethod(\n authorizedTool: AuthorizedIntegrationTool,\n args: Record<string, unknown>,\n): {kind: 'ok'; method?: string | undefined} | {kind: 'error'; message: string} {\n if (!authorizedTool.tool.methods) return {kind: 'ok'};\n\n const method = args.method;\n if (typeof method !== 'string') {\n return {kind: 'error', message: 'Method-family tools require a string method argument'};\n }\n\n const allowedMethods = new Set(authorizedTool.tool.methods.map((candidate) => candidate.id));\n if (!allowedMethods.has(method)) {\n return {kind: 'error', message: `Unauthorized integration tool method: ${method}`};\n }\n\n return {kind: 'ok', method};\n}\n\nfunction toolError(message: string): CallToolResult {\n return {\n isError: true,\n content: [{type: 'text', text: message}],\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction statusCode(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value >= 100 && value <= 599\n ? value\n : undefined;\n}\n"],"names":["Server","CallToolRequestSchema","ListToolsRequestSchema","reportError","logger","normalizeIntegrationAgentToolCallErrorCode","INVALID_METHOD_LABEL","NO_METHOD_LABEL","buildAgentToolsMcpServer","params","server","name","version","capabilities","tools","setRequestHandler","authorizedTools","values","map","authorizedTool","mcpName","description","inputSchema","outputSchema","request","get","recordToolCall","recordCall","arguments","method","outcome","errorCode","toolError","args","isRecord","methodValidation","validateMethod","kind","message","result","dispatch","isError","toolCallErrorDetails","error","structuredContent","undefined","providerStatus","statusCode","status","code","record","err","boundary","operation","tool","methods","allowedMethods","Set","candidate","id","has","content","type","text","value","Array","isArray","Number","isInteger"],"mappings":"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"}