@shipfox/api-agent-access 20.2.0 → 20.3.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 (38) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +16 -0
  5. package/dist/core/paged-tools.d.ts +15 -0
  6. package/dist/core/paged-tools.d.ts.map +1 -0
  7. package/dist/core/paged-tools.js +454 -0
  8. package/dist/core/paged-tools.js.map +1 -0
  9. package/dist/core/response.d.ts +22 -0
  10. package/dist/core/response.d.ts.map +1 -0
  11. package/dist/core/response.js +75 -0
  12. package/dist/core/response.js.map +1 -0
  13. package/dist/core/tools.d.ts +2 -0
  14. package/dist/core/tools.d.ts.map +1 -1
  15. package/dist/core/tools.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/presentation/mcp-server.d.ts.map +1 -1
  21. package/dist/presentation/mcp-server.js +23 -3
  22. package/dist/presentation/mcp-server.js.map +1 -1
  23. package/dist/presentation/routes.d.ts +10 -0
  24. package/dist/presentation/routes.d.ts.map +1 -1
  25. package/dist/presentation/routes.js +20 -3
  26. package/dist/presentation/routes.js.map +1 -1
  27. package/dist/tsconfig.test.tsbuildinfo +1 -1
  28. package/package.json +31 -14
  29. package/src/core/paged-tools.test.ts +519 -0
  30. package/src/core/paged-tools.ts +657 -0
  31. package/src/core/response.test.ts +65 -0
  32. package/src/core/response.ts +101 -0
  33. package/src/core/tools.ts +2 -0
  34. package/src/index.ts +11 -0
  35. package/src/presentation/mcp-server.test.ts +58 -0
  36. package/src/presentation/mcp-server.ts +25 -3
  37. package/src/presentation/routes.ts +37 -1
  38. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,75 @@
1
+ import { AGENT_ACCESS_RESPONSE_MAX_BYTES } from '@shipfox/api-agent-access-dto';
2
+ import { agentAccessError } from './envelope.js';
3
+ const utf8Encoder = new TextEncoder();
4
+ export function truncateAgentAccessUtf8(value, maxBytes) {
5
+ const totalBytes = utf8Encoder.encode(value).byteLength;
6
+ if (totalBytes <= maxBytes) return {
7
+ value,
8
+ truncated: false,
9
+ totalBytes
10
+ };
11
+ if (maxBytes <= 0) return {
12
+ value: '',
13
+ truncated: true,
14
+ totalBytes
15
+ };
16
+ let bytes = 0;
17
+ let result = '';
18
+ for (const codePoint of value){
19
+ const codePointBytes = utf8Encoder.encode(codePoint).byteLength;
20
+ if (bytes + codePointBytes > maxBytes) break;
21
+ result += codePoint;
22
+ bytes += codePointBytes;
23
+ }
24
+ return {
25
+ value: result,
26
+ truncated: true,
27
+ totalBytes
28
+ };
29
+ }
30
+ export function serializedAgentAccessEnvelopeByteLength(envelope) {
31
+ const serialized = JSON.stringify(envelope);
32
+ if (serialized === undefined) throw new Error('Agent-access envelope is not serializable');
33
+ return utf8Encoder.encode(serialized).byteLength;
34
+ }
35
+ /**
36
+ * Fits a paged success response without reusing a producer cursor that points past dropped rows.
37
+ * The cursor is always rebuilt from the final retained item.
38
+ */ export function reducePagedAgentAccessResponse(params) {
39
+ const maxBytes = params.maxBytes ?? AGENT_ACCESS_RESPONSE_MAX_BYTES;
40
+ const initialBytes = serializedAgentAccessEnvelopeByteLength(params.envelope);
41
+ if (initialBytes <= maxBytes) return params.envelope;
42
+ if (!params.envelope.ok || !isRecord(params.envelope.result)) {
43
+ return agentAccessError('content-too-large');
44
+ }
45
+ const itemCounts = params.items.length === 0 ? [
46
+ 0
47
+ ] : Array.from({
48
+ length: Math.max(0, params.items.length - 1)
49
+ }, (_, index)=>params.items.length - index - 1);
50
+ for (const itemCount of itemCounts){
51
+ const retained = params.items.slice(0, itemCount);
52
+ const last = retained.at(-1);
53
+ const nextCursor = last === undefined ? null : params.cursorForItem(last, itemCount - 1);
54
+ const candidate = {
55
+ ...params.envelope,
56
+ result: {
57
+ ...params.envelope.result,
58
+ [params.itemKey]: retained,
59
+ next_cursor: nextCursor
60
+ },
61
+ response_truncated: true,
62
+ response_total_bytes: initialBytes
63
+ };
64
+ if (serializedAgentAccessEnvelopeByteLength(candidate) <= maxBytes) return candidate;
65
+ }
66
+ return agentAccessError('content-too-large');
67
+ }
68
+ export function fitAgentAccessResponseToCeiling(envelope, maxBytes = AGENT_ACCESS_RESPONSE_MAX_BYTES) {
69
+ return serializedAgentAccessEnvelopeByteLength(envelope) <= maxBytes ? envelope : agentAccessError('content-too-large');
70
+ }
71
+ function isRecord(value) {
72
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
73
+ }
74
+
75
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/response.ts"],"sourcesContent":["import {\n AGENT_ACCESS_RESPONSE_MAX_BYTES,\n type AgentAccessEnvelopeDto,\n} from '@shipfox/api-agent-access-dto';\nimport {agentAccessError} from './envelope.js';\n\nconst utf8Encoder = new TextEncoder();\n\nexport interface AgentAccessUtf8Truncation {\n value: string;\n truncated: boolean;\n totalBytes: number;\n}\n\nexport function truncateAgentAccessUtf8(\n value: string,\n maxBytes: number,\n): AgentAccessUtf8Truncation {\n const totalBytes = utf8Encoder.encode(value).byteLength;\n if (totalBytes <= maxBytes) return {value, truncated: false, totalBytes};\n if (maxBytes <= 0) return {value: '', truncated: true, totalBytes};\n\n let bytes = 0;\n let result = '';\n for (const codePoint of value) {\n const codePointBytes = utf8Encoder.encode(codePoint).byteLength;\n if (bytes + codePointBytes > maxBytes) break;\n result += codePoint;\n bytes += codePointBytes;\n }\n\n return {value: result, truncated: true, totalBytes};\n}\n\nexport function serializedAgentAccessEnvelopeByteLength(envelope: AgentAccessEnvelopeDto): number {\n const serialized = JSON.stringify(envelope);\n if (serialized === undefined) throw new Error('Agent-access envelope is not serializable');\n return utf8Encoder.encode(serialized).byteLength;\n}\n\nexport interface ReducePagedAgentAccessResponseParams {\n envelope: AgentAccessEnvelopeDto;\n itemKey: string;\n items: readonly Record<string, unknown>[];\n cursorForItem: (item: Record<string, unknown>, index: number) => string;\n maxBytes?: number | undefined;\n}\n\n/**\n * Fits a paged success response without reusing a producer cursor that points past dropped rows.\n * The cursor is always rebuilt from the final retained item.\n */\nexport function reducePagedAgentAccessResponse(\n params: ReducePagedAgentAccessResponseParams,\n): AgentAccessEnvelopeDto {\n const maxBytes = params.maxBytes ?? AGENT_ACCESS_RESPONSE_MAX_BYTES;\n const initialBytes = serializedAgentAccessEnvelopeByteLength(params.envelope);\n if (initialBytes <= maxBytes) return params.envelope;\n if (!params.envelope.ok || !isRecord(params.envelope.result)) {\n return agentAccessError('content-too-large');\n }\n\n const itemCounts =\n params.items.length === 0\n ? [0]\n : Array.from(\n {length: Math.max(0, params.items.length - 1)},\n (_, index) => params.items.length - index - 1,\n );\n for (const itemCount of itemCounts) {\n const retained = params.items.slice(0, itemCount);\n const last = retained.at(-1);\n const nextCursor = last === undefined ? null : params.cursorForItem(last, itemCount - 1);\n const candidate: AgentAccessEnvelopeDto = {\n ...params.envelope,\n result: {\n ...params.envelope.result,\n [params.itemKey]: retained,\n next_cursor: nextCursor,\n },\n response_truncated: true,\n response_total_bytes: initialBytes,\n };\n if (serializedAgentAccessEnvelopeByteLength(candidate) <= maxBytes) return candidate;\n }\n\n return agentAccessError('content-too-large');\n}\n\nexport function fitAgentAccessResponseToCeiling(\n envelope: AgentAccessEnvelopeDto,\n maxBytes = AGENT_ACCESS_RESPONSE_MAX_BYTES,\n): AgentAccessEnvelopeDto {\n return serializedAgentAccessEnvelopeByteLength(envelope) <= maxBytes\n ? envelope\n : agentAccessError('content-too-large');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["AGENT_ACCESS_RESPONSE_MAX_BYTES","agentAccessError","utf8Encoder","TextEncoder","truncateAgentAccessUtf8","value","maxBytes","totalBytes","encode","byteLength","truncated","bytes","result","codePoint","codePointBytes","serializedAgentAccessEnvelopeByteLength","envelope","serialized","JSON","stringify","undefined","Error","reducePagedAgentAccessResponse","params","initialBytes","ok","isRecord","itemCounts","items","length","Array","from","Math","max","_","index","itemCount","retained","slice","last","at","nextCursor","cursorForItem","candidate","itemKey","next_cursor","response_truncated","response_total_bytes","fitAgentAccessResponseToCeiling","isArray"],"mappings":"AAAA,SACEA,+BAA+B,QAE1B,gCAAgC;AACvC,SAAQC,gBAAgB,QAAO,gBAAgB;AAE/C,MAAMC,cAAc,IAAIC;AAQxB,OAAO,SAASC,wBACdC,KAAa,EACbC,QAAgB;IAEhB,MAAMC,aAAaL,YAAYM,MAAM,CAACH,OAAOI,UAAU;IACvD,IAAIF,cAAcD,UAAU,OAAO;QAACD;QAAOK,WAAW;QAAOH;IAAU;IACvE,IAAID,YAAY,GAAG,OAAO;QAACD,OAAO;QAAIK,WAAW;QAAMH;IAAU;IAEjE,IAAII,QAAQ;IACZ,IAAIC,SAAS;IACb,KAAK,MAAMC,aAAaR,MAAO;QAC7B,MAAMS,iBAAiBZ,YAAYM,MAAM,CAACK,WAAWJ,UAAU;QAC/D,IAAIE,QAAQG,iBAAiBR,UAAU;QACvCM,UAAUC;QACVF,SAASG;IACX;IAEA,OAAO;QAACT,OAAOO;QAAQF,WAAW;QAAMH;IAAU;AACpD;AAEA,OAAO,SAASQ,wCAAwCC,QAAgC;IACtF,MAAMC,aAAaC,KAAKC,SAAS,CAACH;IAClC,IAAIC,eAAeG,WAAW,MAAM,IAAIC,MAAM;IAC9C,OAAOnB,YAAYM,MAAM,CAACS,YAAYR,UAAU;AAClD;AAUA;;;CAGC,GACD,OAAO,SAASa,+BACdC,MAA4C;IAE5C,MAAMjB,WAAWiB,OAAOjB,QAAQ,IAAIN;IACpC,MAAMwB,eAAeT,wCAAwCQ,OAAOP,QAAQ;IAC5E,IAAIQ,gBAAgBlB,UAAU,OAAOiB,OAAOP,QAAQ;IACpD,IAAI,CAACO,OAAOP,QAAQ,CAACS,EAAE,IAAI,CAACC,SAASH,OAAOP,QAAQ,CAACJ,MAAM,GAAG;QAC5D,OAAOX,iBAAiB;IAC1B;IAEA,MAAM0B,aACJJ,OAAOK,KAAK,CAACC,MAAM,KAAK,IACpB;QAAC;KAAE,GACHC,MAAMC,IAAI,CACR;QAACF,QAAQG,KAAKC,GAAG,CAAC,GAAGV,OAAOK,KAAK,CAACC,MAAM,GAAG;IAAE,GAC7C,CAACK,GAAGC,QAAUZ,OAAOK,KAAK,CAACC,MAAM,GAAGM,QAAQ;IAEpD,KAAK,MAAMC,aAAaT,WAAY;QAClC,MAAMU,WAAWd,OAAOK,KAAK,CAACU,KAAK,CAAC,GAAGF;QACvC,MAAMG,OAAOF,SAASG,EAAE,CAAC,CAAC;QAC1B,MAAMC,aAAaF,SAASnB,YAAY,OAAOG,OAAOmB,aAAa,CAACH,MAAMH,YAAY;QACtF,MAAMO,YAAoC;YACxC,GAAGpB,OAAOP,QAAQ;YAClBJ,QAAQ;gBACN,GAAGW,OAAOP,QAAQ,CAACJ,MAAM;gBACzB,CAACW,OAAOqB,OAAO,CAAC,EAAEP;gBAClBQ,aAAaJ;YACf;YACAK,oBAAoB;YACpBC,sBAAsBvB;QACxB;QACA,IAAIT,wCAAwC4B,cAAcrC,UAAU,OAAOqC;IAC7E;IAEA,OAAO1C,iBAAiB;AAC1B;AAEA,OAAO,SAAS+C,gCACdhC,QAAgC,EAChCV,WAAWN,+BAA+B;IAE1C,OAAOe,wCAAwCC,aAAaV,WACxDU,WACAf,iBAAiB;AACvB;AAEA,SAASyB,SAASrB,KAAc;IAC9B,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACyB,MAAMmB,OAAO,CAAC5C;AACvE"}
@@ -9,10 +9,12 @@ export interface AgentAccessTool {
9
9
  description: string;
10
10
  inputSchema: AgentAccessObjectSchema;
11
11
  outputSchema: AgentAccessObjectSchema;
12
+ validateInput?: ((input: unknown) => boolean) | undefined;
12
13
  annotations: {
13
14
  readonly readOnlyHint: true;
14
15
  };
15
16
  execute: (call: AgentAccessToolCall) => Promise<AgentAccessEnvelopeDto> | AgentAccessEnvelopeDto;
17
+ validateResult?: ((result: unknown) => boolean) | undefined;
16
18
  }
