@@ -2,27 +2,68 @@ import { createMcpHandler } from "@vercel/mcp-adapter";
22import { z } from "zod" ;
33import { prisma } from '@/app/prisma' ;
44import { NextRequest } from 'next/server' ;
5- import { analyticsDB , getClientIP } from '@/lib/analytics-db' ;
5+
6+ // Utility function for getting client IP
7+ function getClientIP ( request : NextRequest ) : string {
8+ const forwarded = request . headers . get ( 'x-forwarded-for' ) ;
9+ if ( forwarded ) {
10+ return forwarded . split ( ',' ) [ 0 ] . trim ( ) ;
11+ }
12+
13+ const realIP = request . headers . get ( 'x-real-ip' ) ;
14+ if ( realIP ) {
15+ return realIP ;
16+ }
17+
18+ const cfConnectingIP = request . headers . get ( 'cf-connecting-ip' ) ;
19+ if ( cfConnectingIP ) {
20+ return cfConnectingIP ;
21+ }
22+
23+ return '127.0.0.1' ;
24+ }
25+
26+ // Helper function to log security events (Edge Runtime compatible)
27+ async function logSecurityEvent ( request : NextRequest , eventType : string , details : string , clientId ?: string ) {
28+ try {
29+ const host = request . headers . get ( 'host' ) ;
30+ const protocol = process . env . NODE_ENV === 'production' ? 'https' : 'http' ;
31+ const baseUrl = `${ protocol } ://${ host } ` ;
32+
33+ const securityData = {
34+ timestamp : new Date ( ) . toISOString ( ) ,
35+ eventType,
36+ ipAddress : getClientIP ( request ) ,
37+ userAgent : request . headers . get ( 'user-agent' ) || '' ,
38+ clientId,
39+ details
40+ } ;
41+
42+ await fetch ( `${ baseUrl } /api/analytics/security` , {
43+ method : 'POST' ,
44+ headers : {
45+ 'Content-Type' : 'application/json' ,
46+ } ,
47+ body : JSON . stringify ( securityData )
48+ } ) . catch ( ( ) => {
49+ // Silent fail - security logging shouldn't break auth
50+ } ) ;
51+ } catch ( error ) {
52+ console . warn ( 'Security event logging failed:' , error ) ;
53+ }
54+ }
655
756// Authentication helper
857async function authenticateRequest ( request : NextRequest ) {
958 const authHeader = request . headers . get ( 'authorization' ) ;
10- const ip = getClientIP ( request ) ;
11- const userAgent = request . headers . get ( 'user-agent' ) || '' ;
1259
1360 console . log ( '[MCP] Auth header present:' , ! ! authHeader ) ;
1461
1562 if ( ! authHeader ) {
1663 console . log ( '[MCP] No auth header, returning 401' ) ;
1764
1865 // Log security event for missing auth
19- analyticsDB . logSecurityEvent ( {
20- timestamp : new Date ( ) ,
21- eventType : 'auth_failure' ,
22- ipAddress : ip ,
23- userAgent,
24- details : 'Missing authorization header'
25- } ) ;
66+ await logSecurityEvent ( request , 'auth_failure' , 'Missing authorization header' ) ;
2667
2768 return null ;
2869 }
@@ -34,13 +75,7 @@ async function authenticateRequest(request: NextRequest) {
3475 console . log ( '[MCP] No token, returning 401' ) ;
3576
3677 // Log security event for malformed auth header
37- analyticsDB . logSecurityEvent ( {
38- timestamp : new Date ( ) ,
39- eventType : 'auth_failure' ,
40- ipAddress : ip ,
41- userAgent,
42- details : 'Malformed authorization header'
43- } ) ;
78+ await logSecurityEvent ( request , 'auth_failure' , 'Malformed authorization header' ) ;
4479
4580 return null ;
4681 }
@@ -61,13 +96,7 @@ async function authenticateRequest(request: NextRequest) {
6196 console . log ( '[MCP] No access token found, returning 401' ) ;
6297
6398 // Log security event for invalid token
64- analyticsDB . logSecurityEvent ( {
65- timestamp : new Date ( ) ,
66- eventType : 'invalid_token' ,
67- ipAddress : ip ,
68- userAgent,
69- details : 'Invalid access token provided'
70- } ) ;
99+ await logSecurityEvent ( request , 'invalid_token' , 'Invalid access token provided' ) ;
71100
72101 return null ;
73102 }
@@ -79,14 +108,7 @@ async function authenticateRequest(request: NextRequest) {
79108 console . log ( '[MCP] Token expired, returning 401' ) ;
80109
81110 // Log security event for expired token
82- analyticsDB . logSecurityEvent ( {
83- timestamp : new Date ( ) ,
84- eventType : 'invalid_token' ,
85- ipAddress : ip ,
86- userAgent,
87- clientId : accessToken . clientId ,
88- details : 'Expired access token used'
89- } ) ;
111+ await logSecurityEvent ( request , 'invalid_token' , 'Expired access token used' , accessToken . clientId ) ;
90112
91113 return null ;
92114 }
@@ -100,14 +122,9 @@ async function authenticateRequest(request: NextRequest) {
100122 console . log ( '[MCP] Token audience mismatch. Expected:' , currentResource , 'Got:' , accessToken . resource ) ;
101123
102124 // Log security event for audience mismatch
103- analyticsDB . logSecurityEvent ( {
104- timestamp : new Date ( ) ,
105- eventType : 'suspicious_activity' ,
106- ipAddress : ip ,
107- userAgent,
108- clientId : accessToken . clientId ,
109- details : `Token audience mismatch. Expected: ${ currentResource } , Got: ${ accessToken . resource } `
110- } ) ;
125+ await logSecurityEvent ( request , 'suspicious_activity' ,
126+ `Token audience mismatch. Expected: ${ currentResource } , Got: ${ accessToken . resource } ` ,
127+ accessToken . clientId ) ;
111128
112129 return null ;
113130 }
@@ -118,13 +135,8 @@ async function authenticateRequest(request: NextRequest) {
118135 console . error ( '[MCP] Error validating token:' , e ) ;
119136
120137 // Log security event for authentication error
121- analyticsDB . logSecurityEvent ( {
122- timestamp : new Date ( ) ,
123- eventType : 'auth_failure' ,
124- ipAddress : ip ,
125- userAgent,
126- details : `Authentication error: ${ e instanceof Error ? e . message : 'Unknown error' } `
127- } ) ;
138+ await logSecurityEvent ( request , 'auth_failure' ,
139+ `Authentication error: ${ e instanceof Error ? e . message : 'Unknown error' } ` ) ;
128140
129141 return null ;
130142 }
0 commit comments