@shipfox/api-integration-core 12.4.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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +32 -0
- package/dist/metrics/instance.d.ts +5 -0
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +21 -1
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/audit.d.ts +4 -1
- package/dist/presentation/routes/agent-tools-gateway/audit.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/audit.js +6 -1
- package/dist/presentation/routes/agent-tools-gateway/audit.js.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts +9 -1
- package/dist/presentation/routes/agent-tools-gateway/dispatch.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/dispatch.js +55 -17
- package/dist/presentation/routes/agent-tools-gateway/dispatch.js.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/index.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/index.js +6 -5
- package/dist/presentation/routes/agent-tools-gateway/index.js.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/mcp-server.d.ts.map +1 -1
- package/dist/presentation/routes/agent-tools-gateway/mcp-server.js +27 -5
- package/dist/presentation/routes/agent-tools-gateway/mcp-server.js.map +1 -1
- package/dist/presentation/routes/errors.d.ts.map +1 -1
- package/dist/presentation/routes/errors.js +1 -1
- package/dist/presentation/routes/errors.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/metrics/instance.ts +40 -1
- package/src/presentation/routes/agent-tools-gateway/agent-tools-gateway.route.test.ts +11 -4
- package/src/presentation/routes/agent-tools-gateway/audit.test.ts +51 -0
- package/src/presentation/routes/agent-tools-gateway/audit.ts +8 -0
- package/src/presentation/routes/agent-tools-gateway/dispatch.test.ts +167 -0
- package/src/presentation/routes/agent-tools-gateway/dispatch.ts +93 -20
- package/src/presentation/routes/agent-tools-gateway/index.ts +3 -4
- package/src/presentation/routes/agent-tools-gateway/mcp-server.test.ts +41 -4
- package/src/presentation/routes/agent-tools-gateway/mcp-server.ts +35 -1
- package/src/presentation/routes/errors.ts +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
$ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
|
|
2
|
-
Successfully compiled: 54 files with swc (
|
|
3
|
-
2026-08-
|
|
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
|
|
19
|
-
2026-08-
|
|
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,37 @@
|
|
|
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
|
+
|
|
15
|
+
## 12.5.0
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- f2b20af: Preserve GitHub provider rejection details and classify terminal agent-tool failures without reporting them as provider outages.
|
|
20
|
+
- Updated dependencies [420ef97]
|
|
21
|
+
- Updated dependencies [f2b20af]
|
|
22
|
+
- Updated dependencies [da02bd8]
|
|
23
|
+
- Updated dependencies [4fa3667]
|
|
24
|
+
- Updated dependencies [5b1838c]
|
|
25
|
+
- @shipfox/api-integration-github@12.5.0
|
|
26
|
+
- @shipfox/api-integration-spi@1.1.1
|
|
27
|
+
- @shipfox/api-workflows-dto@12.5.0
|
|
28
|
+
- @shipfox/api-integration-gitea@12.5.0
|
|
29
|
+
- @shipfox/api-integration-jira@12.5.0
|
|
30
|
+
- @shipfox/api-integration-linear@12.5.0
|
|
31
|
+
- @shipfox/api-integration-sentry@12.5.0
|
|
32
|
+
- @shipfox/api-integration-slack@12.5.0
|
|
33
|
+
- @shipfox/api-integration-webhook@12.5.0
|
|
34
|
+
|
|
3
35
|
## 12.4.0
|
|
4
36
|
|
|
5
37
|
### 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":"
|
|
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"}
|
package/dist/metrics/instance.js
CHANGED
|
@@ -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
|
|
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
|
|
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;
|
|
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,
|
|
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,7 +1,15 @@
|
|
|
1
|
+
import type { LeasedJobContext } from '@shipfox/api-auth-context';
|
|
2
|
+
import { reportError } from '@shipfox/node-error-monitoring';
|
|
3
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
1
4
|
import type { IntegrationProviderRegistry } from '#core/providers/registry.js';
|
|
2
5
|
import type { IntegrationToolDispatcher } from './mcp-server.js';
|
|
3
6
|
export interface CreateIntegrationToolDispatcherParams {
|
|
4
7
|
registry: IntegrationProviderRegistry;
|
|
8
|
+
lease?: LeasedJobContext | undefined;
|
|
5
9
|
}
|
|
6
|
-
export
|
|
10
|
+
export interface IntegrationToolDispatcherDependencies {
|
|
11
|
+
logger?: typeof logger;
|
|
12
|
+
reportError?: typeof reportError;
|
|
13
|
+
}
|
|
14
|
+
export declare function createIntegrationToolDispatcher(params: CreateIntegrationToolDispatcherParams, dependencies?: IntegrationToolDispatcherDependencies): IntegrationToolDispatcher;
|
|
7
15
|
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../../src/presentation/routes/agent-tools-gateway/dispatch.ts"],"names":[],"mappings":"
|
|
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,17 @@
|
|
|
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
|
-
|
|
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
|
-
export function createIntegrationToolDispatcher(params) {
|
|
8
|
+
export function createIntegrationToolDispatcher(params, dependencies = {}) {
|
|
7
9
|
return (input)=>dispatchIntegrationToolCall({
|
|
8
10
|
...input,
|
|
9
|
-
registry: params.registry
|
|
11
|
+
registry: params.registry,
|
|
12
|
+
lease: params.lease,
|
|
13
|
+
logger: dependencies.logger ?? logger,
|
|
14
|
+
reportError: dependencies.reportError ?? reportError
|
|
10
15
|
});
|
|
11
16
|
}
|
|
12
17
|
async function dispatchIntegrationToolCall(input) {
|
|
@@ -26,20 +31,41 @@ async function dispatchIntegrationToolCall(input) {
|
|
|
26
31
|
});
|
|
27
32
|
} catch (error) {
|
|
28
33
|
const result = errorResult(error);
|
|
29
|
-
if (result.code === 'provider-unavailable') {
|
|
30
|
-
logger().error({
|
|
34
|
+
if (result.code === 'provider-unavailable' || result.code === 'unknown') {
|
|
35
|
+
input.logger().error({
|
|
36
|
+
...toolCallLogContext(input),
|
|
31
37
|
err: error,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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');
|
|
43
|
+
input.reportError(error, {
|
|
35
44
|
boundary: 'integration.agent-tool'
|
|
36
45
|
});
|
|
37
46
|
}
|
|
38
47
|
return toolError(result);
|
|
39
48
|
} finally{
|
|
40
|
-
await closeSession(session);
|
|
49
|
+
await closeSession(session, input.logger, input.reportError);
|
|
41
50
|
}
|
|
42
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
|
+
}
|
|
43
69
|
function agentToolCatalogEntry(input) {
|
|
44
70
|
const { tool, description, inputSchema, outputSchema } = input.authorizedTool;
|
|
45
71
|
return {
|
|
@@ -63,15 +89,15 @@ function agentToolCatalogEntry(input) {
|
|
|
63
89
|
}
|
|
64
90
|
};
|
|
65
91
|
}
|
|
66
|
-
async function closeSession(session) {
|
|
92
|
+
async function closeSession(session, loggerFactory, reportErrorFn) {
|
|
67
93
|
try {
|
|
68
94
|
await session?.close?.();
|
|
69
95
|
} catch (error) {
|
|
70
96
|
// Cleanup must not mask the tool result returned to the runner.
|
|
71
|
-
|
|
97
|
+
loggerFactory().error({
|
|
72
98
|
err: error
|
|
73
99
|
}, 'Failed to close integration agent tool session');
|
|
74
|
-
|
|
100
|
+
reportErrorFn(error, {
|
|
75
101
|
boundary: 'integration.agent-tool',
|
|
76
102
|
operation: 'close-session'
|
|
77
103
|
});
|
|
@@ -81,7 +107,13 @@ function errorResult(error) {
|
|
|
81
107
|
if (error instanceof IntegrationProviderError) {
|
|
82
108
|
return {
|
|
83
109
|
code: error.reason,
|
|
84
|
-
message:
|
|
110
|
+
message: error.message,
|
|
111
|
+
...error.retryAfterSeconds === undefined ? {} : {
|
|
112
|
+
retryAfterSeconds: error.retryAfterSeconds
|
|
113
|
+
},
|
|
114
|
+
...error.status === undefined ? {} : {
|
|
115
|
+
status: error.status
|
|
116
|
+
}
|
|
85
117
|
};
|
|
86
118
|
}
|
|
87
119
|
if (isTimeoutError(error)) {
|
|
@@ -97,13 +129,13 @@ function errorResult(error) {
|
|
|
97
129
|
};
|
|
98
130
|
}
|
|
99
131
|
return {
|
|
100
|
-
code: '
|
|
101
|
-
message: 'Integration
|
|
132
|
+
code: 'unknown',
|
|
133
|
+
message: 'Integration tool call failed'
|
|
102
134
|
};
|
|
103
135
|
}
|
|
104
136
|
function isTimeoutError(error) {
|
|
105
137
|
if (!(error instanceof Error)) return false;
|
|
106
|
-
return error.name === 'AbortError' ||
|
|
138
|
+
return error.name === 'AbortError' || timeoutErrorNamePattern.test(error.name) || error.name === 'McpError' && mcpRequestTimeoutMessagePattern.test(error.message);
|
|
107
139
|
}
|
|
108
140
|
function isCredentialError(error) {
|
|
109
141
|
if (!(error instanceof Error)) return false;
|
|
@@ -119,7 +151,13 @@ function toolError(params) {
|
|
|
119
151
|
}
|
|
120
152
|
],
|
|
121
153
|
structuredContent: {
|
|
122
|
-
code: params.code
|
|
154
|
+
code: params.code,
|
|
155
|
+
...params.retryAfterSeconds === undefined ? {} : {
|
|
156
|
+
retryAfterSeconds: params.retryAfterSeconds
|
|
157
|
+
},
|
|
158
|
+
...params.status === undefined ? {} : {
|
|
159
|
+
status: params.status
|
|
160
|
+
}
|
|
123
161
|
}
|
|
124
162
|
};
|
|
125
163
|
}
|
|
@@ -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\nconst timeoutErrorPattern = /timed?\\s*out|timeout/i;\nconst credentialErrorNamePattern = /Token|Credential|Secret|AccessToken/;\n\nexport function createIntegrationToolDispatcher(\n params: CreateIntegrationToolDispatcherParams,\n): IntegrationToolDispatcher {\n return (input) => dispatchIntegrationToolCall({...input, registry: params.registry});\n}\n\nasync function dispatchIntegrationToolCall(\n input: IntegrationToolDispatchInput & {registry: IntegrationProviderRegistry},\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 logger().error(\n {err: error, provider: input.authorizedTool.integration.provider},\n 'Integration agent tool provider was unavailable',\n );\n reportError(error, {boundary: 'integration.agent-tool'});\n }\n return toolError(result);\n } finally {\n await closeSession(session);\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(session: {close?(): Promise<void>} | undefined): Promise<void> {\n try {\n await session?.close?.();\n } catch (error) {\n // Cleanup must not mask the tool result returned to the runner.\n logger().error({err: error}, 'Failed to close integration agent tool session');\n reportError(error, {boundary: 'integration.agent-tool', operation: 'close-session'});\n }\n}\n\nfunction errorResult(error: unknown): {code: string; message: string} {\n if (error instanceof IntegrationProviderError) {\n return {\n code: error.reason,\n message: `Integration provider error: ${error.reason}`,\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: {code: string; message: string}): CallToolResult {\n return {\n isError: true,\n content: [{type: 'text', text: params.message}],\n structuredContent: {code: params.code},\n };\n}\n"],"names":["reportError","logger","IntegrationProviderError","timeoutErrorPattern","credentialErrorNamePattern","createIntegrationToolDispatcher","params","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","close","operation","reason","message","isTimeoutError","isCredentialError","Error","name","test","isError","content","type","text","structuredContent"],"mappings":"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"}
|
|
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,
|
|
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:
|
|
33
|
-
|
|
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
|
|
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;
|
|
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
|