17
19
  export type AgentAccessToolMap = ReadonlyMap<string, AgentAccessTool>;
18
20
  export declare function createAgentAccessToolMap(tools: readonly AgentAccessTool[]): AgentAccessToolMap;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/core/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,uBAAuB,CAAC;IACrC,YAAY,EAAE,uBAAuB,CAAC;IACtC,WAAW,EAAE;QAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAA;KAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,CAAC;CAClG;AAED,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEtE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,kBAAkB,CAO9F;AAED,kGAAkG;AAClG,wBAAgB,4BAA4B,IAAI,eAAe,CA+B9D"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/core/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,uBAAuB,CAAC;IACrC,YAAY,EAAE,uBAAuB,CAAC;IACtC,aAAa,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IAC1D,WAAW,EAAE;QAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAA;KAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,mBAAmB,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,CAAC;IACjG,cAAc,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEtE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,GAAG,kBAAkB,CAO9F;AAED,kGAAkG;AAClG,wBAAgB,4BAA4B,IAAI,eAAe,CA+B9D"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/tools.ts"],"sourcesContent":["import {\n type AgentAccessEnvelopeDto,\n type AgentAccessObjectSchema,\n agentAccessOutputSchema,\n} from '@shipfox/api-agent-access-dto';\nimport type {AgentAccessContext} from '@shipfox/api-auth-context';\nimport {AGENT_ACCESS_FIXTURE_TOOL_NAME} from '#constants.js';\nimport {agentAccessError, agentAccessSuccess} from './envelope.js';\n\nexport interface AgentAccessToolCall {\n context: AgentAccessContext;\n arguments: Record<string, unknown>;\n}\n\nexport interface AgentAccessTool {\n name: string;\n description: string;\n inputSchema: AgentAccessObjectSchema;\n outputSchema: AgentAccessObjectSchema;\n annotations: {readonly readOnlyHint: true};\n execute: (call: AgentAccessToolCall) => Promise<AgentAccessEnvelopeDto> | AgentAccessEnvelopeDto;\n}\n\nexport type AgentAccessToolMap = ReadonlyMap<string, AgentAccessTool>;\n\nexport function createAgentAccessToolMap(tools: readonly AgentAccessTool[]): AgentAccessToolMap {\n const table = new Map<string, AgentAccessTool>();\n for (const tool of tools) {\n if (table.has(tool.name)) throw new Error(`Duplicate agent-access tool: ${tool.name}`);\n table.set(tool.name, tool);\n }\n return table;\n}\n\n/** A deterministic tool used by gateway contract tests; no production tool is registered here. */\nexport function createAgentAccessFixtureTool(): AgentAccessTool {\n return {\n name: AGENT_ACCESS_FIXTURE_TOOL_NAME,\n description: 'Return a deterministic response from the dormant agent-access gateway fixture.',\n inputSchema: {\n type: 'object',\n properties: {message: {type: 'string', maxLength: 256}},\n required: ['message'],\n additionalProperties: false,\n },\n outputSchema: agentAccessOutputSchema({\n type: 'object',\n properties: {message: {type: 'string'}},\n required: ['message'],\n additionalProperties: false,\n }),\n annotations: {readOnlyHint: true},\n execute: ({arguments: input}) => {\n const message = input.message;\n if (\n Object.keys(input).some((key) => key !== 'message') ||\n typeof message !== 'string' ||\n [...message].length > 256\n ) {\n return agentAccessError('invalid-request', {\n message: 'message must be a string of at most 256 characters with no extra properties',\n });\n }\n return agentAccessSuccess({message});\n },\n };\n}\n"],"names":["agentAccessOutputSchema","AGENT_ACCESS_FIXTURE_TOOL_NAME","agentAccessError","agentAccessSuccess","createAgentAccessToolMap","tools","table","Map","tool","has","name","Error","set","createAgentAccessFixtureTool","description","inputSchema","type","properties","message","maxLength","required","additionalProperties","outputSchema","annotations","readOnlyHint","execute","arguments","input","Object","keys","some","key","length"],"mappings":"AAAA,SAGEA,uBAAuB,QAClB,gCAAgC;AAEvC,SAAQC,8BAA8B,QAAO,gBAAgB;AAC7D,SAAQC,gBAAgB,EAAEC,kBAAkB,QAAO,gBAAgB;AAkBnE,OAAO,SAASC,yBAAyBC,KAAiC;IACxE,MAAMC,QAAQ,IAAIC;IAClB,KAAK,MAAMC,QAAQH,MAAO;QACxB,IAAIC,MAAMG,GAAG,CAACD,KAAKE,IAAI,GAAG,MAAM,IAAIC,MAAM,CAAC,6BAA6B,EAAEH,KAAKE,IAAI,EAAE;QACrFJ,MAAMM,GAAG,CAACJ,KAAKE,IAAI,EAAEF;IACvB;IACA,OAAOF;AACT;AAEA,gGAAgG,GAChG,OAAO,SAASO;IACd,OAAO;QACLH,MAAMT;QACNa,aAAa;QACbC,aAAa;YACXC,MAAM;YACNC,YAAY;gBAACC,SAAS;oBAACF,MAAM;oBAAUG,WAAW;gBAAG;YAAC;YACtDC,UAAU;gBAAC;aAAU;YACrBC,sBAAsB;QACxB;QACAC,cAActB,wBAAwB;YACpCgB,MAAM;YACNC,YAAY;gBAACC,SAAS;oBAACF,MAAM;gBAAQ;YAAC;YACtCI,UAAU;gBAAC;aAAU;YACrBC,sBAAsB;QACxB;QACAE,aAAa;YAACC,cAAc;QAAI;QAChCC,SAAS,CAAC,EAACC,WAAWC,KAAK,EAAC;YAC1B,MAAMT,UAAUS,MAAMT,OAAO;YAC7B,IACEU,OAAOC,IAAI,CAACF,OAAOG,IAAI,CAAC,CAACC,MAAQA,QAAQ,cACzC,OAAOb,YAAY,YACnB;mBAAIA;aAAQ,CAACc,MAAM,GAAG,KACtB;gBACA,OAAO9B,iBAAiB,mBAAmB;oBACzCgB,SAAS;gBACX;YACF;YACA,OAAOf,mBAAmB;gBAACe;YAAO;QACpC;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/core/tools.ts"],"sourcesContent":["import {\n type AgentAccessEnvelopeDto,\n type AgentAccessObjectSchema,\n agentAccessOutputSchema,\n} from '@shipfox/api-agent-access-dto';\nimport type {AgentAccessContext} from '@shipfox/api-auth-context';\nimport {AGENT_ACCESS_FIXTURE_TOOL_NAME} from '#constants.js';\nimport {agentAccessError, agentAccessSuccess} from './envelope.js';\n\nexport interface AgentAccessToolCall {\n context: AgentAccessContext;\n arguments: Record<string, unknown>;\n}\n\nexport interface AgentAccessTool {\n name: string;\n description: string;\n inputSchema: AgentAccessObjectSchema;\n outputSchema: AgentAccessObjectSchema;\n validateInput?: ((input: unknown) => boolean) | undefined;\n annotations: {readonly readOnlyHint: true};\n execute: (call: AgentAccessToolCall) => Promise<AgentAccessEnvelopeDto> | AgentAccessEnvelopeDto;\n validateResult?: ((result: unknown) => boolean) | undefined;\n}\n\nexport type AgentAccessToolMap = ReadonlyMap<string, AgentAccessTool>;\n\nexport function createAgentAccessToolMap(tools: readonly AgentAccessTool[]): AgentAccessToolMap {\n const table = new Map<string, AgentAccessTool>();\n for (const tool of tools) {\n if (table.has(tool.name)) throw new Error(`Duplicate agent-access tool: ${tool.name}`);\n table.set(tool.name, tool);\n }\n return table;\n}\n\n/** A deterministic tool used by gateway contract tests; no production tool is registered here. */\nexport function createAgentAccessFixtureTool(): AgentAccessTool {\n return {\n name: AGENT_ACCESS_FIXTURE_TOOL_NAME,\n description: 'Return a deterministic response from the dormant agent-access gateway fixture.',\n inputSchema: {\n type: 'object',\n properties: {message: {type: 'string', maxLength: 256}},\n required: ['message'],\n additionalProperties: false,\n },\n outputSchema: agentAccessOutputSchema({\n type: 'object',\n properties: {message: {type: 'string'}},\n required: ['message'],\n additionalProperties: false,\n }),\n annotations: {readOnlyHint: true},\n execute: ({arguments: input}) => {\n const message = input.message;\n if (\n Object.keys(input).some((key) => key !== 'message') ||\n typeof message !== 'string' ||\n [...message].length > 256\n ) {\n return agentAccessError('invalid-request', {\n message: 'message must be a string of at most 256 characters with no extra properties',\n });\n }\n return agentAccessSuccess({message});\n },\n };\n}\n"],"names":["agentAccessOutputSchema","AGENT_ACCESS_FIXTURE_TOOL_NAME","agentAccessError","agentAccessSuccess","createAgentAccessToolMap","tools","table","Map","tool","has","name","Error","set","createAgentAccessFixtureTool","description","inputSchema","type","properties","message","maxLength","required","additionalProperties","outputSchema","annotations","readOnlyHint","execute","arguments","input","Object","keys","some","key","length"],"mappings":"AAAA,SAGEA,uBAAuB,QAClB,gCAAgC;AAEvC,SAAQC,8BAA8B,QAAO,gBAAgB;AAC7D,SAAQC,gBAAgB,EAAEC,kBAAkB,QAAO,gBAAgB;AAoBnE,OAAO,SAASC,yBAAyBC,KAAiC;IACxE,MAAMC,QAAQ,IAAIC;IAClB,KAAK,MAAMC,QAAQH,MAAO;QACxB,IAAIC,MAAMG,GAAG,CAACD,KAAKE,IAAI,GAAG,MAAM,IAAIC,MAAM,CAAC,6BAA6B,EAAEH,KAAKE,IAAI,EAAE;QACrFJ,MAAMM,GAAG,CAACJ,KAAKE,IAAI,EAAEF;IACvB;IACA,OAAOF;AACT;AAEA,gGAAgG,GAChG,OAAO,SAASO;IACd,OAAO;QACLH,MAAMT;QACNa,aAAa;QACbC,aAAa;YACXC,MAAM;YACNC,YAAY;gBAACC,SAAS;oBAACF,MAAM;oBAAUG,WAAW;gBAAG;YAAC;YACtDC,UAAU;gBAAC;aAAU;YACrBC,sBAAsB;QACxB;QACAC,cAActB,wBAAwB;YACpCgB,MAAM;YACNC,YAAY;gBAACC,SAAS;oBAACF,MAAM;gBAAQ;YAAC;YACtCI,UAAU;gBAAC;aAAU;YACrBC,sBAAsB;QACxB;QACAE,aAAa;YAACC,cAAc;QAAI;QAChCC,SAAS,CAAC,EAACC,WAAWC,KAAK,EAAC;YAC1B,MAAMT,UAAUS,MAAMT,OAAO;YAC7B,IACEU,OAAOC,IAAI,CAACF,OAAOG,IAAI,CAAC,CAACC,MAAQA,QAAQ,cACzC,OAAOb,YAAY,YACnB;mBAAIA;aAAQ,CAACc,MAAM,GAAG,KACtB;gBACA,OAAO9B,iBAAiB,mBAAmB;oBACzCgB,SAAS;gBACX;YACF;YACA,OAAOf,mBAAmB;gBAACe;YAAO;QACpC;IACF;AACF"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { AGENT_ACCESS_FIXTURE_TOOL_NAME, AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_MCP_SERVER_NAME, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH, AGENT_ACCESS_TOOL_CALL_LIMIT, AGENT_ACCESS_TOOL_CALL_WINDOW_MS, } from '#constants.js';
