visus-mcp 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.claude/settings.local.json +28 -1
  2. package/.mcpregistry_github_token +1 -1
  3. package/.mcpregistry_registry_token +1 -1
  4. package/CLAUDE.md +197 -0
  5. package/TROUBLESHOOT-COGNITO-AUTH-20260324-2029.md +415 -0
  6. package/TROUBLESHOOT-COGNITO-JWT-20260324.md +592 -0
  7. package/dist/browser/playwright-renderer.d.ts.map +1 -1
  8. package/dist/browser/playwright-renderer.js +71 -51
  9. package/dist/browser/playwright-renderer.js.map +1 -1
  10. package/dist/index.js +0 -0
  11. package/infrastructure/stack.ts +1 -0
  12. package/lambda-deploy/index.js +81512 -0
  13. package/lambda-deploy/index.js.map +7 -0
  14. package/lambda-package/browser/__mocks__/playwright-renderer.d.ts +25 -0
  15. package/lambda-package/browser/__mocks__/playwright-renderer.d.ts.map +1 -0
  16. package/lambda-package/browser/__mocks__/playwright-renderer.js +119 -0
  17. package/lambda-package/browser/__mocks__/playwright-renderer.js.map +1 -0
  18. package/lambda-package/browser/playwright-renderer.d.ts +40 -0
  19. package/lambda-package/browser/playwright-renderer.d.ts.map +1 -0
  20. package/lambda-package/browser/playwright-renderer.js +214 -0
  21. package/lambda-package/browser/playwright-renderer.js.map +1 -0
  22. package/lambda-package/browser/reader.d.ts +31 -0
  23. package/lambda-package/browser/reader.d.ts.map +1 -0
  24. package/lambda-package/browser/reader.js +98 -0
  25. package/lambda-package/browser/reader.js.map +1 -0
  26. package/lambda-package/index.d.ts +18 -0
  27. package/lambda-package/index.d.ts.map +1 -0
  28. package/lambda-package/index.js +238 -0
  29. package/lambda-package/index.js.map +1 -0
  30. package/lambda-package/lambda-handler.d.ts +28 -0
  31. package/lambda-package/lambda-handler.d.ts.map +1 -0
  32. package/lambda-package/lambda-handler.js +257 -0
  33. package/lambda-package/lambda-handler.js.map +1 -0
  34. package/lambda-package/package-lock.json +7435 -0
  35. package/lambda-package/package.json +74 -0
  36. package/lambda-package/runtime.d.ts +50 -0
  37. package/lambda-package/runtime.d.ts.map +1 -0
  38. package/lambda-package/runtime.js +86 -0
  39. package/lambda-package/runtime.js.map +1 -0
  40. package/lambda-package/sanitizer/elicit-runner.d.ts +48 -0
  41. package/lambda-package/sanitizer/elicit-runner.d.ts.map +1 -0
  42. package/lambda-package/sanitizer/elicit-runner.js +100 -0
  43. package/lambda-package/sanitizer/elicit-runner.js.map +1 -0
  44. package/lambda-package/sanitizer/framework-mapper.d.ts +24 -0
  45. package/lambda-package/sanitizer/framework-mapper.d.ts.map +1 -0
  46. package/lambda-package/sanitizer/framework-mapper.js +342 -0
  47. package/lambda-package/sanitizer/framework-mapper.js.map +1 -0
  48. package/lambda-package/sanitizer/hitl-gate.d.ts +69 -0
  49. package/lambda-package/sanitizer/hitl-gate.d.ts.map +1 -0
  50. package/lambda-package/sanitizer/hitl-gate.js +101 -0
  51. package/lambda-package/sanitizer/hitl-gate.js.map +1 -0
  52. package/lambda-package/sanitizer/index.d.ts +63 -0
  53. package/lambda-package/sanitizer/index.d.ts.map +1 -0
  54. package/lambda-package/sanitizer/index.js +105 -0
  55. package/lambda-package/sanitizer/index.js.map +1 -0
  56. package/lambda-package/sanitizer/injection-detector.d.ts +34 -0
  57. package/lambda-package/sanitizer/injection-detector.d.ts.map +1 -0
  58. package/lambda-package/sanitizer/injection-detector.js +89 -0
  59. package/lambda-package/sanitizer/injection-detector.js.map +1 -0
  60. package/lambda-package/sanitizer/patterns.d.ts +30 -0
  61. package/lambda-package/sanitizer/patterns.d.ts.map +1 -0
  62. package/lambda-package/sanitizer/patterns.js +372 -0
  63. package/lambda-package/sanitizer/patterns.js.map +1 -0
  64. package/lambda-package/sanitizer/pii-allowlist.d.ts +49 -0
  65. package/lambda-package/sanitizer/pii-allowlist.d.ts.map +1 -0
  66. package/lambda-package/sanitizer/pii-allowlist.js +231 -0
  67. package/lambda-package/sanitizer/pii-allowlist.js.map +1 -0
  68. package/lambda-package/sanitizer/pii-redactor.d.ts +41 -0
  69. package/lambda-package/sanitizer/pii-redactor.d.ts.map +1 -0
  70. package/lambda-package/sanitizer/pii-redactor.js +213 -0
  71. package/lambda-package/sanitizer/pii-redactor.js.map +1 -0
  72. package/lambda-package/sanitizer/severity-classifier.d.ts +33 -0
  73. package/lambda-package/sanitizer/severity-classifier.d.ts.map +1 -0
  74. package/lambda-package/sanitizer/severity-classifier.js +113 -0
  75. package/lambda-package/sanitizer/severity-classifier.js.map +1 -0
  76. package/lambda-package/sanitizer/threat-reporter.d.ts +66 -0
  77. package/lambda-package/sanitizer/threat-reporter.d.ts.map +1 -0
  78. package/lambda-package/sanitizer/threat-reporter.js +163 -0
  79. package/lambda-package/sanitizer/threat-reporter.js.map +1 -0
  80. package/lambda-package/tools/fetch-structured.d.ts +51 -0
  81. package/lambda-package/tools/fetch-structured.d.ts.map +1 -0
  82. package/lambda-package/tools/fetch-structured.js +237 -0
  83. package/lambda-package/tools/fetch-structured.js.map +1 -0
  84. package/lambda-package/tools/fetch.d.ts +49 -0
  85. package/lambda-package/tools/fetch.d.ts.map +1 -0
  86. package/lambda-package/tools/fetch.js +131 -0
  87. package/lambda-package/tools/fetch.js.map +1 -0
  88. package/lambda-package/tools/read.d.ts +51 -0
  89. package/lambda-package/tools/read.d.ts.map +1 -0
  90. package/lambda-package/tools/read.js +127 -0
  91. package/lambda-package/tools/read.js.map +1 -0
  92. package/lambda-package/tools/search.d.ts +45 -0
  93. package/lambda-package/tools/search.d.ts.map +1 -0
  94. package/lambda-package/tools/search.js +220 -0
  95. package/lambda-package/tools/search.js.map +1 -0
  96. package/lambda-package/types.d.ts +167 -0
  97. package/lambda-package/types.d.ts.map +1 -0
  98. package/lambda-package/types.js +16 -0
  99. package/lambda-package/types.js.map +1 -0
  100. package/lambda-package/utils/format-converter.d.ts +39 -0
  101. package/lambda-package/utils/format-converter.d.ts.map +1 -0
  102. package/lambda-package/utils/format-converter.js +191 -0
  103. package/lambda-package/utils/format-converter.js.map +1 -0
  104. package/lambda-package/utils/truncate.d.ts +26 -0
  105. package/lambda-package/utils/truncate.d.ts.map +1 -0
  106. package/lambda-package/utils/truncate.js +54 -0
  107. package/lambda-package/utils/truncate.js.map +1 -0
  108. package/lambda.zip +0 -0
  109. package/package.json +3 -2
  110. package/server.json +3 -3
  111. package/src/browser/playwright-renderer.ts +74 -51
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Visus MCP - Dual-Mode Entry Point (Phase 2)
4
+ *
5
+ * Supports two runtime modes:
6
+ * 1. stdio MCP server (npx visus-mcp) - Open source tier
7
+ * 2. AWS Lambda handler (API Gateway) - Hosted tier
8
+ *
9
+ * Runtime detection determines which mode to use based on environment variables.
10
+ *
11
+ * Tools:
12
+ * - visus_fetch: Fetch and sanitize web page content
13
+ * - visus_fetch_structured: Extract structured data from web pages
14
+ *
15
+ * ALL content passes through the Lateos injection sanitizer before reaching the LLM.
16
+ */
17
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
18
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
19
+ import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
20
+ import { visusFetch, visusFetchToolDefinition } from './tools/fetch.js';
21
+ import { visusFetchStructured, visusFetchStructuredToolDefinition } from './tools/fetch-structured.js';
22
+ import { visusRead, visusReadToolDefinition } from './tools/read.js';
23
+ import { visusSearch, visusSearchToolDefinition } from './tools/search.js';
24
+ import { closeBrowser } from './browser/playwright-renderer.js';
25
+ import { detectRuntime, logRuntimeConfig, validateRuntime } from './runtime.js';
26
+ import { shouldElicit } from './sanitizer/hitl-gate.js';
27
+ import { runElicitation } from './sanitizer/elicit-runner.js';
28
+ /**
29
+ * Create and configure the MCP server
30
+ */
31
+ const server = new Server({
32
+ name: 'visus-mcp',
33
+ version: '0.6.0'
34
+ }, {
35
+ capabilities: {
36
+ tools: {}
37
+ }
38
+ });
39
+ /**
40
+ * Handle tool list requests
41
+ */
42
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
43
+ return {
44
+ tools: [
45
+ visusFetchToolDefinition,
46
+ visusFetchStructuredToolDefinition,
47
+ visusReadToolDefinition,
48
+ visusSearchToolDefinition
49
+ ]
50
+ };
51
+ });
52
+ /**
53
+ * Helper function to handle HITL elicitation for CRITICAL threats
54
+ *
55
+ * Returns modified output with threat_report removed if user declined,
56
+ * or blocked response if user declined to proceed.
57
+ */
58
+ async function handleCriticalThreatElicitation(output, url) {
59
+ const threatReport = output.threat_report;
60
+ // Check if elicitation is needed
61
+ if (shouldElicit(threatReport ?? null)) {
62
+ const { proceed, includeReport } = await runElicitation(server, threatReport, url);
63
+ if (!proceed) {
64
+ // User declined — return blocked response with threat report
65
+ return {
66
+ output: {
67
+ url,
68
+ blocked: true,
69
+ reason: 'User declined to proceed after CRITICAL threat detected',
70
+ threat_report: threatReport
71
+ },
72
+ blocked: true
73
+ };
74
+ }
75
+ // User accepted — proceed with sanitized content
76
+ // Remove threat_report if user didn't request it
77
+ if (!includeReport && output.threat_report) {
78
+ const { threat_report, ...outputWithoutReport } = output;
79
+ return { output: outputWithoutReport, blocked: false };
80
+ }
81
+ }
82
+ return { output, blocked: false };
83
+ }
84
+ /**
85
+ * Handle tool execution requests
86
+ */
87
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
88
+ const { name, arguments: args } = request.params;
89
+ try {
90
+ switch (name) {
91
+ case 'visus_fetch': {
92
+ const result = await visusFetch(args);
93
+ if (!result.ok) {
94
+ throw new McpError(ErrorCode.InternalError, `visus_fetch failed: ${result.error.message}`);
95
+ }
96
+ // Handle HITL elicitation for CRITICAL threats
97
+ const { output } = await handleCriticalThreatElicitation(result.value, args.url);
98
+ return {
99
+ content: [
100
+ {
101
+ type: 'text',
102
+ text: JSON.stringify(output, null, 2)
103
+ }
104
+ ]
105
+ };
106
+ }
107
+ case 'visus_fetch_structured': {
108
+ const result = await visusFetchStructured(args);
109
+ if (!result.ok) {
110
+ throw new McpError(ErrorCode.InternalError, `visus_fetch_structured failed: ${result.error.message}`);
111
+ }
112
+ // Handle HITL elicitation for CRITICAL threats
113
+ const { output } = await handleCriticalThreatElicitation(result.value, args.url);
114
+ return {
115
+ content: [
116
+ {
117
+ type: 'text',
118
+ text: JSON.stringify(output, null, 2)
119
+ }
120
+ ]
121
+ };
122
+ }
123
+ case 'visus_read': {
124
+ const result = await visusRead(args);
125
+ if (!result.ok) {
126
+ throw new McpError(ErrorCode.InternalError, `visus_read failed: ${result.error.message}`);
127
+ }
128
+ // Handle HITL elicitation for CRITICAL threats
129
+ const { output } = await handleCriticalThreatElicitation(result.value, args.url);
130
+ return {
131
+ content: [
132
+ {
133
+ type: 'text',
134
+ text: JSON.stringify(output, null, 2)
135
+ }
136
+ ]
137
+ };
138
+ }
139
+ case 'visus_search': {
140
+ const result = await visusSearch(args);
141
+ if (!result.ok) {
142
+ throw new McpError(ErrorCode.InternalError, `visus_search failed: ${result.error.message}`);
143
+ }
144
+ // Handle HITL elicitation for CRITICAL threats
145
+ // For search, use the query as the "URL" in the elicitation message
146
+ const { output } = await handleCriticalThreatElicitation(result.value, `search: ${args.query}`);
147
+ return {
148
+ content: [
149
+ {
150
+ type: 'text',
151
+ text: JSON.stringify(output, null, 2)
152
+ }
153
+ ]
154
+ };
155
+ }
156
+ default:
157
+ throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
158
+ }
159
+ }
160
+ catch (error) {
161
+ if (error instanceof McpError) {
162
+ throw error;
163
+ }
164
+ throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : String(error)}`);
165
+ }
166
+ });
167
+ /**
168
+ * Start the MCP server (stdio mode)
169
+ */
170
+ async function startMcpServer() {
171
+ const transport = new StdioServerTransport();
172
+ // Connect server to transport
173
+ await server.connect(transport);
174
+ // Log startup to stderr (not stdout - MCP uses stdout)
175
+ console.error(JSON.stringify({
176
+ timestamp: new Date().toISOString(),
177
+ event: 'mcp_server_started',
178
+ name: 'visus-mcp',
179
+ version: '0.6.0',
180
+ tools: ['visus_fetch', 'visus_fetch_structured', 'visus_read', 'visus_search']
181
+ }));
182
+ // Graceful shutdown
183
+ process.on('SIGINT', async () => {
184
+ console.error(JSON.stringify({
185
+ timestamp: new Date().toISOString(),
186
+ event: 'mcp_server_shutdown'
187
+ }));
188
+ await closeBrowser();
189
+ process.exit(0);
190
+ });
191
+ process.on('SIGTERM', async () => {
192
+ console.error(JSON.stringify({
193
+ timestamp: new Date().toISOString(),
194
+ event: 'mcp_server_shutdown'
195
+ }));
196
+ await closeBrowser();
197
+ process.exit(0);
198
+ });
199
+ }
200
+ /**
201
+ * Main entry point - Dual-mode detection
202
+ */
203
+ async function main() {
204
+ // Detect runtime environment
205
+ const runtime = detectRuntime();
206
+ logRuntimeConfig(runtime);
207
+ validateRuntime(runtime);
208
+ // Route to appropriate entry point
209
+ if (runtime.isStdio) {
210
+ // Open-source tier: stdio MCP server
211
+ await startMcpServer();
212
+ }
213
+ else if (runtime.isLambda) {
214
+ // Hosted tier: Lambda handler
215
+ // In Lambda mode, the handler is exported and invoked by AWS
216
+ // This code path is not executed; see lambda-handler.ts export below
217
+ console.error(JSON.stringify({
218
+ timestamp: new Date().toISOString(),
219
+ event: 'lambda_mode_detected',
220
+ message: 'Lambda handler will be invoked by AWS runtime'
221
+ }));
222
+ }
223
+ }
224
+ // Export Lambda handler (for AWS deployment)
225
+ // This is only used when the file is imported as a module by Lambda runtime
226
+ export { handler } from './lambda-handler.js';
227
+ // Run stdio MCP server when executed directly (not in Lambda)
228
+ if (!process.env.AWS_LAMBDA_FUNCTION_NAME) {
229
+ main().catch((error) => {
230
+ console.error(JSON.stringify({
231
+ timestamp: new Date().toISOString(),
232
+ event: 'startup_error',
233
+ error: error instanceof Error ? error.message : String(error)
234
+ }));
235
+ process.exit(1);
236
+ });
237
+ }
238
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * AWS Lambda Handler - Phase 2 Hosted Tier
3
+ *
4
+ * Provides RESTful API endpoint for Visus sanitization service
5
+ * Invoked via API Gateway → Lambda → DynamoDB audit logging
6
+ *
7
+ * SECURITY RULES (from CLAUDE.md):
8
+ * - No secrets in code (use Secrets Manager)
9
+ * - No wildcard IAM permissions
10
+ * - All user input sanitized
11
+ * - No cross-user data access
12
+ * - Reserved concurrent executions set
13
+ * - No plaintext logging of tokens/PII
14
+ */
15
+ import type { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
16
+ /**
17
+ * Lambda handler for Visus API
18
+ *
19
+ * Routes:
20
+ * - POST /fetch → visus_fetch
21
+ * - POST /fetch-structured → visus_fetch_structured
22
+ *
23
+ * @param event API Gateway event
24
+ * @param context Lambda context
25
+ * @returns API Gateway response
26
+ */
27
+ export declare function handler(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult>;
28
+ //# sourceMappingURL=lambda-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda-handler.d.ts","sourceRoot":"","sources":["../src/lambda-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAsFvF;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,oBAAoB,EAC3B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC,CAsNhC"}
@@ -0,0 +1,257 @@
1
+ /**
2
+ * AWS Lambda Handler - Phase 2 Hosted Tier
3
+ *
4
+ * Provides RESTful API endpoint for Visus sanitization service
5
+ * Invoked via API Gateway → Lambda → DynamoDB audit logging
6
+ *
7
+ * SECURITY RULES (from CLAUDE.md):
8
+ * - No secrets in code (use Secrets Manager)
9
+ * - No wildcard IAM permissions
10
+ * - All user input sanitized
11
+ * - No cross-user data access
12
+ * - Reserved concurrent executions set
13
+ * - No plaintext logging of tokens/PII
14
+ */
15
+ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
16
+ import { DynamoDBDocumentClient, PutCommand } from '@aws-sdk/lib-dynamodb';
17
+ import { visusFetch } from './tools/fetch.js';
18
+ import { visusFetchStructured } from './tools/fetch-structured.js';
19
+ import { closeBrowser } from './browser/playwright-renderer.js';
20
+ // Initialize DynamoDB client
21
+ const ddbClient = new DynamoDBClient({});
22
+ const docClient = DynamoDBDocumentClient.from(ddbClient);
23
+ /**
24
+ * Fire-and-forget audit logging to DynamoDB
25
+ *
26
+ * Logs request metadata without blocking the response.
27
+ * Errors are logged but do not affect the API response.
28
+ *
29
+ * @param userId User ID from Cognito JWT
30
+ * @param requestId AWS request ID
31
+ * @param url URL being fetched
32
+ * @param endpoint API endpoint (/fetch or /fetch-structured)
33
+ * @param patternsDetected Sanitization patterns detected
34
+ * @param piiRedacted PII types redacted
35
+ */
36
+ function logAuditEvent(userId, requestId, url, endpoint, patternsDetected, piiRedacted) {
37
+ const tableName = process.env.AUDIT_TABLE_NAME;
38
+ if (!tableName) {
39
+ console.error('AUDIT_TABLE_NAME not set - skipping audit logging');
40
+ return;
41
+ }
42
+ const now = new Date();
43
+ const ttl = Math.floor(now.getTime() / 1000) + (30 * 24 * 60 * 60); // 30 days from now
44
+ const item = {
45
+ user_id: userId,
46
+ timestamp: now.toISOString(),
47
+ request_id: requestId,
48
+ url,
49
+ endpoint,
50
+ patterns_detected: patternsDetected,
51
+ pii_redacted: piiRedacted,
52
+ ttl, // Auto-delete after 30 days
53
+ };
54
+ // Fire-and-forget: do not await
55
+ docClient.send(new PutCommand({
56
+ TableName: tableName,
57
+ Item: item,
58
+ })).catch((error) => {
59
+ // Log error but do not throw (fire-and-forget pattern)
60
+ console.error(JSON.stringify({
61
+ timestamp: now.toISOString(),
62
+ event: 'audit_logging_failed',
63
+ error: error instanceof Error ? error.message : String(error),
64
+ request_id: requestId,
65
+ }));
66
+ });
67
+ }
68
+ /**
69
+ * Lambda handler for Visus API
70
+ *
71
+ * Routes:
72
+ * - POST /fetch → visus_fetch
73
+ * - POST /fetch-structured → visus_fetch_structured
74
+ *
75
+ * @param event API Gateway event
76
+ * @param context Lambda context
77
+ * @returns API Gateway response
78
+ */
79
+ export async function handler(event, context) {
80
+ const requestId = context.awsRequestId;
81
+ // Log request to stderr
82
+ console.error(JSON.stringify({
83
+ timestamp: new Date().toISOString(),
84
+ event: 'lambda_invocation',
85
+ request_id: requestId,
86
+ path: event.path,
87
+ method: event.httpMethod,
88
+ source_ip: event.requestContext.identity.sourceIp,
89
+ user_agent: event.headers['User-Agent'] || event.headers['user-agent'],
90
+ }));
91
+ try {
92
+ // CORS headers for all responses (environment-variable-driven allowlist)
93
+ const allowedOrigins = (process.env.ALLOWED_ORIGINS || '*').split(',');
94
+ const origin = event.headers.origin || event.headers.Origin || '';
95
+ const allowOrigin = allowedOrigins.includes(origin) ? origin : allowedOrigins[0] || '*';
96
+ const corsHeaders = {
97
+ 'Access-Control-Allow-Origin': allowOrigin,
98
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
99
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
100
+ 'Content-Type': 'application/json',
101
+ };
102
+ // Handle preflight OPTIONS request
103
+ if (event.httpMethod === 'OPTIONS') {
104
+ return {
105
+ statusCode: 200,
106
+ headers: corsHeaders,
107
+ body: '',
108
+ };
109
+ }
110
+ // Health check endpoint (no auth required, allows GET and POST)
111
+ // SECURITY FIX (FINDING 2): Moved before POST-only validation to support standard GET health checks
112
+ if (event.path === '/health' || event.path === '/dev/health' || event.path === '/prod/health') {
113
+ return {
114
+ statusCode: 200,
115
+ headers: corsHeaders,
116
+ body: JSON.stringify({
117
+ status: 'healthy',
118
+ service: 'visus-mcp',
119
+ version: '0.3.1',
120
+ timestamp: new Date().toISOString(),
121
+ }),
122
+ };
123
+ }
124
+ // Only allow POST requests for protected endpoints
125
+ if (event.httpMethod !== 'POST') {
126
+ return {
127
+ statusCode: 405,
128
+ headers: corsHeaders,
129
+ body: JSON.stringify({ error: 'Method not allowed. Use POST.' }),
130
+ };
131
+ }
132
+ // Parse request body
133
+ let body;
134
+ try {
135
+ body = JSON.parse(event.body || '{}');
136
+ }
137
+ catch (error) {
138
+ return {
139
+ statusCode: 400,
140
+ headers: corsHeaders,
141
+ body: JSON.stringify({ error: 'Invalid JSON in request body' }),
142
+ };
143
+ }
144
+ // SECURITY FIX (FINDING 1): Application-level authentication enforcement
145
+ // Extract user ID from Cognito authorizer
146
+ const userId = event.requestContext.authorizer?.claims?.sub;
147
+ // Require authentication for all protected endpoints (not already handled above)
148
+ if (!userId) {
149
+ console.error(JSON.stringify({
150
+ timestamp: new Date().toISOString(),
151
+ event: 'auth_required',
152
+ request_id: requestId,
153
+ path: event.path,
154
+ reason: 'Missing Cognito authorizer context - Lambda must be invoked via API Gateway',
155
+ }));
156
+ return {
157
+ statusCode: 401,
158
+ headers: corsHeaders,
159
+ body: JSON.stringify({
160
+ error: 'Unauthorized: Authentication required. This Lambda must be invoked via API Gateway with Cognito authorizer.',
161
+ }),
162
+ };
163
+ }
164
+ // Route based on path
165
+ if (event.path === '/fetch' || event.path === '/dev/fetch' || event.path === '/prod/fetch') {
166
+ const fetchReq = body;
167
+ // Validate request
168
+ if (!fetchReq.url || typeof fetchReq.url !== 'string') {
169
+ return {
170
+ statusCode: 400,
171
+ headers: corsHeaders,
172
+ body: JSON.stringify({ error: 'Missing or invalid "url" field' }),
173
+ };
174
+ }
175
+ // Call visus_fetch
176
+ const result = await visusFetch(fetchReq);
177
+ if (!result.ok) {
178
+ return {
179
+ statusCode: 500,
180
+ headers: corsHeaders,
181
+ body: JSON.stringify({ error: result.error.message }),
182
+ };
183
+ }
184
+ // Fire-and-forget audit logging
185
+ logAuditEvent(userId, requestId, fetchReq.url, '/fetch', result.value.sanitization.patterns_detected, result.value.sanitization.pii_types_redacted);
186
+ return {
187
+ statusCode: 200,
188
+ headers: corsHeaders,
189
+ body: JSON.stringify(result.value),
190
+ };
191
+ }
192
+ if (event.path === '/fetch-structured' || event.path === '/dev/fetch-structured' || event.path === '/prod/fetch-structured') {
193
+ const fetchReq = body;
194
+ // Validate request
195
+ if (!fetchReq.url || typeof fetchReq.url !== 'string') {
196
+ return {
197
+ statusCode: 400,
198
+ headers: corsHeaders,
199
+ body: JSON.stringify({ error: 'Missing or invalid "url" field' }),
200
+ };
201
+ }
202
+ if (!fetchReq.schema || typeof fetchReq.schema !== 'object') {
203
+ return {
204
+ statusCode: 400,
205
+ headers: corsHeaders,
206
+ body: JSON.stringify({ error: 'Missing or invalid "schema" field' }),
207
+ };
208
+ }
209
+ // Call visus_fetch_structured
210
+ const result = await visusFetchStructured(fetchReq);
211
+ if (!result.ok) {
212
+ return {
213
+ statusCode: 500,
214
+ headers: corsHeaders,
215
+ body: JSON.stringify({ error: result.error.message }),
216
+ };
217
+ }
218
+ // Fire-and-forget audit logging
219
+ logAuditEvent(userId, requestId, fetchReq.url, '/fetch-structured', result.value.sanitization.patterns_detected, result.value.sanitization.pii_types_redacted);
220
+ return {
221
+ statusCode: 200,
222
+ headers: corsHeaders,
223
+ body: JSON.stringify(result.value),
224
+ };
225
+ }
226
+ // Unknown path
227
+ return {
228
+ statusCode: 404,
229
+ headers: corsHeaders,
230
+ body: JSON.stringify({ error: 'Not found. Use /fetch or /fetch-structured' }),
231
+ };
232
+ }
233
+ catch (error) {
234
+ // Log error to stderr (CloudWatch Logs)
235
+ console.error(JSON.stringify({
236
+ timestamp: new Date().toISOString(),
237
+ event: 'lambda_error',
238
+ request_id: requestId,
239
+ error: error instanceof Error ? error.message : String(error),
240
+ stack: error instanceof Error ? error.stack : undefined,
241
+ }));
242
+ return {
243
+ statusCode: 500,
244
+ headers: {
245
+ 'Content-Type': 'application/json',
246
+ 'Access-Control-Allow-Origin': '*',
247
+ },
248
+ body: JSON.stringify({ error: 'Internal server error' }),
249
+ };
250
+ }
251
+ finally {
252
+ // Close browser to free resources
253
+ // Lambda containers are reused, but we clean up after each invocation
254
+ await closeBrowser();
255
+ }
256
+ }
257
+ //# sourceMappingURL=lambda-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lambda-handler.js","sourceRoot":"","sources":["../src/lambda-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAEhE,6BAA6B;AAC7B,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AACzC,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAoBzD;;;;;;;;;;;;GAYG;AACH,SAAS,aAAa,CACpB,MAAc,EACd,SAAiB,EACjB,GAAW,EACX,QAAgB,EAChB,gBAA0B,EAC1B,WAAqB;IAErB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAE/C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,mBAAmB;IAEvF,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,MAAM;QACf,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;QAC5B,UAAU,EAAE,SAAS;QACrB,GAAG;QACH,QAAQ;QACR,iBAAiB,EAAE,gBAAgB;QACnC,YAAY,EAAE,WAAW;QACzB,GAAG,EAAE,4BAA4B;KAClC,CAAC;IAEF,gCAAgC;IAChC,SAAS,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC;QAC5B,SAAS,EAAE,SAAS;QACpB,IAAI,EAAE,IAAI;KACX,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC3B,uDAAuD;QACvD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;YAC5B,KAAK,EAAE,sBAAsB;YAC7B,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC7D,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAA2B,EAC3B,OAAgB;IAEhB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;IAEvC,wBAAwB;IACxB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;QAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,mBAAmB;QAC1B,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,UAAU;QACxB,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ;QACjD,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC;KACvE,CAAC,CAAC,CAAC;IAEJ,IAAI,CAAC;QACH,yEAAyE;QACzE,MAAM,cAAc,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;QAClE,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAExF,MAAM,WAAW,GAAG;YAClB,6BAA6B,EAAE,WAAW;YAC1C,8BAA8B,EAAE,oBAAoB;YACpD,8BAA8B,EAAE,6BAA6B;YAC7D,cAAc,EAAE,kBAAkB;SACnC,CAAC;QAEF,mCAAmC;QACnC,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,EAAE;aACT,CAAC;QACJ,CAAC;QAED,gEAAgE;QAChE,oGAAoG;QACpG,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC9F,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM,EAAE,SAAS;oBACjB,OAAO,EAAE,WAAW;oBACpB,OAAO,EAAE,OAAO;oBAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;iBACpC,CAAC;aACH,CAAC;QACJ,CAAC;QAED,mDAAmD;QACnD,IAAI,KAAK,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;YAChC,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;aACjE,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,IAAI,IAA2C,CAAC;QAChD,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC;aAChE,CAAC;QACJ,CAAC;QAED,yEAAyE;QACzE,0CAA0C;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC;QAE5D,iFAAiF;QACjF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;gBAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,KAAK,EAAE,eAAe;gBACtB,UAAU,EAAE,SAAS;gBACrB,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,6EAA6E;aACtF,CAAC,CAAC,CAAC;YAEJ,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,KAAK,EAAE,6GAA6G;iBACrH,CAAC;aACH,CAAC;QACJ,CAAC;QAED,sBAAsB;QACtB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3F,MAAM,QAAQ,GAAG,IAAoB,CAAC;YAEtC,mBAAmB;YACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACtD,OAAO;oBACL,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,WAAW;oBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;iBAClE,CAAC;YACJ,CAAC;YAED,mBAAmB;YACnB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;YAE1C,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO;oBACL,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,WAAW;oBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;iBACtD,CAAC;YACJ,CAAC;YAED,gCAAgC;YAChC,aAAa,CACX,MAAM,EACN,SAAS,EACT,QAAQ,CAAC,GAAG,EACZ,QAAQ,EACR,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,EAC3C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAC7C,CAAC;YAEF,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;aACnC,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;YAC5H,MAAM,QAAQ,GAAG,IAA8B,CAAC;YAEhD,mBAAmB;YACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACtD,OAAO;oBACL,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,WAAW;oBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;iBAClE,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAC5D,OAAO;oBACL,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,WAAW;oBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC;iBACrE,CAAC;YACJ,CAAC;YAED,8BAA8B;YAC9B,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YAEpD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO;oBACL,UAAU,EAAE,GAAG;oBACf,OAAO,EAAE,WAAW;oBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;iBACtD,CAAC;YACJ,CAAC;YAED,gCAAgC;YAChC,aAAa,CACX,MAAM,EACN,SAAS,EACT,QAAQ,CAAC,GAAG,EACZ,mBAAmB,EACnB,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,EAC3C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,CAC7C,CAAC;YAEF,OAAO;gBACL,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,WAAW;gBACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;aACnC,CAAC;QACJ,CAAC;QAED,eAAe;QACf,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,WAAW;YACpB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAC;SAC9E,CAAC;IAEJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wCAAwC;QACxC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,SAAS;YACrB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YAC7D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;SACxD,CAAC,CAAC,CAAC;QAEJ,OAAO;YACL,UAAU,EAAE,GAAG;YACf,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,6BAA6B,EAAE,GAAG;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;SACzD,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,kCAAkC;QAClC,sEAAsE;QACtE,MAAM,YAAY,EAAE,CAAC;IACvB,CAAC;AACH,CAAC"}