@@ -71,6 +71,7 @@ export class ContextStorage extends DurableObject {
7171 customerContext ,
7272 this . ctx . id . toString ( ) . slice ( - 6 )
7373 ) ;
74+
7475 await this . ctx . storage . put ( "customerContext" , customerContext ) ;
7576 }
7677
@@ -140,7 +141,9 @@ export class DoitMCPAgent extends McpAgent {
140141 private createToolCallback ( toolName : string ) {
141142 return async ( args : any ) => {
142143 const token = this . getToken ( ) ;
143- const customerContext = await this . loadPersistedProps ( ) ;
144+ const persistedCustomerContext = await this . loadPersistedProps ( ) ;
145+ const customerContext =
146+ persistedCustomerContext || ( this . props . customerContext as string ) ;
144147
145148 const argsWithCustomerContext = {
146149 ...args ,
@@ -271,13 +274,88 @@ async function handleMcpRequest(req: Request, env: Env, ctx: ExecutionContext) {
271274 return new Response ( "Not found" , { status : 404 } ) ;
272275}
273276
274- // Export the OAuth handler as the default
275- export default new OAuthProvider ( {
277+ // Helper function to extract token from Authorization header
278+ function extractTokenFromAuthHeader ( authHeader : string ) : string | null {
279+ if ( ! authHeader ) return null ;
280+
281+ // Support both "Bearer <token>" and just "<token>" formats
282+ const bearerMatch = authHeader . match ( / ^ B e a r e r \s + ( .+ ) $ / i) ;
283+ if ( bearerMatch ) {
284+ return bearerMatch [ 1 ] ;
285+ }
286+
287+ // If no Bearer prefix, assume the whole header is the token
288+ return authHeader ;
289+ }
290+
291+ // Create the OAuth provider instance
292+ const oauthProvider = new OAuthProvider ( {
276293 apiHandler : { fetch : handleMcpRequest as any } ,
277294 apiRoute : [ "/sse" , "/mcp" ] ,
278295 // @ts -expect-error
279296 defaultHandler : app ,
280297 authorizeEndpoint : "/authorize" ,
281298 tokenEndpoint : "/token" ,
282299 clientRegistrationEndpoint : "/register" ,
300+ accessTokenTTL : 1000 * 60 * 60 * 24 * 24 , // 24 days (2,073,600,000 - within 32-bit range)
301+ tokenExchangeCallback : async ( { grantType, props } ) => {
302+ console . log ( "tokenExchangeCallback" , grantType , props ) ;
303+ if ( grantType === "refresh_token" || grantType === "authorization_code" ) {
304+ return {
305+ newProps : {
306+ ...props ,
307+ customerContext : props . customerContext ,
308+ apiKey : props . apiKey ,
309+ isDoitUser : props . isDoitUser ,
310+ } ,
311+ } ;
312+ }
313+ } ,
283314} ) ;
315+
316+ // Main request handler that checks for Authorization header
317+ async function handleRequest (
318+ req : Request ,
319+ env : Env ,
320+ ctx : ExecutionContext
321+ ) : Promise < Response > {
322+ const url = new URL ( req . url ) ;
323+ const authHeader = req . headers . get ( "Authorization" ) ;
324+
325+ // Check if this is an API route and has Authorization header
326+ if (
327+ ( url . pathname === "/sse" ||
328+ url . pathname === "/sse/message" ||
329+ url . pathname === "/mcp" ) &&
330+ authHeader
331+ ) {
332+ const token = extractTokenFromAuthHeader ( authHeader ) ;
333+ const customerContext = url . searchParams . get ( "customerContext" ) || "" ;
334+
335+ if ( token && customerContext ) {
336+ console . log ( "Using Authorization header for authentication" ) ;
337+
338+ ctx . props = {
339+ ...ctx . props ,
340+ apiKey : token ,
341+ customerContext : customerContext ,
342+ } ;
343+
344+ // Handle the request directly with the modified request
345+ if ( url . pathname === "/sse" || url . pathname === "/sse/message" ) {
346+ return DoitMCPAgent . serveSSE ( "/sse" ) . fetch ( req , env , ctx ) ;
347+ }
348+ if ( url . pathname === "/mcp" ) {
349+ return DoitMCPAgent . serve ( "/mcp" ) . fetch ( req , env , ctx ) ;
350+ }
351+ }
352+ }
353+
354+ // If no Authorization header or not an API route, use the OAuth provider
355+ return oauthProvider . fetch ( req , env , ctx ) ;
356+ }
357+
358+ // Export the main handler as the default
359+ export default {
360+ fetch : handleRequest ,
361+ } ;
0 commit comments