2
2
  export { agentAccessError, agentAccessSuccess, parseAgentAccessEnvelope, serializeAgentAccessEnvelope, } from '#core/envelope.js';
3
+ export { type AgentAccessPagedToolsOptions, createAgentAccessTools, } from '#core/paged-tools.js';
3
4
  export { type AgentAccessRateLimitDecision, type AgentAccessRateLimiter, type CreateAgentAccessRateLimiterOptions, createAgentAccessRateLimiter, } from '#core/rate-limiter.js';
5
+ export { type AgentAccessUtf8Truncation, fitAgentAccessResponseToCeiling, reducePagedAgentAccessResponse, serializedAgentAccessEnvelopeByteLength, truncateAgentAccessUtf8, } from '#core/response.js';
4
6
  export { type AgentAccessTool, type AgentAccessToolCall, type AgentAccessToolMap, createAgentAccessFixtureTool, createAgentAccessToolMap, } from '#core/tools.js';
5
7
  export { type AgentAccessAuthFailureReason, type AgentAccessToolCallOutcome, recordAgentAccessAuthFailure, recordAgentAccessToolCall, } from '#metrics/index.js';
6
8
  export { type AgentAccessToolCallAuditRecord, type AgentAccessToolCallRecorder, type CreateAgentAccessToolCallRecorderOptions, createAgentAccessToolCallRecorder, } from '#presentation/audit.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,6CAA6C,EAC7C,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,mCAAmC,EACxC,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,wCAAwC,EAC7C,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,+BAA+B,EACpC,yBAAyB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,4BAA4B,EAAC,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,6CAA6C,EAC7C,4BAA4B,EAC5B,gCAAgC,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,wBAAwB,EACxB,4BAA4B,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,4BAA4B,EACjC,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,sBAAsB,EAC3B,KAAK,mCAAmC,EACxC,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,8BAA8B,EAC9B,uCAAuC,EACvC,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,wCAAwC,EAC7C,iCAAiC,GAClC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,+BAA+B,EACpC,yBAAyB,GAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,EACjB,KAAK,8BAA8B,EACnC,uBAAuB,GACxB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,4BAA4B,EAAC,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export { AGENT_ACCESS_FIXTURE_TOOL_NAME, AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_MCP_SERVER_NAME, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH, AGENT_ACCESS_TOOL_CALL_LIMIT, AGENT_ACCESS_TOOL_CALL_WINDOW_MS } from '#constants.js';
2
2
  export { agentAccessError, agentAccessSuccess, parseAgentAccessEnvelope, serializeAgentAccessEnvelope } from '#core/envelope.js';
3
+ export { createAgentAccessTools } from '#core/paged-tools.js';
3
4
  export { createAgentAccessRateLimiter } from '#core/rate-limiter.js';
5
+ export { fitAgentAccessResponseToCeiling, reducePagedAgentAccessResponse, serializedAgentAccessEnvelopeByteLength, truncateAgentAccessUtf8 } from '#core/response.js';
4
6
  export { createAgentAccessFixtureTool, createAgentAccessToolMap } from '#core/tools.js';
5
7
  export { recordAgentAccessAuthFailure, recordAgentAccessToolCall } from '#metrics/index.js';
