@shipfox/api-agent-access 20.2.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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +17 -0
- package/dist/constants.js.map +1 -0
- package/dist/core/envelope.d.ts +9 -0
- package/dist/core/envelope.d.ts.map +1 -0
- package/dist/core/envelope.js +33 -0
- package/dist/core/envelope.js.map +1 -0
- package/dist/core/rate-limiter.d.ts +18 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js +67 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/tools.d.ts +21 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +60 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/index.d.ts +2 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +3 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/instance.d.ts +8 -0
- package/dist/metrics/instance.d.ts.map +1 -0
- package/dist/metrics/instance.js +26 -0
- package/dist/metrics/instance.js.map +1 -0
- package/dist/module.d.ts +7 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +12 -0
- package/dist/module.js.map +1 -0
- package/dist/presentation/audit.d.ts +15 -0
- package/dist/presentation/audit.d.ts.map +1 -0
- package/dist/presentation/audit.js +28 -0
- package/dist/presentation/audit.js.map +1 -0
- package/dist/presentation/mcp-server.d.ts +13 -0
- package/dist/presentation/mcp-server.d.ts.map +1 -0
- package/dist/presentation/mcp-server.js +171 -0
- package/dist/presentation/mcp-server.js.map +1 -0
- package/dist/presentation/routes.d.ts +14 -0
- package/dist/presentation/routes.d.ts.map +1 -0
- package/dist/presentation/routes.js +149 -0
- package/dist/presentation/routes.js.map +1 -0
- package/dist/tsconfig.test.tsbuildinfo +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
- package/src/constants.ts +22 -0
- package/src/core/envelope.test.ts +9 -0
- package/src/core/envelope.ts +36 -0
- package/src/core/rate-limiter.test.ts +62 -0
- package/src/core/rate-limiter.ts +95 -0
- package/src/core/tools.test.ts +38 -0
- package/src/core/tools.ts +67 -0
- package/src/index.ts +54 -0
- package/src/metrics/index.ts +1 -0
- package/src/metrics/instance.test.ts +67 -0
- package/src/metrics/instance.ts +48 -0
- package/src/module.ts +19 -0
- package/src/presentation/audit.test.ts +67 -0
- package/src/presentation/audit.ts +45 -0
- package/src/presentation/mcp-server.test.ts +168 -0
- package/src/presentation/mcp-server.ts +212 -0
- package/src/presentation/routes.test.ts +193 -0
- package/src/presentation/routes.ts +171 -0
- package/src/version.ts +5 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +3 -0
- package/tsconfig.test.json +8 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { agentAccessEnvelopeSchema } from '@shipfox/api-agent-access-dto';
|
|
4
|
+
import { reportError } from '@shipfox/node-error-monitoring';
|
|
5
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
6
|
+
import { AGENT_ACCESS_MCP_INSTRUCTIONS, AGENT_ACCESS_MCP_SERVER_NAME } from '#constants.js';
|
|
7
|
+
import { agentAccessError, serializeAgentAccessEnvelope } from '#core/envelope.js';
|
|
8
|
+
import { createAgentAccessRateLimiter } from '#core/rate-limiter.js';
|
|
9
|
+
import { createAgentAccessFixtureTool, createAgentAccessToolMap } from '#core/tools.js';
|
|
10
|
+
import { AGENT_ACCESS_PACKAGE_VERSION } from '#version.js';
|
|
11
|
+
import { createAgentAccessToolCallRecorder } from './audit.js';
|
|
12
|
+
const defaultTools = ()=>[
|
|
13
|
+
createAgentAccessFixtureTool()
|
|
14
|
+
];
|
|
15
|
+
export function buildAgentAccessMcpServer(params) {
|
|
16
|
+
const tools = createAgentAccessToolMap(params.tools ?? defaultTools());
|
|
17
|
+
const rateLimiter = params.rateLimiter ?? createAgentAccessRateLimiter();
|
|
18
|
+
const recordCall = params.recordCall ?? createAgentAccessToolCallRecorder();
|
|
19
|
+
const server = new Server({
|
|
20
|
+
name: AGENT_ACCESS_MCP_SERVER_NAME,
|
|
21
|
+
version: AGENT_ACCESS_PACKAGE_VERSION
|
|
22
|
+
}, {
|
|
23
|
+
capabilities: {
|
|
24
|
+
tools: {}
|
|
25
|
+
},
|
|
26
|
+
instructions: AGENT_ACCESS_MCP_INSTRUCTIONS
|
|
27
|
+
});
|
|
28
|
+
server.setRequestHandler(ListToolsRequestSchema, ()=>({
|
|
29
|
+
tools: [
|
|
30
|
+
...tools.values()
|
|
31
|
+
].map((tool)=>({
|
|
32
|
+
name: tool.name,
|
|
33
|
+
description: tool.description,
|
|
34
|
+
inputSchema: tool.inputSchema,
|
|
35
|
+
outputSchema: tool.outputSchema,
|
|
36
|
+
annotations: {
|
|
37
|
+
readOnlyHint: true
|
|
38
|
+
}
|
|
39
|
+
}))
|
|
40
|
+
}));
|
|
41
|
+
server.setRequestHandler(CallToolRequestSchema, (request)=>handleAgentAccessToolCall({
|
|
42
|
+
name: request.params.name,
|
|
43
|
+
arguments: request.params.arguments,
|
|
44
|
+
context: params.context,
|
|
45
|
+
tools,
|
|
46
|
+
rateLimiter,
|
|
47
|
+
recordCall
|
|
48
|
+
}));
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
async function handleAgentAccessToolCall(params) {
|
|
52
|
+
const tool = params.tools.get(params.name);
|
|
53
|
+
const rateLimit = params.rateLimiter.consume(params.context.credential);
|
|
54
|
+
if (!rateLimit.allowed) {
|
|
55
|
+
recordToolCall(params.recordCall, {
|
|
56
|
+
tool: tool?.name ?? 'unknown',
|
|
57
|
+
outcome: 'rate-limited',
|
|
58
|
+
errorCode: 'rate-limited',
|
|
59
|
+
context: params.context
|
|
60
|
+
});
|
|
61
|
+
return toolResult(agentAccessError('rate-limited', rateLimit.retry_after_seconds === undefined ? {} : {
|
|
62
|
+
retryAfterSeconds: rateLimit.retry_after_seconds
|
|
63
|
+
}), true);
|
|
64
|
+
}
|
|
65
|
+
if (tool === undefined) return unknownToolResult(params);
|
|
66
|
+
const input = params.arguments ?? {};
|
|
67
|
+
if (!isRecord(input)) return invalidArgumentsResult(params, tool.name);
|
|
68
|
+
return await executeAgentAccessTool({
|
|
69
|
+
tool,
|
|
70
|
+
input,
|
|
71
|
+
context: params.context,
|
|
72
|
+
recordCall: params.recordCall
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function executeAgentAccessTool(params) {
|
|
76
|
+
try {
|
|
77
|
+
const response = await params.tool.execute({
|
|
78
|
+
context: params.context,
|
|
79
|
+
arguments: params.input
|
|
80
|
+
});
|
|
81
|
+
const envelope = agentAccessEnvelopeSchema.safeParse(response);
|
|
82
|
+
if (!envelope.success) {
|
|
83
|
+
recordToolCall(params.recordCall, {
|
|
84
|
+
tool: params.tool.name,
|
|
85
|
+
outcome: 'exception',
|
|
86
|
+
errorCode: 'invalid-tool-response',
|
|
87
|
+
context: params.context
|
|
88
|
+
});
|
|
89
|
+
return toolResult(agentAccessError('invalid-tool-response'), true);
|
|
90
|
+
}
|
|
91
|
+
const outcome = envelope.data.ok ? 'success' : 'tool-error';
|
|
92
|
+
const result = toolResult(envelope.data, !envelope.data.ok);
|
|
93
|
+
recordToolCall(params.recordCall, {
|
|
94
|
+
tool: params.tool.name,
|
|
95
|
+
outcome,
|
|
96
|
+
errorCode: envelope.data.ok ? 'none' : envelope.data.error?.code ?? 'unknown',
|
|
97
|
+
context: params.context
|
|
98
|
+
});
|
|
99
|
+
return result;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
recordToolCall(params.recordCall, {
|
|
102
|
+
tool: params.tool.name,
|
|
103
|
+
outcome: 'exception',
|
|
104
|
+
errorCode: 'unknown',
|
|
105
|
+
context: params.context
|
|
106
|
+
});
|
|
107
|
+
logger().error({
|
|
108
|
+
err: error,
|
|
109
|
+
tool: params.tool.name
|
|
110
|
+
}, 'Agent-access tool execution failed');
|
|
111
|
+
reportError(error, {
|
|
112
|
+
boundary: 'agent-access.mcp',
|
|
113
|
+
operation: 'tool-call'
|
|
114
|
+
});
|
|
115
|
+
return toolResult(agentAccessError('tool-failed'), true);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function unknownToolResult(params) {
|
|
119
|
+
recordToolCall(params.recordCall, {
|
|
120
|
+
tool: 'unknown',
|
|
121
|
+
outcome: 'invalid-request',
|
|
122
|
+
errorCode: 'unknown-tool',
|
|
123
|
+
context: params.context
|
|
124
|
+
});
|
|
125
|
+
return toolResult(agentAccessError('unknown-tool', {
|
|
126
|
+
message: 'Tool is not available'
|
|
127
|
+
}), true);
|
|
128
|
+
}
|
|
129
|
+
function invalidArgumentsResult(params, toolName) {
|
|
130
|
+
recordToolCall(params.recordCall, {
|
|
131
|
+
tool: toolName,
|
|
132
|
+
outcome: 'invalid-request',
|
|
133
|
+
errorCode: 'invalid-request',
|
|
134
|
+
context: params.context
|
|
135
|
+
});
|
|
136
|
+
return toolResult(agentAccessError('invalid-request', {
|
|
137
|
+
message: 'Tool arguments must be an object'
|
|
138
|
+
}), true);
|
|
139
|
+
}
|
|
140
|
+
function toolResult(envelope, isError) {
|
|
141
|
+
return {
|
|
142
|
+
...isError ? {
|
|
143
|
+
isError: true
|
|
144
|
+
} : {},
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: 'text',
|
|
148
|
+
text: serializeAgentAccessEnvelope(envelope)
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
structuredContent: envelope
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function recordToolCall(recordCall, record) {
|
|
155
|
+
try {
|
|
156
|
+
recordCall(record);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
logger().error({
|
|
159
|
+
err: error
|
|
160
|
+
}, 'Failed to record agent-access tool audit event');
|
|
161
|
+
reportError(error, {
|
|
162
|
+
boundary: 'agent-access.mcp',
|
|
163
|
+
operation: 'audit'
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function isRecord(value) {
|
|
168
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type RouteGroup } from '@shipfox/node-fastify';
|
|
2
|
+
import { type AgentAccessRateLimiter } from '#core/rate-limiter.js';
|
|
3
|
+
import { type AgentAccessTool } from '#core/tools.js';
|
|
4
|
+
import { type AgentAccessToolCallRecorder } from './audit.js';
|
|
5
|
+
export interface CreateAgentAccessRoutesOptions {
|
|
6
|
+
apiPublicUrl?: string | undefined;
|
|
7
|
+
protectedResourceMetadataUrl?: string | undefined;
|
|
8
|
+
tools?: readonly AgentAccessTool[] | undefined;
|
|
9
|
+
rateLimiter?: AgentAccessRateLimiter | undefined;
|
|
10
|
+
recordCall?: AgentAccessToolCallRecorder | undefined;
|
|
11
|
+
isOriginAllowed?: ((origin: string | undefined) => boolean) | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function createAgentAccessRoutes(options?: CreateAgentAccessRoutesOptions): RouteGroup;
|
|
14
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
2
|
+
import { AUTH_AGENT_ACCESS, requireAgentAccessContext } from '@shipfox/api-auth-context';
|
|
3
|
+
import { reportError } from '@shipfox/node-error-monitoring';
|
|
4
|
+
import { ClientError, createAllowedOriginMatcher, errorHandler as defaultErrorHandler, defineRoute } from '@shipfox/node-fastify';
|
|
5
|
+
import { logger } from '@shipfox/node-opentelemetry';
|
|
6
|
+
import { AGENT_ACCESS_MCP_PATH, AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH } from '#constants.js';
|
|
7
|
+
import { createAgentAccessRateLimiter } from '#core/rate-limiter.js';
|
|
8
|
+
import { createAgentAccessFixtureTool } from '#core/tools.js';
|
|
9
|
+
import { recordAgentAccessAuthFailure } from '#metrics/index.js';
|
|
10
|
+
import { createAgentAccessToolCallRecorder } from './audit.js';
|
|
11
|
+
import { buildAgentAccessMcpServer } from './mcp-server.js';
|
|
12
|
+
const TRAILING_SLASHES_RE = /\/+$/u;
|
|
13
|
+
export function createAgentAccessRoutes(options = {}) {
|
|
14
|
+
const tools = options.tools ?? [
|
|
15
|
+
createAgentAccessFixtureTool()
|
|
16
|
+
];
|
|
17
|
+
const rateLimiter = options.rateLimiter ?? createAgentAccessRateLimiter();
|
|
18
|
+
const recordCall = options.recordCall ?? createAgentAccessToolCallRecorder();
|
|
19
|
+
const originMatcher = options.isOriginAllowed ?? createAllowedOriginMatcher();
|
|
20
|
+
const errorHandler = createAgentAccessErrorHandler(resourceMetadataUrl(options));
|
|
21
|
+
return {
|
|
22
|
+
prefix: '',
|
|
23
|
+
routes: [
|
|
24
|
+
defineRoute({
|
|
25
|
+
method: 'GET',
|
|
26
|
+
path: AGENT_ACCESS_MCP_PATH,
|
|
27
|
+
description: 'MCP endpoint does not provide an SSE GET stream.',
|
|
28
|
+
preAuth: createOriginGuard(originMatcher),
|
|
29
|
+
handler: methodNotAllowed
|
|
30
|
+
}),
|
|
31
|
+
defineRoute({
|
|
32
|
+
method: 'DELETE',
|
|
33
|
+
path: AGENT_ACCESS_MCP_PATH,
|
|
34
|
+
description: 'MCP endpoint does not provide DELETE session operations.',
|
|
35
|
+
preAuth: createOriginGuard(originMatcher),
|
|
36
|
+
handler: methodNotAllowed
|
|
37
|
+
}),
|
|
38
|
+
defineRoute({
|
|
39
|
+
method: 'POST',
|
|
40
|
+
path: AGENT_ACCESS_MCP_PATH,
|
|
41
|
+
description: 'Stateless Streamable HTTP MCP endpoint for agent-access tools.',
|
|
42
|
+
auth: AUTH_AGENT_ACCESS,
|
|
43
|
+
preAuth: createOriginGuard(originMatcher),
|
|
44
|
+
errorHandler,
|
|
45
|
+
handler: async (request, reply)=>{
|
|
46
|
+
const context = requireAgentAccessContext(request);
|
|
47
|
+
const server = buildAgentAccessMcpServer({
|
|
48
|
+
context,
|
|
49
|
+
tools,
|
|
50
|
+
rateLimiter,
|
|
51
|
+
recordCall
|
|
52
|
+
});
|
|
53
|
+
// No sessionIdGenerator selects the SDK's stateless transport mode.
|
|
54
|
+
const transport = new StreamableHTTPServerTransport();
|
|
55
|
+
let connected = false;
|
|
56
|
+
let cleanedUp = false;
|
|
57
|
+
const cleanup = ()=>{
|
|
58
|
+
if (cleanedUp) return;
|
|
59
|
+
cleanedUp = true;
|
|
60
|
+
void transport.close().catch((error)=>{
|
|
61
|
+
logger().error({
|
|
62
|
+
err: error
|
|
63
|
+
}, 'Failed to close agent-access transport');
|
|
64
|
+
reportError(error, {
|
|
65
|
+
boundary: 'agent-access.mcp',
|
|
66
|
+
operation: 'close-transport'
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
if (connected) {
|
|
70
|
+
void server.close().catch((error)=>{
|
|
71
|
+
logger().error({
|
|
72
|
+
err: error
|
|
73
|
+
}, 'Failed to close agent-access server');
|
|
74
|
+
reportError(error, {
|
|
75
|
+
boundary: 'agent-access.mcp',
|
|
76
|
+
operation: 'close-server'
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
reply.raw.once('close', cleanup);
|
|
82
|
+
try {
|
|
83
|
+
await server.connect(transport);
|
|
84
|
+
connected = true;
|
|
85
|
+
reply.hijack();
|
|
86
|
+
await transport.handleRequest(request.raw, reply.raw, request.body);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
cleanup();
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function methodNotAllowed(_request, reply) {
|
|
97
|
+
return reply.code(405).header('allow', 'POST').send({
|
|
98
|
+
code: 'method-not-allowed'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function createOriginGuard(isOriginAllowed) {
|
|
102
|
+
return async (request, reply)=>{
|
|
103
|
+
if (isOriginAllowed(request.headers.origin)) return;
|
|
104
|
+
recordAgentAccessAuthFailure('origin-not-allowed');
|
|
105
|
+
await reply.code(403).send({
|
|
106
|
+
code: 'origin-not-allowed'
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function createAgentAccessErrorHandler(resourceMetadataUrl) {
|
|
111
|
+
const challenge = `Bearer scope="read", resource_metadata="${escapeHeaderValue(resourceMetadataUrl)}"`;
|
|
112
|
+
return (error, request, reply)=>{
|
|
113
|
+
const status = errorStatus(error);
|
|
114
|
+
const reason = authFailureReason(error, status, request);
|
|
115
|
+
if (reason !== undefined) recordAgentAccessAuthFailure(reason);
|
|
116
|
+
if (status === 401) reply.header('www-authenticate', challenge);
|
|
117
|
+
return defaultErrorHandler(error, request, reply);
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function resourceMetadataUrl(options) {
|
|
121
|
+
if (options.protectedResourceMetadataUrl !== undefined) {
|
|
122
|
+
return options.protectedResourceMetadataUrl;
|
|
123
|
+
}
|
|
124
|
+
if (options.apiPublicUrl === undefined) return AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH;
|
|
125
|
+
return `${options.apiPublicUrl.replace(TRAILING_SLASHES_RE, '')}${AGENT_ACCESS_PROTECTED_RESOURCE_METADATA_PATH}`;
|
|
126
|
+
}
|
|
127
|
+
function escapeHeaderValue(value) {
|
|
128
|
+
return value.replace(/[\\"\r\n]/gu, (character)=>{
|
|
129
|
+
if (character === '\r' || character === '\n') return '';
|
|
130
|
+
return `\\${character}`;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function errorStatus(error) {
|
|
134
|
+
if (error instanceof ClientError) return error.status ?? 400;
|
|
135
|
+
if (isRecord(error) && typeof error.statusCode === 'number') return error.statusCode;
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
function authFailureReason(error, status, request) {
|
|
139
|
+
if (isRecord(error) && error.code === 'auth-dependency-unavailable') {
|
|
140
|
+
return 'dependency-unavailable';
|
|
141
|
+
}
|
|
142
|
+
if (status !== 401) return undefined;
|
|
143
|
+
return request.headers.authorization === undefined ? 'missing' : 'invalid';
|
|
144
|
+
}
|
|
145
|
+
function isRecord(value) {
|
|
146
|
+
return typeof value === 'object' && value !== null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +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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"}
|