6
8
  export { createAgentAccessToolCallRecorder } from '#presentation/audit.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n AGENT_ACCESS_FIXTURE_TOOL_NAME,\n AGENT_ACCESS_MCP_INSTRUCTIONS,\n AGENT_ACCESS_MCP_PATH,\n AGENT_ACCESS_MCP_SERVER_NAME,\n AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH,\n AGENT_ACCESS_TOOL_CALL_LIMIT,\n AGENT_ACCESS_TOOL_CALL_WINDOW_MS,\n} from '#constants.js';\nexport {\n agentAccessError,\n agentAccessSuccess,\n parseAgentAccessEnvelope,\n serializeAgentAccessEnvelope,\n} from '#core/envelope.js';\nexport {\n type AgentAccessRateLimitDecision,\n type AgentAccessRateLimiter,\n type CreateAgentAccessRateLimiterOptions,\n createAgentAccessRateLimiter,\n} from '#core/rate-limiter.js';\nexport {\n type AgentAccessTool,\n type AgentAccessToolCall,\n type AgentAccessToolMap,\n createAgentAccessFixtureTool,\n createAgentAccessToolMap,\n} from '#core/tools.js';\nexport {\n type AgentAccessAuthFailureReason,\n type AgentAccessToolCallOutcome,\n recordAgentAccessAuthFailure,\n recordAgentAccessToolCall,\n} from '#metrics/index.js';\nexport {\n type AgentAccessToolCallAuditRecord,\n type AgentAccessToolCallRecorder,\n type CreateAgentAccessToolCallRecorderOptions,\n createAgentAccessToolCallRecorder,\n} from '#presentation/audit.js';\nexport {\n type BuildAgentAccessMcpServerParams,\n buildAgentAccessMcpServer,\n} from '#presentation/mcp-server.js';\nexport {\n type CreateAgentAccessRoutesOptions,\n createAgentAccessRoutes,\n} from '#presentation/routes.js';\nexport {\n agentAccessModule,\n type CreateAgentAccessModuleOptions,\n createAgentAccessModule,\n} from './module.js';\nexport {AGENT_ACCESS_PACKAGE_VERSION} from './version.js';\n"],"names":["AGENT_ACCESS_FIXTURE_TOOL_NAME","AGENT_ACCESS_MCP_INSTRUCTIONS","AGENT_ACCESS_MCP_PATH","AGENT_ACCESS_MCP_SERVER_NAME","AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH","AGENT_ACCESS_TOOL_CALL_LIMIT","AGENT_ACCESS_TOOL_CALL_WINDOW_MS","agentAccessError","agentAccessSuccess","parseAgentAccessEnvelope","serializeAgentAccessEnvelope","createAgentAccessRateLimiter","createAgentAccessFixtureTool","createAgentAccessToolMap","recordAgentAccessAuthFailure","recordAgentAccessToolCall","createAgentAccessToolCallRecorder","buildAgentAccessMcpServer","createAgentAccessRoutes","agentAccessModule","createAgentAccessModule","AGENT_ACCESS_PACKAGE_VERSION"],"mappings":"AAAA,SACEA,8BAA8B,EAC9BC,6BAA6B,EAC7BC,qBAAqB,EACrBC,4BAA4B,EAC5BC,6CAA6C,EAC7CC,4BAA4B,EAC5BC,gCAAgC,QAC3B,gBAAgB;AACvB,SACEC,gBAAgB,EAChBC,kBAAkB,EAClBC,wBAAwB,EACxBC,4BAA4B,QACvB,oBAAoB;AAC3B,SAIEC,4BAA4B,QACvB,wBAAwB;AAC/B,SAIEC,4BAA4B,EAC5BC,wBAAwB,QACnB,iBAAiB;AACxB,SAGEC,4BAA4B,EAC5BC,yBAAyB,QACpB,oBAAoB;AAC3B,SAIEC,iCAAiC,QAC5B,yBAAyB;AAChC,SAEEC,yBAAyB,QACpB,8BAA8B;AACrC,SAEEC,uBAAuB,QAClB,0BAA0B;AACjC,SACEC,iBAAiB,EAEjBC,uBAAuB,QAClB,cAAc;AACrB,SAAQC,4BAA4B,QAAO,eAAe"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export {\n AGENT_ACCESS_FIXTURE_TOOL_NAME,\n AGENT_ACCESS_MCP_INSTRUCTIONS,\n AGENT_ACCESS_MCP_PATH,\n AGENT_ACCESS_MCP_SERVER_NAME,\n AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH,\n AGENT_ACCESS_TOOL_CALL_LIMIT,\n AGENT_ACCESS_TOOL_CALL_WINDOW_MS,\n} from '#constants.js';\nexport {\n agentAccessError,\n agentAccessSuccess,\n parseAgentAccessEnvelope,\n serializeAgentAccessEnvelope,\n} from '#core/envelope.js';\nexport {\n type AgentAccessPagedToolsOptions,\n createAgentAccessTools,\n} from '#core/paged-tools.js';\nexport {\n type AgentAccessRateLimitDecision,\n type AgentAccessRateLimiter,\n type CreateAgentAccessRateLimiterOptions,\n createAgentAccessRateLimiter,\n} from '#core/rate-limiter.js';\nexport {\n type AgentAccessUtf8Truncation,\n fitAgentAccessResponseToCeiling,\n reducePagedAgentAccessResponse,\n serializedAgentAccessEnvelopeByteLength,\n truncateAgentAccessUtf8,\n} from '#core/response.js';\nexport {\n type AgentAccessTool,\n type AgentAccessToolCall,\n type AgentAccessToolMap,\n createAgentAccessFixtureTool,\n createAgentAccessToolMap,\n} from '#core/tools.js';\nexport {\n type AgentAccessAuthFailureReason,\n type AgentAccessToolCallOutcome,\n recordAgentAccessAuthFailure,\n recordAgentAccessToolCall,\n} from '#metrics/index.js';\nexport {\n type AgentAccessToolCallAuditRecord,\n type AgentAccessToolCallRecorder,\n type CreateAgentAccessToolCallRecorderOptions,\n createAgentAccessToolCallRecorder,\n} from '#presentation/audit.js';\nexport {\n type BuildAgentAccessMcpServerParams,\n buildAgentAccessMcpServer,\n} from '#presentation/mcp-server.js';\nexport {\n type CreateAgentAccessRoutesOptions,\n createAgentAccessRoutes,\n} from '#presentation/routes.js';\nexport {\n agentAccessModule,\n type CreateAgentAccessModuleOptions,\n createAgentAccessModule,\n} from './module.js';\nexport {AGENT_ACCESS_PACKAGE_VERSION} from './version.js';\n"],"names":["AGENT_ACCESS_FIXTURE_TOOL_NAME","AGENT_ACCESS_MCP_INSTRUCTIONS","AGENT_ACCESS_MCP_PATH","AGENT_ACCESS_MCP_SERVER_NAME","AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH","AGENT_ACCESS_TOOL_CALL_LIMIT","AGENT_ACCESS_TOOL_CALL_WINDOW_MS","agentAccessError","agentAccessSuccess","parseAgentAccessEnvelope","serializeAgentAccessEnvelope","createAgentAccessTools","createAgentAccessRateLimiter","fitAgentAccessResponseToCeiling","reducePagedAgentAccessResponse","serializedAgentAccessEnvelopeByteLength","truncateAgentAccessUtf8","createAgentAccessFixtureTool","createAgentAccessToolMap","recordAgentAccessAuthFailure","recordAgentAccessToolCall","createAgentAccessToolCallRecorder","buildAgentAccessMcpServer","createAgentAccessRoutes","agentAccessModule","createAgentAccessModule","AGENT_ACCESS_PACKAGE_VERSION"],"mappings":"AAAA,SACEA,8BAA8B,EAC9BC,6BAA6B,EAC7BC,qBAAqB,EACrBC,4BAA4B,EAC5BC,6CAA6C,EAC7CC,4BAA4B,EAC5BC,gCAAgC,QAC3B,gBAAgB;AACvB,SACEC,gBAAgB,EAChBC,kBAAkB,EAClBC,wBAAwB,EACxBC,4BAA4B,QACvB,oBAAoB;AAC3B,SAEEC,sBAAsB,QACjB,uBAAuB;AAC9B,SAIEC,4BAA4B,QACvB,wBAAwB;AAC/B,SAEEC,+BAA+B,EAC/BC,8BAA8B,EAC9BC,uCAAuC,EACvCC,uBAAuB,QAClB,oBAAoB;AAC3B,SAIEC,4BAA4B,EAC5BC,wBAAwB,QACnB,iBAAiB;AACxB,SAGEC,4BAA4B,EAC5BC,yBAAyB,QACpB,oBAAoB;AAC3B,SAIEC,iCAAiC,QAC5B,yBAAyB;AAChC,SAEEC,yBAAyB,QACpB,8BAA8B;AACrC,SAEEC,uBAAuB,QAClB,0BAA0B;AACjC,SACEC,iBAAiB,EAEjBC,uBAAuB,QAClB,cAAc;AACrB,SAAQC,4BAA4B,QAAO,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/presentation/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAOjE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAKlE,OAAO,EAAC,KAAK,sBAAsB,EAA+B,MAAM,uBAAuB,CAAC;AAChG,OAAO,EACL,KAAK,eAAe,EAIrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAC,KAAK,2BAA2B,EAAoC,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACjD,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACtD;AAID,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,+BAA+B,GAAG,MAAM,CA0CzF"}
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/presentation/mcp-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAOjE,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,2BAA2B,CAAC;AAKlE,OAAO,EAAC,KAAK,sBAAsB,EAA+B,MAAM,uBAAuB,CAAC;AAEhG,OAAO,EACL,KAAK,eAAe,EAIrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAC,KAAK,2BAA2B,EAAoC,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,kBAAkB,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACjD,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACtD;AAID,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,+BAA+B,GAAG,MAAM,CA0CzF"}
@@ -6,6 +6,7 @@ import { logger } from '@shipfox/node-opentelemetry';
6
6
  import { AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_SERVER_NAME } from '#constants.js';
7
7
  import { agentAccessError, serializeAgentAccessEnvelope } from '#core/envelope.js';
8
8
  import { createAgentAccessRateLimiter } from '#core/rate-limiter.js';
9
+ import { fitAgentAccessResponseToCeiling } from '#core/response.js';
9
10
  import { createAgentAccessFixtureTool, createAgentAccessToolMap } from '#core/tools.js';
10
11
  import { AGENT_ACCESS_PACKAGE_VERSION } from '#version.js';
11
12
  import { createAgentAccessToolCallRecorder } from './audit.js';
@@ -74,6 +75,15 @@ async function handleAgentAccessToolCall(params) {
74
75
  }
75
76
  async function executeAgentAccessTool(params) {
76
77
  try {
78
+ if (params.tool.validateInput?.(params.input) === false) {
79
+ recordToolCall(params.recordCall, {
80
+ tool: params.tool.name,
81
+ outcome: 'invalid-request',
82
+ errorCode: 'invalid-request',
83
+ context: params.context
84
+ });
85
+ return toolResult(agentAccessError('invalid-request'), true);
86
+ }
77
87
  const response = await params.tool.execute({
78
88
  context: params.context,
79
89
  arguments: params.input
@@ -88,12 +98,22 @@ async function executeAgentAccessTool(params) {
88
98
  });
89
99
  return toolResult(agentAccessError('invalid-tool-response'), true);
90
100
  }
91
- const outcome = envelope.data.ok ? 'success' : 'tool-error';
92
- const result = toolResult(envelope.data, !envelope.data.ok);
101
+ if (envelope.data.ok && params.tool.validateResult?.(envelope.data.result) === false) {
102
+ recordToolCall(params.recordCall, {
103
+ tool: params.tool.name,
104
+ outcome: 'exception',
105
+ errorCode: 'invalid-tool-response',
106
+ context: params.context
107
+ });
108
+ return toolResult(agentAccessError('invalid-tool-response'), true);
109
+ }
110
+ const boundedEnvelope = fitAgentAccessResponseToCeiling(envelope.data);
111
+ const outcome = boundedEnvelope.ok ? 'success' : 'tool-error';
112
+ const result = toolResult(boundedEnvelope, !boundedEnvelope.ok);
93
113
  recordToolCall(params.recordCall, {
94
114
  tool: params.tool.name,
95
115
  outcome,
96
- errorCode: envelope.data.ok ? 'none' : envelope.data.error?.code ?? 'unknown',
116
+ errorCode: boundedEnvelope.ok ? 'none' : boundedEnvelope.error?.code ?? 'unknown',
97
117
  context: params.context
98
118
  });
99
119
  return result;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/presentation/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 {agentAccessEnvelopeSchema} from '@shipfox/api-agent-access-dto';\nimport type {AgentAccessContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_SERVER_NAME} from '#constants.js';\nimport {agentAccessError, serializeAgentAccessEnvelope} from '#core/envelope.js';\nimport {type AgentAccessRateLimiter, createAgentAccessRateLimiter} from '#core/rate-limiter.js';\nimport {\n type AgentAccessTool,\n type AgentAccessToolMap,\n createAgentAccessFixtureTool,\n createAgentAccessToolMap,\n} from '#core/tools.js';\nimport type {AgentAccessToolCallOutcome} from '#metrics/index.js';\nimport {AGENT_ACCESS_PACKAGE_VERSION} from '#version.js';\nimport {type AgentAccessToolCallRecorder, createAgentAccessToolCallRecorder} from './audit.js';\n\nexport interface BuildAgentAccessMcpServerParams {\n context: AgentAccessContext;\n tools?: readonly AgentAccessTool[] | undefined;\n rateLimiter?: AgentAccessRateLimiter | undefined;\n recordCall?: AgentAccessToolCallRecorder | undefined;\n}\n\nconst defaultTools = (): readonly AgentAccessTool[] => [createAgentAccessFixtureTool()];\n\nexport function buildAgentAccessMcpServer(params: BuildAgentAccessMcpServerParams): Server {\n const tools = createAgentAccessToolMap(params.tools ?? defaultTools());\n const rateLimiter = params.rateLimiter ?? createAgentAccessRateLimiter();\n const recordCall = params.recordCall ?? createAgentAccessToolCallRecorder();\n const server = new Server(\n {name: AGENT_ACCESS_MCP_SERVER_NAME, version: AGENT_ACCESS_PACKAGE_VERSION},\n {\n capabilities: {tools: {}},\n instructions: AGENT_ACCESS_MCP_INSTRUCTIONS,\n },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: [...tools.values()].map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n outputSchema: tool.outputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n annotations: {readOnlyHint: true},\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, (request) =>\n handleAgentAccessToolCall({\n name: request.params.name,\n arguments: request.params.arguments,\n context: params.context,\n tools,\n rateLimiter,\n recordCall,\n }),\n );\n\n return server;\n}\n\ninterface HandleAgentAccessToolCallParams {\n name: string;\n arguments?: Record<string, unknown> | undefined;\n context: AgentAccessContext;\n tools: AgentAccessToolMap;\n rateLimiter: AgentAccessRateLimiter;\n recordCall: AgentAccessToolCallRecorder;\n}\n\nasync function handleAgentAccessToolCall(\n params: HandleAgentAccessToolCallParams,\n): Promise<CallToolResult> {\n const tool = params.tools.get(params.name);\n const rateLimit = params.rateLimiter.consume(params.context.credential);\n if (!rateLimit.allowed) {\n recordToolCall(params.recordCall, {\n tool: tool?.name ?? 'unknown',\n outcome: 'rate-limited',\n errorCode: 'rate-limited',\n context: params.context,\n });\n return toolResult(\n agentAccessError(\n 'rate-limited',\n rateLimit.retry_after_seconds === undefined\n ? {}\n : {retryAfterSeconds: rateLimit.retry_after_seconds},\n ),\n true,\n );\n }\n if (tool === undefined) return unknownToolResult(params);\n\n const input = params.arguments ?? {};\n if (!isRecord(input)) return invalidArgumentsResult(params, tool.name);\n return await executeAgentAccessTool({\n tool,\n input,\n context: params.context,\n recordCall: params.recordCall,\n });\n}\n\nasync function executeAgentAccessTool(params: {\n tool: AgentAccessTool;\n input: Record<string, unknown>;\n context: AgentAccessContext;\n recordCall: AgentAccessToolCallRecorder;\n}): Promise<CallToolResult> {\n try {\n const response = await params.tool.execute({context: params.context, arguments: params.input});\n const envelope = agentAccessEnvelopeSchema.safeParse(response);\n if (!envelope.success) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'exception',\n errorCode: 'invalid-tool-response',\n context: params.context,\n });\n return toolResult(agentAccessError('invalid-tool-response'), true);\n }\n\n const outcome: AgentAccessToolCallOutcome = envelope.data.ok ? 'success' : 'tool-error';\n const result = toolResult(envelope.data, !envelope.data.ok);\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome,\n errorCode: envelope.data.ok ? 'none' : (envelope.data.error?.code ?? 'unknown'),\n context: params.context,\n });\n return result;\n } catch (error) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'exception',\n errorCode: 'unknown',\n context: params.context,\n });\n logger().error({err: error, tool: params.tool.name}, 'Agent-access tool execution failed');\n reportError(error, {boundary: 'agent-access.mcp', operation: 'tool-call'});\n return toolResult(agentAccessError('tool-failed'), true);\n }\n}\n\nfunction unknownToolResult(params: HandleAgentAccessToolCallParams): CallToolResult {\n recordToolCall(params.recordCall, {\n tool: 'unknown',\n outcome: 'invalid-request',\n errorCode: 'unknown-tool',\n context: params.context,\n });\n return toolResult(agentAccessError('unknown-tool', {message: 'Tool is not available'}), true);\n}\n\nfunction invalidArgumentsResult(\n params: HandleAgentAccessToolCallParams,\n toolName: string,\n): CallToolResult {\n recordToolCall(params.recordCall, {\n tool: toolName,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n context: params.context,\n });\n return toolResult(\n agentAccessError('invalid-request', {message: 'Tool arguments must be an object'}),\n true,\n );\n}\n\nfunction toolResult(\n envelope: ReturnType<typeof agentAccessError>,\n isError: boolean,\n): CallToolResult {\n return {\n ...(isError ? {isError: true} : {}),\n content: [{type: 'text', text: serializeAgentAccessEnvelope(envelope)}],\n structuredContent: envelope as Record<string, unknown>,\n };\n}\n\nfunction recordToolCall(\n recordCall: AgentAccessToolCallRecorder,\n record: Parameters<AgentAccessToolCallRecorder>[0],\n): void {\n try {\n recordCall(record);\n } catch (error) {\n logger().error({err: error}, 'Failed to record agent-access tool audit event');\n reportError(error, {boundary: 'agent-access.mcp', operation: 'audit'});\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","agentAccessEnvelopeSchema","reportError","logger","AGENT_ACCESS_MCP_INSTRUCTIONS","AGENT_ACCESS_MCP_SERVER_NAME","agentAccessError","serializeAgentAccessEnvelope","createAgentAccessRateLimiter","createAgentAccessFixtureTool","createAgentAccessToolMap","AGENT_ACCESS_PACKAGE_VERSION","createAgentAccessToolCallRecorder","defaultTools","buildAgentAccessMcpServer","params","tools","rateLimiter","recordCall","server","name","version","capabilities","instructions","setRequestHandler","values","map","tool","description","inputSchema","outputSchema","annotations","readOnlyHint","request","handleAgentAccessToolCall","arguments","context","get","rateLimit","consume","credential","allowed","recordToolCall","outcome","errorCode","toolResult","retry_after_seconds","undefined","retryAfterSeconds","unknownToolResult","input","isRecord","invalidArgumentsResult","executeAgentAccessTool","response","execute","envelope","safeParse","success","data","ok","result","error","code","err","boundary","operation","message","toolName","isError","content","type","text","structuredContent","record","value","Array","isArray"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/presentation/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 {agentAccessEnvelopeSchema} from '@shipfox/api-agent-access-dto';\nimport type {AgentAccessContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_SERVER_NAME} from '#constants.js';\nimport {agentAccessError, serializeAgentAccessEnvelope} from '#core/envelope.js';\nimport {type AgentAccessRateLimiter, createAgentAccessRateLimiter} from '#core/rate-limiter.js';\nimport {fitAgentAccessResponseToCeiling} from '#core/response.js';\nimport {\n type AgentAccessTool,\n type AgentAccessToolMap,\n createAgentAccessFixtureTool,\n createAgentAccessToolMap,\n} from '#core/tools.js';\nimport type {AgentAccessToolCallOutcome} from '#metrics/index.js';\nimport {AGENT_ACCESS_PACKAGE_VERSION} from '#version.js';\nimport {type AgentAccessToolCallRecorder, createAgentAccessToolCallRecorder} from './audit.js';\n\nexport interface BuildAgentAccessMcpServerParams {\n context: AgentAccessContext;\n tools?: readonly AgentAccessTool[] | undefined;\n rateLimiter?: AgentAccessRateLimiter | undefined;\n recordCall?: AgentAccessToolCallRecorder | undefined;\n}\n\nconst defaultTools = (): readonly AgentAccessTool[] => [createAgentAccessFixtureTool()];\n\nexport function buildAgentAccessMcpServer(params: BuildAgentAccessMcpServerParams): Server {\n const tools = createAgentAccessToolMap(params.tools ?? defaultTools());\n const rateLimiter = params.rateLimiter ?? createAgentAccessRateLimiter();\n const recordCall = params.recordCall ?? createAgentAccessToolCallRecorder();\n const server = new Server(\n {name: AGENT_ACCESS_MCP_SERVER_NAME, version: AGENT_ACCESS_PACKAGE_VERSION},\n {\n capabilities: {tools: {}},\n instructions: AGENT_ACCESS_MCP_INSTRUCTIONS,\n },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: [...tools.values()].map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n outputSchema: tool.outputSchema as {\n type: 'object';\n properties?: Record<string, object> | undefined;\n required?: string[] | undefined;\n },\n annotations: {readOnlyHint: true},\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, (request) =>\n handleAgentAccessToolCall({\n name: request.params.name,\n arguments: request.params.arguments,\n context: params.context,\n tools,\n rateLimiter,\n recordCall,\n }),\n );\n\n return server;\n}\n\ninterface HandleAgentAccessToolCallParams {\n name: string;\n arguments?: Record<string, unknown> | undefined;\n context: AgentAccessContext;\n tools: AgentAccessToolMap;\n rateLimiter: AgentAccessRateLimiter;\n recordCall: AgentAccessToolCallRecorder;\n}\n\nasync function handleAgentAccessToolCall(\n params: HandleAgentAccessToolCallParams,\n): Promise<CallToolResult> {\n const tool = params.tools.get(params.name);\n const rateLimit = params.rateLimiter.consume(params.context.credential);\n if (!rateLimit.allowed) {\n recordToolCall(params.recordCall, {\n tool: tool?.name ?? 'unknown',\n outcome: 'rate-limited',\n errorCode: 'rate-limited',\n context: params.context,\n });\n return toolResult(\n agentAccessError(\n 'rate-limited',\n rateLimit.retry_after_seconds === undefined\n ? {}\n : {retryAfterSeconds: rateLimit.retry_after_seconds},\n ),\n true,\n );\n }\n if (tool === undefined) return unknownToolResult(params);\n\n const input = params.arguments ?? {};\n if (!isRecord(input)) return invalidArgumentsResult(params, tool.name);\n return await executeAgentAccessTool({\n tool,\n input,\n context: params.context,\n recordCall: params.recordCall,\n });\n}\n\nasync function executeAgentAccessTool(params: {\n tool: AgentAccessTool;\n input: Record<string, unknown>;\n context: AgentAccessContext;\n recordCall: AgentAccessToolCallRecorder;\n}): Promise<CallToolResult> {\n try {\n if (params.tool.validateInput?.(params.input) === false) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n context: params.context,\n });\n return toolResult(agentAccessError('invalid-request'), true);\n }\n\n const response = await params.tool.execute({context: params.context, arguments: params.input});\n const envelope = agentAccessEnvelopeSchema.safeParse(response);\n if (!envelope.success) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'exception',\n errorCode: 'invalid-tool-response',\n context: params.context,\n });\n return toolResult(agentAccessError('invalid-tool-response'), true);\n }\n\n if (envelope.data.ok && params.tool.validateResult?.(envelope.data.result) === false) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'exception',\n errorCode: 'invalid-tool-response',\n context: params.context,\n });\n return toolResult(agentAccessError('invalid-tool-response'), true);\n }\n\n const boundedEnvelope = fitAgentAccessResponseToCeiling(envelope.data);\n const outcome: AgentAccessToolCallOutcome = boundedEnvelope.ok ? 'success' : 'tool-error';\n const result = toolResult(boundedEnvelope, !boundedEnvelope.ok);\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome,\n errorCode: boundedEnvelope.ok ? 'none' : (boundedEnvelope.error?.code ?? 'unknown'),\n context: params.context,\n });\n return result;\n } catch (error) {\n recordToolCall(params.recordCall, {\n tool: params.tool.name,\n outcome: 'exception',\n errorCode: 'unknown',\n context: params.context,\n });\n logger().error({err: error, tool: params.tool.name}, 'Agent-access tool execution failed');\n reportError(error, {boundary: 'agent-access.mcp', operation: 'tool-call'});\n return toolResult(agentAccessError('tool-failed'), true);\n }\n}\n\nfunction unknownToolResult(params: HandleAgentAccessToolCallParams): CallToolResult {\n recordToolCall(params.recordCall, {\n tool: 'unknown',\n outcome: 'invalid-request',\n errorCode: 'unknown-tool',\n context: params.context,\n });\n return toolResult(agentAccessError('unknown-tool', {message: 'Tool is not available'}), true);\n}\n\nfunction invalidArgumentsResult(\n params: HandleAgentAccessToolCallParams,\n toolName: string,\n): CallToolResult {\n recordToolCall(params.recordCall, {\n tool: toolName,\n outcome: 'invalid-request',\n errorCode: 'invalid-request',\n context: params.context,\n });\n return toolResult(\n agentAccessError('invalid-request', {message: 'Tool arguments must be an object'}),\n true,\n );\n}\n\nfunction toolResult(\n envelope: ReturnType<typeof agentAccessError>,\n isError: boolean,\n): CallToolResult {\n return {\n ...(isError ? {isError: true} : {}),\n content: [{type: 'text', text: serializeAgentAccessEnvelope(envelope)}],\n structuredContent: envelope as Record<string, unknown>,\n };\n}\n\nfunction recordToolCall(\n recordCall: AgentAccessToolCallRecorder,\n record: Parameters<AgentAccessToolCallRecorder>[0],\n): void {\n try {\n recordCall(record);\n } catch (error) {\n logger().error({err: error}, 'Failed to record agent-access tool audit event');\n reportError(error, {boundary: 'agent-access.mcp', operation: 'audit'});\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","agentAccessEnvelopeSchema","reportError","logger","AGENT_ACCESS_MCP_INSTRUCTIONS","AGENT_ACCESS_MCP_SERVER_NAME","agentAccessError","serializeAgentAccessEnvelope","createAgentAccessRateLimiter","fitAgentAccessResponseToCeiling","createAgentAccessFixtureTool","createAgentAccessToolMap","AGENT_ACCESS_PACKAGE_VERSION","createAgentAccessToolCallRecorder","defaultTools","buildAgentAccessMcpServer","params","tools","rateLimiter","recordCall","server","name","version","capabilities","instructions","setRequestHandler","values","map","tool","description","inputSchema","outputSchema","annotations","readOnlyHint","request","handleAgentAccessToolCall","arguments","context","get","rateLimit","consume","credential","allowed","recordToolCall","outcome","errorCode","toolResult","retry_after_seconds","undefined","retryAfterSeconds","unknownToolResult","input","isRecord","invalidArgumentsResult","executeAgentAccessTool","validateInput","response","execute","envelope","safeParse","success","data","ok","validateResult","result","boundedEnvelope","error","code","err","boundary","operation","message","toolName","isError","content","type","text","structuredContent","record","value","Array","isArray"],"mappings":"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"}
@@ -1,3 +1,8 @@
1
+ import type { AnnotationsInterModuleClient } from '@shipfox/annotations-dto/inter-module';
2
+ import type { DefinitionsInterModuleClient } from '@shipfox/api-definitions-dto/inter-module';
3
+ import type { ProjectsModuleClient } from '@shipfox/api-projects-dto/inter-module';
4
+ import type { TriggersInterModuleClient } from '@shipfox/api-triggers-dto/inter-module';
5
+ import type { WorkflowsModuleClient } from '@shipfox/api-workflows-dto/inter-module';
1
6
  import { type RouteGroup } from '@shipfox/node-fastify';
2
7
  import { type AgentAccessRateLimiter } from '#core/rate-limiter.js';
3
8
  import { type AgentAccessTool } from '#core/tools.js';
@@ -9,6 +14,11 @@ export interface CreateAgentAccessRoutesOptions {
9
14
  rateLimiter?: AgentAccessRateLimiter | undefined;
10
15
  recordCall?: AgentAccessToolCallRecorder | undefined;
11
16
  isOriginAllowed?: ((origin: string | undefined) => boolean) | undefined;
17
+ projects?: ProjectsModuleClient | undefined;
18
+ definitions?: DefinitionsInterModuleClient | undefined;
19
+ workflows?: WorkflowsModuleClient | undefined;
20
+ annotations?: AnnotationsInterModuleClient | undefined;
21
+ triggers?: TriggersInterModuleClient | undefined;
12
22
  }
13
23
  export declare function createAgentAccessRoutes(options?: CreateAgentAccessRoutesOptions): RouteGroup;
14
24
  //# sourceMappingURL=routes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/presentation/routes.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,UAAU,EAEhB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAC,KAAK,sBAAsB,EAA+B,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAC,KAAK,eAAe,EAA+B,MAAM,gBAAgB,CAAC;AAElF,OAAO,EAAC,KAAK,2BAA2B,EAAoC,MAAM,YAAY,CAAC;AAK/F,MAAM,WAAW,8BAA8B;IAC7C,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4BAA4B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACjD,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACrD,eAAe,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CACzE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,8BAAmC,GAAG,UAAU,CA0EhG"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/presentation/routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,uCAAuC,CAAC;AAExF,OAAO,KAAK,EAAC,4BAA4B,EAAC,MAAM,2CAA2C,CAAC;AAC5F,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,wCAAwC,CAAC;AACtF,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yCAAyC,CAAC;AAEnF,OAAO,EAOL,KAAK,UAAU,EAEhB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EAAC,KAAK,sBAAsB,EAA+B,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAC,KAAK,eAAe,EAA+B,MAAM,gBAAgB,CAAC;AAElF,OAAO,EAAC,KAAK,2BAA2B,EAAoC,MAAM,YAAY,CAAC;AAK/F,MAAM,WAAW,8BAA8B;IAC7C,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4BAA4B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,GAAG,SAAS,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;IACjD,UAAU,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACrD,eAAe,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IACxE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC5C,WAAW,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACvD,SAAS,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC9C,WAAW,CAAC,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,EAAE,yBAAyB,GAAG,SAAS,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,8BAAmC,GAAG,UAAU,CA0EhG"}
@@ -4,6 +4,7 @@ import { reportError } from '@shipfox/node-error-monitoring';
4
4
  import { ClientError, createAllowedOriginMatcher, errorHandler as defaultErrorHandler, defineRoute } from '@shipfox/node-fastify';
5
5
  import { logger } from '@shipfox/node-opentelemetry';
6
6
  import { AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH } from '#constants.js';
7
+ import { createAgentAccessTools } from '#core/paged-tools.js';
7
8
  import { createAgentAccessRateLimiter } from '#core/rate-limiter.js';
8
9
  import { createAgentAccessFixtureTool } from '#core/tools.js';
9
10
  import { recordAgentAccessAuthFailure } from '#metrics/index.js';
@@ -11,9 +12,7 @@ import { createAgentAccessToolCallRecorder } from './audit.js';
11
12
  import { buildAgentAccessMcpServer } from './mcp-server.js';
12
13
  const TRAILING_SLASHES_RE = /\/+$/u;
13
14
  export function createAgentAccessRoutes(options = {}) {
14
- const tools = options.tools ?? [
15
- createAgentAccessFixtureTool()
16
- ];
15
+ const tools = options.tools ?? toolsFromProducerClients(options);
17
16
  const rateLimiter = options.rateLimiter ?? createAgentAccessRateLimiter();
18
17
  const recordCall = options.recordCall ?? createAgentAccessToolCallRecorder();
19
18
  const originMatcher = options.isOriginAllowed ?? createAllowedOriginMatcher();
@@ -93,6 +92,24 @@ export function createAgentAccessRoutes(options = {}) {
93
92
  ]
94
93
  };
95
94
  }
95
+ function toolsFromProducerClients(options) {
96
+ const { projects, definitions, workflows, annotations, triggers } = options;
97
+ if (projects === undefined && definitions === undefined && workflows === undefined && annotations === undefined && triggers === undefined) {
98
+ return [
99
+ createAgentAccessFixtureTool()
100
+ ];
101
+ }
102
+ if (projects === undefined || definitions === undefined || workflows === undefined || annotations === undefined || triggers === undefined) {
103
+ throw new Error('Agent-access producer clients must be configured together');
104
+ }
105
+ return createAgentAccessTools({
106
+ projects,
107
+ definitions,
108
+ workflows,
109
+ annotations,
110
+ triggers
111
+ });
112
+ }
96
113
  function methodNotAllowed(_request, reply) {
97
114
  return reply.code(405).header('allow', 'POST').send({
98
115
  code: 'method-not-allowed'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/presentation/routes.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {AUTH_AGENT_ACCESS, requireAgentAccessContext} from '@shipfox/api-auth-context';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {\n ClientError,\n createAllowedOriginMatcher,\n errorHandler as defaultErrorHandler,\n defineRoute,\n type FastifyReply,\n type FastifyRequest,\n type RouteGroup,\n type RoutePreHandler,\n} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH} from '#constants.js';\nimport {type AgentAccessRateLimiter, createAgentAccessRateLimiter} from '#core/rate-limiter.js';\nimport {type AgentAccessTool, createAgentAccessFixtureTool} from '#core/tools.js';\nimport {recordAgentAccessAuthFailure} from '#metrics/index.js';\nimport {type AgentAccessToolCallRecorder, createAgentAccessToolCallRecorder} from './audit.js';\nimport {buildAgentAccessMcpServer} from './mcp-server.js';\n\nconst TRAILING_SLASHES_RE = /\\/+$/u;\n\nexport interface CreateAgentAccessRoutesOptions {\n apiPublicUrl?: string | undefined;\n protectedResourceMetadataUrl?: string | undefined;\n tools?: readonly AgentAccessTool[] | undefined;\n rateLimiter?: AgentAccessRateLimiter | undefined;\n recordCall?: AgentAccessToolCallRecorder | undefined;\n isOriginAllowed?: ((origin: string | undefined) => boolean) | undefined;\n}\n\nexport function createAgentAccessRoutes(options: CreateAgentAccessRoutesOptions = {}): RouteGroup {\n const tools = options.tools ?? [createAgentAccessFixtureTool()];\n const rateLimiter = options.rateLimiter ?? createAgentAccessRateLimiter();\n const recordCall = options.recordCall ?? createAgentAccessToolCallRecorder();\n const originMatcher = options.isOriginAllowed ?? createAllowedOriginMatcher();\n const errorHandler = createAgentAccessErrorHandler(resourceMetadataUrl(options));\n\n return {\n prefix: '',\n routes: [\n defineRoute({\n method: 'GET',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'MCP endpoint does not provide an SSE GET stream.',\n preAuth: createOriginGuard(originMatcher),\n handler: methodNotAllowed,\n }),\n defineRoute({\n method: 'DELETE',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'MCP endpoint does not provide DELETE session operations.',\n preAuth: createOriginGuard(originMatcher),\n handler: methodNotAllowed,\n }),\n defineRoute({\n method: 'POST',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'Stateless Streamable HTTP MCP endpoint for agent-access tools.',\n auth: AUTH_AGENT_ACCESS,\n preAuth: createOriginGuard(originMatcher),\n errorHandler,\n handler: async (request, reply) => {\n const context = requireAgentAccessContext(request);\n const server = buildAgentAccessMcpServer({context, tools, rateLimiter, recordCall});\n // No sessionIdGenerator selects the SDK's stateless transport mode.\n const transport = new StreamableHTTPServerTransport();\n let connected = false;\n let cleanedUp = false;\n\n const cleanup = () => {\n if (cleanedUp) return;\n cleanedUp = true;\n void transport.close().catch((error) => {\n logger().error({err: error}, 'Failed to close agent-access transport');\n reportError(error, {\n boundary: 'agent-access.mcp',\n operation: 'close-transport',\n });\n });\n if (connected) {\n void server.close().catch((error) => {\n logger().error({err: error}, 'Failed to close agent-access server');\n reportError(error, {\n boundary: 'agent-access.mcp',\n operation: 'close-server',\n });\n });\n }\n };\n\n reply.raw.once('close', cleanup);\n try {\n await server.connect(transport as unknown as Transport);\n connected = true;\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n } catch (error) {\n cleanup();\n throw error;\n }\n },\n }),\n ],\n };\n}\n\nfunction methodNotAllowed(_request: FastifyRequest, reply: FastifyReply) {\n return reply.code(405).header('allow', 'POST').send({code: 'method-not-allowed'});\n}\n\nfunction createOriginGuard(\n isOriginAllowed: (origin: string | undefined) => boolean,\n): RoutePreHandler {\n return async (request, reply) => {\n if (isOriginAllowed(request.headers.origin)) return;\n recordAgentAccessAuthFailure('origin-not-allowed');\n await reply.code(403).send({code: 'origin-not-allowed'});\n };\n}\n\nfunction createAgentAccessErrorHandler(resourceMetadataUrl: string) {\n const challenge = `Bearer scope=\"read\", resource_metadata=\"${escapeHeaderValue(resourceMetadataUrl)}\"`;\n\n return (error: unknown, request: FastifyRequest, reply: FastifyReply) => {\n const status = errorStatus(error);\n const reason = authFailureReason(error, status, request);\n if (reason !== undefined) recordAgentAccessAuthFailure(reason);\n if (status === 401) reply.header('www-authenticate', challenge);\n return defaultErrorHandler(error, request, reply);\n };\n}\n\nfunction resourceMetadataUrl(options: CreateAgentAccessRoutesOptions): string {\n if (options.protectedResourceMetadataUrl !== undefined) {\n return options.protectedResourceMetadataUrl;\n }\n if (options.apiPublicUrl === undefined) return AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH;\n return `${options.apiPublicUrl.replace(TRAILING_SLASHES_RE, '')}${AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH}`;\n}\n\nfunction escapeHeaderValue(value: string): string {\n return value.replace(/[\\\\\"\\r\\n]/gu, (character) => {\n if (character === '\\r' || character === '\\n') return '';\n return `\\\\${character}`;\n });\n}\n\nfunction errorStatus(error: unknown): number | undefined {\n if (error instanceof ClientError) return error.status ?? 400;\n if (isRecord(error) && typeof error.statusCode === 'number') return error.statusCode;\n return undefined;\n}\n\nfunction authFailureReason(\n error: unknown,\n status: number | undefined,\n request: FastifyRequest,\n): 'missing' | 'invalid' | 'dependency-unavailable' | undefined {\n if (isRecord(error) && error.code === 'auth-dependency-unavailable') {\n return 'dependency-unavailable';\n }\n if (status !== 401) return undefined;\n return request.headers.authorization === undefined ? 'missing' : 'invalid';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_AGENT_ACCESS","requireAgentAccessContext","reportError","ClientError","createAllowedOriginMatcher","errorHandler","defaultErrorHandler","defineRoute","logger","AGENT_ACCESS_MCP_PATH","AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH","createAgentAccessRateLimiter","createAgentAccessFixtureTool","recordAgentAccessAuthFailure","createAgentAccessToolCallRecorder","buildAgentAccessMcpServer","TRAILING_SLASHES_RE","createAgentAccessRoutes","options","tools","rateLimiter","recordCall","originMatcher","isOriginAllowed","createAgentAccessErrorHandler","resourceMetadataUrl","prefix","routes","method","path","description","preAuth","createOriginGuard","handler","methodNotAllowed","auth","request","reply","context","server","transport","connected","cleanedUp","cleanup","close","catch","error","err","boundary","operation","raw","once","connect","hijack","handleRequest","body","_request","code","header","send","headers","origin","challenge","escapeHeaderValue","status","errorStatus","reason","authFailureReason","undefined","protectedResourceMetadataUrl","apiPublicUrl","replace","value","character","isRecord","statusCode","authorization"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/presentation/routes.ts"],"sourcesContent":["import {StreamableHTTPServerTransport} from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js';\nimport type {AnnotationsInterModuleClient} from '@shipfox/annotations-dto/inter-module';\nimport {AUTH_AGENT_ACCESS, requireAgentAccessContext} from '@shipfox/api-auth-context';\nimport type {DefinitionsInterModuleClient} from '@shipfox/api-definitions-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {TriggersInterModuleClient} from '@shipfox/api-triggers-dto/inter-module';\nimport type {WorkflowsModuleClient} from '@shipfox/api-workflows-dto/inter-module';\nimport {reportError} from '@shipfox/node-error-monitoring';\nimport {\n ClientError,\n createAllowedOriginMatcher,\n errorHandler as defaultErrorHandler,\n defineRoute,\n type FastifyReply,\n type FastifyRequest,\n type RouteGroup,\n type RoutePreHandler,\n} from '@shipfox/node-fastify';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH} from '#constants.js';\nimport {createAgentAccessTools} from '#core/paged-tools.js';\nimport {type AgentAccessRateLimiter, createAgentAccessRateLimiter} from '#core/rate-limiter.js';\nimport {type AgentAccessTool, createAgentAccessFixtureTool} from '#core/tools.js';\nimport {recordAgentAccessAuthFailure} from '#metrics/index.js';\nimport {type AgentAccessToolCallRecorder, createAgentAccessToolCallRecorder} from './audit.js';\nimport {buildAgentAccessMcpServer} from './mcp-server.js';\n\nconst TRAILING_SLASHES_RE = /\\/+$/u;\n\nexport interface CreateAgentAccessRoutesOptions {\n apiPublicUrl?: string | undefined;\n protectedResourceMetadataUrl?: string | undefined;\n tools?: readonly AgentAccessTool[] | undefined;\n rateLimiter?: AgentAccessRateLimiter | undefined;\n recordCall?: AgentAccessToolCallRecorder | undefined;\n isOriginAllowed?: ((origin: string | undefined) => boolean) | undefined;\n projects?: ProjectsModuleClient | undefined;\n definitions?: DefinitionsInterModuleClient | undefined;\n workflows?: WorkflowsModuleClient | undefined;\n annotations?: AnnotationsInterModuleClient | undefined;\n triggers?: TriggersInterModuleClient | undefined;\n}\n\nexport function createAgentAccessRoutes(options: CreateAgentAccessRoutesOptions = {}): RouteGroup {\n const tools = options.tools ?? toolsFromProducerClients(options);\n const rateLimiter = options.rateLimiter ?? createAgentAccessRateLimiter();\n const recordCall = options.recordCall ?? createAgentAccessToolCallRecorder();\n const originMatcher = options.isOriginAllowed ?? createAllowedOriginMatcher();\n const errorHandler = createAgentAccessErrorHandler(resourceMetadataUrl(options));\n\n return {\n prefix: '',\n routes: [\n defineRoute({\n method: 'GET',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'MCP endpoint does not provide an SSE GET stream.',\n preAuth: createOriginGuard(originMatcher),\n handler: methodNotAllowed,\n }),\n defineRoute({\n method: 'DELETE',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'MCP endpoint does not provide DELETE session operations.',\n preAuth: createOriginGuard(originMatcher),\n handler: methodNotAllowed,\n }),\n defineRoute({\n method: 'POST',\n path: AGENT_ACCESS_MCP_PATH,\n description: 'Stateless Streamable HTTP MCP endpoint for agent-access tools.',\n auth: AUTH_AGENT_ACCESS,\n preAuth: createOriginGuard(originMatcher),\n errorHandler,\n handler: async (request, reply) => {\n const context = requireAgentAccessContext(request);\n const server = buildAgentAccessMcpServer({context, tools, rateLimiter, recordCall});\n // No sessionIdGenerator selects the SDK's stateless transport mode.\n const transport = new StreamableHTTPServerTransport();\n let connected = false;\n let cleanedUp = false;\n\n const cleanup = () => {\n if (cleanedUp) return;\n cleanedUp = true;\n void transport.close().catch((error) => {\n logger().error({err: error}, 'Failed to close agent-access transport');\n reportError(error, {\n boundary: 'agent-access.mcp',\n operation: 'close-transport',\n });\n });\n if (connected) {\n void server.close().catch((error) => {\n logger().error({err: error}, 'Failed to close agent-access server');\n reportError(error, {\n boundary: 'agent-access.mcp',\n operation: 'close-server',\n });\n });\n }\n };\n\n reply.raw.once('close', cleanup);\n try {\n await server.connect(transport as unknown as Transport);\n connected = true;\n reply.hijack();\n await transport.handleRequest(request.raw, reply.raw, request.body);\n } catch (error) {\n cleanup();\n throw error;\n }\n },\n }),\n ],\n };\n}\n\nfunction toolsFromProducerClients(\n options: CreateAgentAccessRoutesOptions,\n): readonly AgentAccessTool[] {\n const {projects, definitions, workflows, annotations, triggers} = options;\n if (\n projects === undefined &&\n definitions === undefined &&\n workflows === undefined &&\n annotations === undefined &&\n triggers === undefined\n ) {\n return [createAgentAccessFixtureTool()];\n }\n if (\n projects === undefined ||\n definitions === undefined ||\n workflows === undefined ||\n annotations === undefined ||\n triggers === undefined\n ) {\n throw new Error('Agent-access producer clients must be configured together');\n }\n return createAgentAccessTools({projects, definitions, workflows, annotations, triggers});\n}\n\nfunction methodNotAllowed(_request: FastifyRequest, reply: FastifyReply) {\n return reply.code(405).header('allow', 'POST').send({code: 'method-not-allowed'});\n}\n\nfunction createOriginGuard(\n isOriginAllowed: (origin: string | undefined) => boolean,\n): RoutePreHandler {\n return async (request, reply) => {\n if (isOriginAllowed(request.headers.origin)) return;\n recordAgentAccessAuthFailure('origin-not-allowed');\n await reply.code(403).send({code: 'origin-not-allowed'});\n };\n}\n\nfunction createAgentAccessErrorHandler(resourceMetadataUrl: string) {\n const challenge = `Bearer scope=\"read\", resource_metadata=\"${escapeHeaderValue(resourceMetadataUrl)}\"`;\n\n return (error: unknown, request: FastifyRequest, reply: FastifyReply) => {\n const status = errorStatus(error);\n const reason = authFailureReason(error, status, request);\n if (reason !== undefined) recordAgentAccessAuthFailure(reason);\n if (status === 401) reply.header('www-authenticate', challenge);\n return defaultErrorHandler(error, request, reply);\n };\n}\n\nfunction resourceMetadataUrl(options: CreateAgentAccessRoutesOptions): string {\n if (options.protectedResourceMetadataUrl !== undefined) {\n return options.protectedResourceMetadataUrl;\n }\n if (options.apiPublicUrl === undefined) return AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH;\n return `${options.apiPublicUrl.replace(TRAILING_SLASHES_RE, '')}${AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH}`;\n}\n\nfunction escapeHeaderValue(value: string): string {\n return value.replace(/[\\\\\"\\r\\n]/gu, (character) => {\n if (character === '\\r' || character === '\\n') return '';\n return `\\\\${character}`;\n });\n}\n\nfunction errorStatus(error: unknown): number | undefined {\n if (error instanceof ClientError) return error.status ?? 400;\n if (isRecord(error) && typeof error.statusCode === 'number') return error.statusCode;\n return undefined;\n}\n\nfunction authFailureReason(\n error: unknown,\n status: number | undefined,\n request: FastifyRequest,\n): 'missing' | 'invalid' | 'dependency-unavailable' | undefined {\n if (isRecord(error) && error.code === 'auth-dependency-unavailable') {\n return 'dependency-unavailable';\n }\n if (status !== 401) return undefined;\n return request.headers.authorization === undefined ? 'missing' : 'invalid';\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"names":["StreamableHTTPServerTransport","AUTH_AGENT_ACCESS","requireAgentAccessContext","reportError","ClientError","createAllowedOriginMatcher","errorHandler","defaultErrorHandler","defineRoute","logger","AGENT_ACCESS_MCP_PATH","AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH","createAgentAccessTools","createAgentAccessRateLimiter","createAgentAccessFixtureTool","recordAgentAccessAuthFailure","createAgentAccessToolCallRecorder","buildAgentAccessMcpServer","TRAILING_SLASHES_RE","createAgentAccessRoutes","options","tools","toolsFromProducerClients","rateLimiter","recordCall","originMatcher","isOriginAllowed","createAgentAccessErrorHandler","resourceMetadataUrl","prefix","routes","method","path","description","preAuth","createOriginGuard","handler","methodNotAllowed","auth","request","reply","context","server","transport","connected","cleanedUp","cleanup","close","catch","error","err","boundary","operation","raw","once","connect","hijack","handleRequest","body","projects","definitions","workflows","annotations","triggers","undefined","Error","_request","code","header","send","headers","origin","challenge","escapeHeaderValue","status","errorStatus","reason","authFailureReason","protectedResourceMetadataUrl","apiPublicUrl","replace","value","character","isRecord","statusCode","authorization"],"mappings":"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"}