mcp-use 2.7.3 → 2.8.0-canary.1

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 (67) hide show
  1. package/dist/bin.js +1 -1
  2. package/dist/branding.d.ts +4 -4
  3. package/dist/chunk-BNLXCMPL.js +11 -0
  4. package/dist/chunk-EI7MMDWY.js +1 -0
  5. package/dist/chunk-HAV435PF.js +1 -0
  6. package/dist/chunk-LPMFXLNI.js +1 -0
  7. package/dist/chunk-TCIRBQPM.js +1 -0
  8. package/dist/{chunk-FRVJVG2A.js → chunk-TTX5MUYW.js} +1 -1
  9. package/dist/chunk-YI27EOFM.js +1 -0
  10. package/dist/gate-GHSM72MD.js +1 -0
  11. package/dist/index-node.js +14 -14
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.js +22 -19
  14. package/dist/internal/buffered-response.js +1 -0
  15. package/dist/internal/resource-completion.js +1 -1
  16. package/dist/internal/usage.js +2 -1
  17. package/dist/{chunk-Z6ROXYBJ.js → landing-handler-3ZBRKAI2.js} +41 -41
  18. package/dist/landing.js +666 -1
  19. package/dist/mcp-proxy-YSI2UFBY.js +2 -0
  20. package/dist/mcp-proxy.d.ts +2 -0
  21. package/dist/node-bridge.js +1 -1
  22. package/dist/oauth/auth0.js +1 -1
  23. package/dist/oauth/better-auth.js +1 -1
  24. package/dist/oauth/clerk.js +1 -1
  25. package/dist/oauth/convex.js +1 -1
  26. package/dist/oauth/index.js +1 -1
  27. package/dist/oauth/keycloak.js +1 -1
  28. package/dist/oauth/scalekit.js +1 -1
  29. package/dist/oauth/supabase.js +1 -1
  30. package/dist/oauth/workos.js +1 -1
  31. package/dist/openapi/index.js +3 -1
  32. package/dist/public-route-AVKCGJDQ.js +1 -0
  33. package/dist/react/hooks/use-deep-link.d.ts +31 -0
  34. package/dist/react/hooks/use-model-context.d.ts +28 -0
  35. package/dist/react/index.d.ts +3 -0
  36. package/dist/react/index.js +1209 -73
  37. package/dist/react/public-assets.d.ts +1 -2
  38. package/dist/react/runtime/bootstrap-view.d.ts +2 -1
  39. package/dist/react/runtime/model-context-image.d.ts +7 -0
  40. package/dist/react/runtime/model-context-store.d.ts +29 -12
  41. package/dist/react/runtime/model-context-wire.d.ts +34 -0
  42. package/dist/react/runtime/model-context.d.ts +46 -0
  43. package/dist/react/runtime/view-config.d.ts +13 -2
  44. package/dist/react/types/model-context.d.ts +64 -0
  45. package/dist/server.d.ts +13 -0
  46. package/dist/settings.d.ts +86 -0
  47. package/dist/tanstack-start/vite.js +1 -1
  48. package/dist/tools.d.ts +41 -1
  49. package/dist/views/entrypoints.d.ts +6 -0
  50. package/dist/views/types.d.ts +10 -0
  51. package/dist/views/wire.d.ts +2 -1
  52. package/dist/vite/index.js +1 -1
  53. package/package.json +10 -9
  54. package/dist/chunk-4TEUYGHH.js +0 -1
  55. package/dist/chunk-6KY574WV.js +0 -1
  56. package/dist/chunk-72EUVURD.js +0 -1
  57. package/dist/chunk-HQWSVX2E.js +0 -2
  58. package/dist/chunk-I46MEN5X.js +0 -1
  59. package/dist/chunk-M7NVJNT3.js +0 -11
  60. package/dist/chunk-OJF6B5EU.js +0 -1
  61. package/dist/chunk-PZTPSQGD.js +0 -1
  62. package/dist/chunk-Y26DNVWA.js +0 -3
  63. package/dist/chunk-YU52DKNS.js +0 -1
  64. package/dist/gate-GK4EU23Q.js +0 -1
  65. package/dist/landing-handler-UNCJYWGL.js +0 -1
  66. package/dist/mcp-proxy-VRA6MTY6.js +0 -2
  67. package/dist/public-route-7PHP6P3A.js +0 -1
package/dist/bin.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- var{main}=await import("@mcp-use/cli");main(process.argv.slice(2),{frameworkVersion:"2.7.3"}).then(code=>{process.exitCode=code},error=>{console.error(error instanceof Error?error.message:String(error)),process.exitCode=1});
2
+ var{main}=await import("@mcp-use/cli");main(process.argv.slice(2),{frameworkVersion:"2.8.0-canary.1"}).then(code=>{process.exitCode=code},error=>{console.error(error instanceof Error?error.message:String(error)),process.exitCode=1});
@@ -28,19 +28,19 @@ export declare function normalizeServerBranding(config: {
28
28
  websiteUrl?: unknown;
29
29
  }): ServerBranding;
30
30
  /**
31
- * Resolve configured icons for MCP implementation metadata.
31
+ * Resolve configured icons for MCP implementation and tool metadata.
32
32
  *
33
33
  * Absolute HTTP(S) and data URLs pass through. Public-relative sources become
34
34
  * request-scoped absolute URLs under `${basePath}/_mcp-use/public/`.
35
35
  *
36
- * @param icons - Normalized configured icons.
36
+ * @param icons - Configured icons, in author order.
37
37
  * @param request - HTTP request used to derive the public asset origin.
38
38
  * @param basePath - MCP endpoint base path.
39
- * @returns Icons suitable for the official SDK `Implementation` object.
39
+ * @returns Icons suitable for official SDK implementation and tool descriptors.
40
40
  *
41
41
  * @internal
42
42
  */
43
- export declare function resolveImplementationIcons(icons: readonly Icon[] | undefined, request: Request | undefined, basePath: string): Icon[] | undefined;
43
+ export declare function resolveImplementationIcons(icons: readonly Icon[], request: Request | undefined, basePath: string): Icon[];
44
44
  /**
45
45
  * Whether any configured branding source needs the local public route.
46
46
  *
@@ -0,0 +1,11 @@
1
+ import{toNodeHandler}from"./chunk-LPMFXLNI.js";import{randomBytes}from"crypto";import{readFile,readdir,writeFile}from"fs/promises";import{dirname,isAbsolute,join,relative,resolve}from"path";import{pathToFileURL}from"url";import{BuildEnvironment,createRunnableDevEnvironment,defaultAllowedOrigins,isRunnableDevEnvironment,normalizePath}from"vite";import{buildDevViewsManifest,readViewConfig,discoverViews,isViewEntryPath,mcpUseViewsPlugin,syncMcpEnvDeclaration,virtualViewId}from"@mcp-use/cli/internal/vite";import{discoverConfiguredSkills,resolveConfiguredSkillsDirectory}from"@mcp-use/cli/internal/skills-loader";var PUBLIC_CONTENT_TYPES={".css":"text/css",".gif":"image/gif",".html":"text/html",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".js":"application/javascript",".json":"application/json",".map":"application/json",".png":"image/png",".svg":"image/svg+xml",".txt":"text/plain",".webp":"image/webp",".woff":"font/woff",".woff2":"font/woff2"};function publicContentType(filename){let extension=filename.slice(filename.lastIndexOf(".")).toLowerCase();return PUBLIC_CONTENT_TYPES[extension]??"application/octet-stream"}function createDevRuntime(load,reportError){let active,revision=0,closed=!1,pending,lastError,dispose=async instance=>{try{await instance.close()}catch(error){reportError(error)}},reconcile=async()=>{let attempted;do{attempted=revision;try{let candidate=await load();if(closed||attempted!==revision){await dispose(candidate);continue}let previous=active;active={server:candidate,abort:new AbortController},lastError=void 0,previous&&(previous.abort.abort(new Error("MCP server updated")),await dispose(previous.server))}catch(error){!closed&&attempted===revision&&(lastError=error,reportError(error))}}while(!closed&&attempted!==revision)};return{reload(){return closed?Promise.resolve():(revision++,pending??=reconcile().finally(()=>{pending=void 0}),pending)},async fetch(request){if(closed)return new Response("MCP development server closed",{status:503});if(active||await pending,!active)throw lastError??new Error("MCP development server is not initialized");return active.server.fetch(new Request(request,{signal:AbortSignal.any([request.signal,active.abort.signal])}))},async close(){closed=!0;let previous=active;active=void 0,previous?.abort.abort(new Error("MCP development server closed")),await Promise.all([pending,previous&&dispose(previous.server)])}}}var HANDLER="#mcp-use-vite-handler",VIRTUAL_HANDLER="\0mcp-use:handler",ENTRY="\0mcp-use:server";function within(file,directory){let path=relative(directory,file);return path===""||!path.startsWith("..")&&!isAbsolute(path)}async function publicAssets(directory){let assets=Object.create(null);async function visit(root,prefix){let entries;try{entries=await readdir(root,{withFileTypes:!0})}catch(error){if(error.code==="ENOENT")return;throw error}for(let entry of entries){let path=join(root,entry.name);entry.isDirectory()?await visit(path,`${prefix}${entry.name}/`):entry.isFile()&&(assets[prefix+entry.name]={body:(await readFile(path)).toString("base64"),contentType:publicContentType(entry.name)})}}return await visit(directory,"public/"),assets}function mcpUse(options={}){let configuredBasePath=options.basePath??"/mcp",end=configuredBasePath.length;for(;end>0&&configuredBasePath[end-1]==="/";)end--;let basePath=configuredBasePath.slice(0,end);if(!basePath.startsWith("/")||basePath.includes("//")||/[:*?#\s]/.test(basePath))throw new Error("mcpUse basePath must be a concrete absolute path.");let config,root=process.cwd(),cors=!1,entry,views=[],devServer,runtime,skillsDirectory,timer,manifest={},frontendConfigs=new Map,assets={},skills,bridgePath=`/@mcp-use/${randomBytes(24).toString("hex")}`,viewsPlugin=mcpUseViewsPlugin({getViews:()=>views,tailwind:!1,environments:["client","mcpViews"]}),report=error=>config.logger.error(`[mcp-use] ${error instanceof Error?error.stack??error.message:String(error)}`),schedule=()=>{clearTimeout(timer),timer=setTimeout(()=>{runtime?.reload()},30)};async function prepare(server,dev){try{if(!server||typeof server.__primeViews!="function")throw new Error("The MCP entry must default-export an MCPServer instance.");if(server.basePath!==basePath)throw new Error(`MCP basePath mismatch: server uses ${server.basePath}, plugin uses ${basePath}.`);let conventionalSkills=join(dirname(options.entry??"src/mcp/server.ts"),"skills");skillsDirectory=resolveConfiguredSkillsDirectory(server.__skillsConfig(),config.root,conventionalSkills),dev&&skillsDirectory&&devServer.watcher.add(skillsDirectory),skills=discoverConfiguredSkills(server.__skillsConfig(),config.root,conventionalSkills),server.__primeSkills(skills);let devManifest=buildDevViewsManifest(views);for(let view of views)frontendConfigs.set(view.entryPath,JSON.stringify(devManifest[view.name]?.viewConfig));let base=config.base;if(base!=="/")for(let view of Object.values(devManifest))view.entry=base+view.entry.slice(1),view.scripts=view.scripts.map(path=>base+path.slice(1));return server.__primeViews(dev?devManifest:manifest,dev?{dev:!0,projectRoot:config.root}:{assets}),server.__mount(),server}catch(error){throw typeof server?.close=="function"&&await server.close().catch(report),error}}return[{name:"mcp-use",enforce:"pre",sharedDuringBuild:!0,config(userConfig,env){if(root=resolve(userConfig.root??process.cwd()),cors=userConfig.server?.cors??{origin:[defaultAllowedOrigins,"null"]},userConfig.environments?.mcp||userConfig.environments?.mcpViews)throw new Error("The mcp Vite environment is reserved by mcp-use.");return env.command==="serve"&&Object.assign(viewsPlugin,mcpUseViewsPlugin({getViews:()=>views,tailwind:!1,dev:{reactRefresh:!0}})),{environments:{mcp:{consumer:"server"},...env.command==="build"&&{mcpViews:{consumer:"client"}}},builder:{sharedConfigBuild:!0},server:{cors},resolve:{noExternal:["mcp-use"]}}},async configResolved(resolved){config=resolved,config.server.cors=cors,entry=normalizePath(resolve(config.root,options.entry??"src/mcp/server.ts")),views=discoverViews(config.root,options.viewsDir??"src/mcp/views"),await syncMcpEnvDeclaration(config.root,entry)},configEnvironment:{order:"post",handler(name,_environment,env){if(name==="mcp")return{consumer:"server",dev:{createEnvironment:(name2,resolved)=>createRunnableDevEnvironment(name2,resolved,{hot:!1})},build:{outDir:".mcp-use/vite/mcp",emptyOutDir:!0,copyPublicDir:!1,ssr:!0,rollupOptions:{input:ENTRY,output:{entryFileNames:"server.mjs"}}}};if(name==="mcpViews"&&env.command==="build"){let discovered=discoverViews(root,options.viewsDir??"src/mcp/views");return{build:{createEnvironment:(name2,resolved)=>new BuildEnvironment(name2,{...resolved,base:"./"}),outDir:".mcp-use/vite/views",emptyOutDir:!0,copyPublicDir:!1,rollupOptions:{input:discovered.length?Object.fromEntries(discovered.map(view=>[`mcp-${view.name}`,virtualViewId(view.name)])):"\0mcp-use:empty-views"}}}}}},async configureServer(server){devServer=server,cors!==!1&&server.middlewares.use((_req,res,next)=>{let setHeader=res.setHeader;res.setHeader=function(name,value){if(name.toLowerCase()==="vary"){let fields=String(value).split(",").map(field=>field.trim());fields.some(field=>field==="*"||field.toLowerCase()==="origin")||(value=[...fields,"Origin"].join(", "))}return setHeader.call(this,name,value)},res.setHeader("Vary","Origin"),next()});let environment=server.environments.mcp;if(!isRunnableDevEnvironment(environment))throw new Error("MCP requires a runnable Node Vite environment.");runtime=createDevRuntime(async()=>{views=discoverViews(config.root,options.viewsDir??"src/mcp/views"),environment.runner.evaluatedModules.clear();let module=await environment.runner.import(entry);return prepare(module.default,!0)},report);let handle=toNodeHandler({fetch:async request=>{let original=request.headers.get("x-mcp-use-url");if(!original)return new Response("Missing original URL",{status:400});let headers=new Headers(request.headers);return headers.delete("x-mcp-use-url"),headers.delete("host"),runtime.fetch(new Request(original,{method:request.method,headers,...request.body&&{body:request.body,duplex:"half"},signal:request.signal}))}},{onerror:report});server.middlewares.use((req,res,next)=>{if(req.url?.split("?")[0]!==bridgePath)return next();handle(req,res).catch(next)});let onDiscovery=file=>{(isViewEntryPath(file,config.root,options.viewsDir??"src/mcp/views")||skillsDirectory&&within(file,skillsDirectory))&&schedule()},onChange=file=>{let view=views.find(entry2=>normalizePath(entry2.entryPath)===normalizePath(file));if(view)try{JSON.stringify(readViewConfig(view.entryPath))!==frontendConfigs.get(view.entryPath)&&schedule()}catch{schedule()}skillsDirectory&&within(file,skillsDirectory)&&schedule()};server.watcher.on("add",onDiscovery).on("unlink",onDiscovery).on("addDir",onDiscovery).on("unlinkDir",onDiscovery).on("change",onChange);let close=server.close.bind(server);server.close=async()=>{clearTimeout(timer),server.watcher.off("add",onDiscovery).off("unlink",onDiscovery).off("addDir",onDiscovery).off("unlinkDir",onDiscovery).off("change",onChange),await runtime.close(),await close()},await runtime.reload()},hotUpdate({modules,timestamp}){if(this.environment.name==="mcp"){if(modules.length){let invalidated=new Set;for(let module of modules)this.environment.moduleGraph.invalidateModule(module,invalidated,timestamp,!0);schedule()}return[]}},resolveId(id){if(id==="\0mcp-use:empty-views")return id;if(id===HANDLER)return VIRTUAL_HANDLER;if(id===ENTRY)return ENTRY},load(id){if(id==="\0mcp-use:empty-views")return"export {};";if(id!==VIRTUAL_HANDLER&&id!==ENTRY)return;if(this.environment.config.consumer!=="server")throw new Error("The MCP handler must only be imported by a server route.");if(id===ENTRY)return`export { default } from ${JSON.stringify(entry)};`;if(!devServer)return`export { handleMcpRequest } from ${JSON.stringify(normalizePath(resolve(config.root,".mcp-use/vite/mcp/index.js")))};`;let address=devServer.httpServer?.address();if(!address||typeof address=="string")throw new Error("MCP development forwarding requires Vite's HTTP listener.");let host=address.address==="::"?"[::1]":address.address==="0.0.0.0"?"127.0.0.1":address.family==="IPv6"?`[${address.address}]`:address.address,url=`${config.server.https?"https":"http"}://${host}:${address.port}${bridgePath}`;return`export async function handleMcpRequest(request) {
2
+ const headers = new Headers(request.headers);
3
+ headers.set("x-mcp-use-url", request.url);
4
+ headers.delete("host");
5
+ return fetch(${JSON.stringify(url)}, { method: request.method, headers,
6
+ body: request.body, duplex: "half", signal: request.signal, redirect: "manual" });
7
+ }`},writeBundle(_options,bundle){if(this.environment.name!=="mcpViews")return;manifest={};let embedded=Object.create(null);assets=embedded;for(let view of views){let chunk=Object.values(bundle).find(output=>output.type==="chunk"&&output.facadeModuleId===`\0${virtualViewId(view.name)}`);if(!chunk)throw new Error(`Missing compiled MCP view ${view.name}`);let css=new Set,visited=new Set,visit=file=>{if(visited.has(file))return;visited.add(file);let output=bundle[file];if(output&&(embedded[`${view.name}/${file}`]={body:Buffer.from(output.type==="chunk"?output.code:output.source).toString("base64"),contentType:publicContentType(file)},output.type==="chunk")){for(let imported of[...output.imports,...output.dynamicImports])visit(imported);let metadata=output.viteMetadata;for(let file2 of metadata?.importedCss??[])css.add(file2),visit(file2);for(let file2 of metadata?.importedAssets??[])visit(file2)}};visit(chunk.fileName);for(let output of Object.values(bundle))output.type==="asset"&&visit(output.fileName);manifest[view.name]={kind:"external",viewConfig:readViewConfig(view.entryPath),entry:chunk.fileName,css:[...css]}}},async buildApp(builder){let client=builder.environments.mcpViews;client.isBuilt||await builder.build(client),config.publicDir&&Object.assign(assets,await publicAssets(config.publicDir));let mcp=builder.environments.mcp;mcp.isBuilt||await builder.build(mcp);let outputDirectory=resolve(config.root,mcp.config.build.outDir),compiledEntry=pathToFileURL(join(outputDirectory,"server.mjs"));compiledEntry.searchParams.set("validation",randomBytes(12).toString("hex"));let candidate;try{let compiled=await import(compiledEntry.href);candidate=await prepare(compiled.default,!1)}finally{await candidate?.close()}await writeFile(join(outputDirectory,"index.js"),`import server from "./server.mjs";
8
+ server.__primeViews(${JSON.stringify(manifest)}, {assets:${JSON.stringify(assets)}});
9
+ server.__primeSkills(${JSON.stringify(skills)});
10
+ export const handleMcpRequest = request => server.fetch(request);
11
+ `)}},viewsPlugin]}export{mcpUse};
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var d=(a,b)=>c(a,"name",{value:b,configurable:!0});export{d as a};
@@ -0,0 +1 @@
1
+ import{a as r}from"./chunk-EI7MMDWY.js";function c(e){return e.replace(/\/+$/,"")}r(c,"stripTrailingSlashes");function u(e){if(typeof process>"u")return;let n=process.env[e];return n!==void 0&&n!==""?n:void 0}r(u,"readEnv");function a(e){for(let n of e.split(",")){let s=new Map;for(let o of n.split(";")){let[d,...f]=o.trim().split("=");d===void 0||f.length===0||s.set(d.toLowerCase(),f.join("=").replace(/^"|"$/g,""))}let i=s.get("proto"),t=s.get("host");if(i!==void 0&&t!==void 0)return`${i}://${t}`}}r(a,"parseForwardedHeader");function l(e){let n=e.headers.get("forwarded");if(n!==null){let t=a(n);if(t!==void 0)return t}let s=e.headers.get("x-forwarded-proto"),i=e.headers.get("x-forwarded-host");if(s!==null&&i!==null){let t=i.split(",")[0]?.trim(),o=s.split(",")[0]?.trim();if(t!==void 0&&o!==void 0&&t!=="")return`${o}://${t}`}return new URL(e.url).origin}r(l,"resolveRequestOriginFromHeaders");function g(e){let n=u("MCP_URL");if(n!==void 0)try{return new URL(n).origin}catch{}return l(e)}r(g,"resolveServerOrigin");function h(e){try{return new URL(e).origin}catch{return e}}r(h,"originFromAssetsBase");function p(e){return c(e)}r(p,"normalizeAssetsBaseUrl");function w(e){let n=u("MCP_ASSETS_URL");if(n!==void 0)try{return p(new URL(n).href.replace(/\/$/,""))}catch{}return g(e)}r(w,"resolveAssetsBase");function R(){let e=u("MCP_ASSETS_URL");if(e===void 0)return!1;try{return new URL(e),!0}catch{return!1}}r(R,"hasExplicitAssetsBase");export{g as a,h as b,w as c,R as d};
@@ -0,0 +1 @@
1
+ import{isBufferedResponse}from"#mcp-use-buffered-response";function toNodeHandler(handler,opts){return async(req,res,parsedBody)=>{typeof parsedBody=="function"&&(parsedBody=void 0);let finished=!1,abort=new AbortController;res.on("close",()=>{finished||abort.abort()}),res.destroyed===!0&&abort.abort();let request,response;try{request=await toWebRequest(req,parsedBody,{signal:abort.signal}),response=await handler.fetch(request,{...req.auth!==void 0&&{authInfo:req.auth},...parsedBody!==void 0&&{parsedBody}})}catch(error){try{opts?.onerror?.(error instanceof Error?error:new Error(String(error)))}catch{}response=internalServerErrorResponse(echoableRequestId(parsedBody))}let headers={},setCookies=response.headers.getSetCookie?.();for(let[name,value]of response.headers){if(name==="set-cookie"&&setCookies?.length){headers[name]=setCookies;continue}headers[name]=value}if(res.writeHead(response.status,headers),response.body===null){finished=!0,res.end();return}if(isBufferedResponse(response,request)){try{let bytes=new Uint8Array(await response.arrayBuffer());finished=!0,res.end(bytes)}catch{finished=!0,res.end()}return}let drainResolve,releaseDrainWait=()=>{drainResolve?.(),drainResolve=void 0},waitForDrain=()=>new Promise(resolve=>{drainResolve=resolve});res.on("drain",releaseDrainWait);let closed=new Promise(resolve=>{abort.signal.addEventListener("abort",()=>resolve(),{once:!0})});try{for await(let chunk of response.body){if(abort.signal.aborted)break;let bytes=chunk instanceof Uint8Array?chunk:new Uint8Array(chunk);res.write(bytes)===!1&&await Promise.race([waitForDrain(),closed])}}catch{}finished=!0,res.end()}}async function toWebRequest(req,parsedBody,options){let method=(req.method??"GET").toUpperCase(),url=`http://${singleHeaderValue(req.headers.host)??singleHeaderValue(req.headers[":authority"])??"localhost"}${req.url??"/"}`,headers=new Headers;for(let[name,value]of Object.entries(req.headers))if(!(value===void 0||name.startsWith(":")))if(Array.isArray(value))for(let item of value)headers.append(name,item);else headers.set(name,value);let body;if(method!=="GET"&&method!=="HEAD")if(parsedBody===void 0){let decoder=new TextDecoder,collected="";for await(let chunk of req)collected+=typeof chunk=="string"?chunk:decoder.decode(chunk,{stream:!0});collected+=decoder.decode(),collected.length>0&&(body=collected)}else{let serialized=JSON.stringify(parsedBody);headers.delete("content-encoding"),headers.delete("transfer-encoding"),serialized===void 0?headers.delete("content-length"):(body=serialized,headers.set("content-length",String(new TextEncoder().encode(serialized).byteLength)))}return new Request(url,{method,headers,...options?.signal!==void 0&&{signal:options.signal},...body!==void 0&&{body}})}function singleHeaderValue(value){return Array.isArray(value)?value[0]:value}function echoableRequestId(body){if(body===null||typeof body!="object"||Array.isArray(body))return null;let{method,id}=body;return typeof method!="string"?null:typeof id=="string"||typeof id=="number"?id:null}function internalServerErrorResponse(id){return Response.json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id},{status:500})}export{toNodeHandler,toWebRequest};
@@ -0,0 +1 @@
1
+ import{a as o}from"./chunk-EI7MMDWY.js";var p={".css":"text/css",".gif":"image/gif",".html":"text/html",".ico":"image/x-icon",".jpeg":"image/jpeg",".jpg":"image/jpeg",".js":"application/javascript",".json":"application/json",".map":"application/json",".png":"image/png",".svg":"image/svg+xml",".txt":"text/plain",".webp":"image/webp",".woff":"font/woff",".woff2":"font/woff2"};function g(e){let t=e.slice(e.lastIndexOf(".")).toLowerCase();return p[t]??"application/octet-stream"}o(g,"publicContentType");async function u(e,t){let{stat:s}=await import("fs/promises"),{resolve:n,sep:r}=await import("path");if(t===""||t.includes("\\")||t.split("/").some(c=>c===".."))return null;let a=t.replace(/^\/+/,"");if(a===""||a.endsWith("/"))return null;let l=n(e),i=n(l,a);if(i!==l&&!i.startsWith(l+r))return null;try{if(!(await s(i)).isFile())return null}catch{return null}return i}o(u,"resolvePublicFilePath");async function f(e,t={}){let{readFile:s}=await import("fs/promises"),n=g(e),r=t.head===!0?null:new Uint8Array(await s(e));return new Response(r,{status:200,headers:{"Content-Type":n,"Cache-Control":"public, max-age=0, must-revalidate",...t.deferCors!==!0&&{"Access-Control-Allow-Origin":"*"}}})}o(f,"servePublicFile");export{g as a,u as b,f as c};
@@ -1 +1 @@
1
- function isRecord(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isLocalhost(url){let hostname=url.hostname.toLowerCase();return hostname==="localhost"||hostname.endsWith(".localhost")||hostname==="[::1]"||/^127(?:\.\d{1,3}){3}$/.test(hostname)}function parseAbsoluteUrl(value,name){let url;try{url=new URL(value)}catch{throw new Error(`${name} must be an absolute URL`)}if(url.origin==="null"||url.username!==""||url.password!=="")throw new Error(`${name} must be an absolute URL without credentials`);return url}function assertSecureHttpUrl(url,name){if(url.protocol!=="https:"&&!(url.protocol==="http:"&&isLocalhost(url)))throw new Error(`${name} must use HTTPS, or HTTP for localhost`)}import{OAuthError,OAuthErrorCode}from"@modelcontextprotocol/server";function invalidToken(message,cause){let error=new OAuthError(OAuthErrorCode.InvalidToken,message);return cause!==void 0&&(error.cause=cause),error}import{OAuthError as OAuthError2}from"@modelcontextprotocol/server";import{createRemoteJWKSet,jwtVerify,errors}from"jose";function createJwtVerifier(options){let key=options.key??createRemoteJWKSet(options.jwksUrl),configuredResource=configuredResourceUrl(options.resource),configuredAudience=verifierAudience(options.audience);if(configuredAudience!==void 0&&options.issuerBoundAccessTokens===!0)throw new TypeError("JWT verifier cannot combine audience and issuer-bound access tokens");return{async verifyAccessToken(token){try{let{payload}=await jwtVerify(token,key,{issuer:options.issuer,...configuredAudience!==void 0&&{audience:configuredAudience},...options.algorithms!==void 0&&{algorithms:[...options.algorithms]},requiredClaims:["exp","sub"]}),claims={...payload},clientId=requiredString(claims,"client_id")??requiredString(claims,"azp"),expiresAt=requiredFutureNumber(claims,"exp"),resource=verifiedResource(claims,configuredResource,configuredAudience!==void 0||options.issuerBoundAccessTokens===!0);return{token,clientId:clientId??"",scopes:normalizedStrings(claims.scope),expiresAt,extra:{payload:claims},resource}}catch(error){throw error instanceof OAuthError2?error:isCredentialFailure(error)?(process.env.MCP_USE_OAUTH_DEBUG&&logJwtFailure(token,error),invalidToken("JWT verification failed",error)):error}}}}function normalizedProviderUrl(value,name){let raw=typeof value=="string"&&!value.includes("://")?`https://${value}`:value,url;try{url=new URL(raw)}catch{throw new TypeError(`${name} must be an absolute HTTP(S) URL`)}if(!isAllowedHttpUrl(url))throw new TypeError(`${name} must use HTTPS, or HTTP for localhost, without credentials, query, or fragment`);return url.pathname=url.pathname.replace(/\/+$/,"")||"/",url}function providerEndpoint(issuer,path){let base=new URL(issuer);return base.pathname=`${base.pathname.replace(/\/+$/,"")}/`,new URL(path.replace(/^\/+/,""),base).href}function payloadFromAuthInfo(authInfo){let payload=authInfo.extra?.payload;if(!isRecord(payload))throw invalidToken("Verified token payload is missing");return payload}function requiredString(claims,name){let value=claims[name];return typeof value=="string"&&value.trim().length>0?value:void 0}function stringValue(claims,name){let value=claims[name];return typeof value=="string"?value:void 0}function booleanValue(claims,name){let value=claims[name];return typeof value=="boolean"?value:void 0}function numberValue(claims,name){let value=claims[name];return typeof value=="number"&&Number.isFinite(value)?value:void 0}function recordValue(claims,name){let value=claims[name];return isRecord(value)?value:void 0}function normalizedStrings(value){return typeof value=="string"?value.split(/\s+/).filter(Boolean):Array.isArray(value)?value.filter(item=>typeof item=="string"&&item.length>0):[]}function requiredFutureNumber(claims,name){let value=numberValue(claims,name);if(value===void 0||value<=Date.now()/1e3)throw invalidToken(`Missing or expired ${name} claim`);return value}function verifiedResource(claims,configuredResource,providerBindingWasValidated){let value=claims.resource;if(value!==void 0){if(typeof value!="string")throw invalidToken("Token resource claim must be an absolute URL");if(canonicalUrl(value).href!==configuredResource.href)throw invalidToken("Token resource claim does not match protected resource");return configuredResource}if(providerBindingWasValidated)return configuredResource;let audience=claims.aud;if(!validAudience(audience))throw invalidToken("Token audience claim must be a string or string array");if(!(typeof audience=="string"?[audience]:audience).includes(configuredResource.href))throw invalidToken("Token audience does not include the protected resource");return configuredResource}function verifierAudience(value){if(value!==void 0){if(typeof value=="string"&&value.trim().length>0)return value;if(Array.isArray(value)&&value.length>0&&value.every(audience=>typeof audience=="string"&&audience.trim().length>0))return[...value];throw new TypeError("JWT verifier audience must be a non-empty string or string array")}}function validAudience(value){return typeof value=="string"||Array.isArray(value)&&value.length>0&&value.every(item=>typeof item=="string")}function configuredResourceUrl(value){let url;try{url=new URL(value)}catch{throw new TypeError(RESOURCE_URL_REQUIREMENT)}if(!isAllowedHttpUrl(url))throw new TypeError(RESOURCE_URL_REQUIREMENT);return url.pathname=url.pathname==="/"?"/":url.pathname.replace(/\/+$/,""),url}var RESOURCE_URL_REQUIREMENT="resource must use HTTPS, or HTTP for localhost, without credentials, query, or fragment";function canonicalUrl(value){try{let url=new URL(value);if(!isAllowedHttpUrl(url))throw new TypeError;return url.pathname=url.pathname==="/"?"/":url.pathname.replace(/\/+$/,""),url}catch{throw invalidToken("Token resource claim must be an absolute HTTPS URL, or HTTP URL for localhost")}}function isAllowedHttpUrl(url){return/^https?:$/.test(url.protocol)&&!url.username&&!url.password&&!url.search&&!url.hash&&(url.protocol!=="http:"||isLocalhost(url))}function isCredentialFailure(error){return error instanceof errors.JWTClaimValidationFailed||error instanceof errors.JWTExpired||error instanceof errors.JOSEAlgNotAllowed||error instanceof errors.JOSENotSupported||error instanceof errors.JWSInvalid||error instanceof errors.JWTInvalid||error instanceof errors.JWSSignatureVerificationFailed||error instanceof errors.JWKSNoMatchingKey}var JWT_DEBUG_CLAIMS=["iss","aud","azp","sub","exp","iat","nbf","client_id","scope","typ","jti"];function debugErrorText(error){return error instanceof Error?error.message:String(error)}function logJwtFailure(token,error){try{let decodeSegment2=function(segment,label){try{return Buffer.from(segment,"base64url").toString("utf8")}catch(decodeError){console.error(`[oauth-debug] ${label} decode failed: ${debugErrorText(decodeError)}`);return}};var decodeSegment=decodeSegment2;let name=error instanceof Error?error.constructor.name:typeof error;console.error(`[oauth-debug] JWT verify failed: ${name}: ${debugErrorText(error)}`),error instanceof errors.JWTClaimValidationFailed&&console.error(`[oauth-debug] claim=${error.claim} reason=${error.reason}`);let segments=token.split(".");if(console.error(`[oauth-debug] token segments: ${segments.length}`),segments.length!==3){let preview=token.length>12?`${token.slice(0,12)}\u2026`:token;console.error(`[oauth-debug] non-JWT token preview=${preview} length=${token.length}`);return}let headerJson=decodeSegment2(segments[0],"header");headerJson!==void 0&&console.error(`[oauth-debug] header=${headerJson}`);let payloadJson=decodeSegment2(segments[1],"payload");if(payloadJson===void 0)return;try{let payload=JSON.parse(payloadJson),selected={};for(let claim of JWT_DEBUG_CLAIMS)claim in payload&&(selected[claim]=payload[claim]);selected.now=Math.floor(Date.now()/1e3),console.error(`[oauth-debug] payload=${JSON.stringify(selected)}`)}catch(decodeError){console.error(`[oauth-debug] payload decode failed: ${debugErrorText(decodeError)}`)}}catch{}}function resolveConfiguredOAuthResource(options){let provider=options.provider,basePath=normalizeBasePath(options.basePath);if(provider.resource!==void 0)return validateOAuthResource(provider.resource,basePath);if(options.mcpUrl!==void 0)return validateOAuthResource(appendBasePath(requireAbsoluteOrigin(options.mcpUrl,"MCP_URL"),basePath),basePath)}function resolveLocalOAuthResource(listenOrigin,basePath){let listenOriginUrl=requireAbsoluteOrigin(listenOrigin,"listen origin");if(!isLocalhost(listenOriginUrl))throw new Error("OAuth listen origin must be localhost or a loopback address");return validateOAuthResource(appendBasePath(listenOriginUrl,normalizeBasePath(basePath)),basePath)}function validateOAuthResource(resource,basePath){let normalizedBasePath=normalizeBasePath(basePath),url=parseAbsoluteUrl(resource,"OAuth resource");if(url.search!==""||url.hash!=="")throw new Error("OAuth resource must not include a query string or fragment");if(assertSecureHttpUrl(url,"OAuth resource"),normalizePathname(url.pathname)!==normalizedBasePath)throw new Error(`OAuth resource path must exactly match basePath (${normalizedBasePath})`);return url.pathname=normalizedBasePath,url}function wrapOAuthTokenVerifier(provider,expectedResource){let canonicalResource=normalizeResourceUrl(expectedResource),tokenVerifier=provider.createTokenVerifier(new URL(canonicalResource.href));if(tokenVerifier===null||typeof tokenVerifier!="object"||typeof tokenVerifier.verifyAccessToken!="function")throw new TypeError("OAuth provider createTokenVerifier must return an OAuthTokenVerifier");return{async verifyAccessToken(token){let authInfo=await tokenVerifier.verifyAccessToken(token);assertVerifiedAuthInfo(authInfo),assertResourceBinding(authInfo,canonicalResource);let mapped;try{mapped=provider.mapAuthInfo(authInfo)}catch(error){throw invalidToken("Token identity mapping failed",error)}return assertMappedExtra(mapped),{...authInfo,scopes:[...authInfo.scopes],extra:{...authInfo.extra,...mapped}}}}}function assertResourceBinding(authInfo,expectedResource){if(authInfo.resource===void 0)throw invalidToken("Token verifier did not return a validated protected resource");if(parseTokenResource(authInfo.resource).href!==normalizeResourceUrl(expectedResource).href)throw invalidToken("Token resource does not match the protected resource")}function parseTokenResource(value){if(!(value instanceof URL))throw invalidToken("Token resource must be an absolute HTTPS URL, or HTTP URL for localhost");let resource=value;if(!/^https?:$/.test(resource.protocol)||resource.username!==""||resource.password!==""||resource.search!==""||resource.hash!==""||resource.protocol==="http:"&&!isLocalhost(resource))throw invalidToken("Token resource must be an absolute HTTPS URL, or HTTP URL for localhost");return normalizeResourceUrl(resource)}function normalizeResourceUrl(resource){let normalized=new URL(resource);return normalized.pathname=normalized.pathname==="/"?"/":normalized.pathname.replace(/\/+$/,""),normalized}function getOAuthProviderOptions(provider){return{oauthMetadata:provider.oauthMetadata,...provider.requiredScopes!==void 0&&{requiredScopes:[...provider.requiredScopes]},...provider.scopesSupported!==void 0&&{scopesSupported:[...provider.scopesSupported]},...provider.resourceName!==void 0&&{resourceName:provider.resourceName},...provider.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:provider.serviceDocumentationUrl}}}function assertVerifiedAuthInfo(authInfo){if(authInfo===null||typeof authInfo!="object"||typeof authInfo.token!="string"||authInfo.token.length===0||typeof authInfo.clientId!="string"||!Array.isArray(authInfo.scopes)||!authInfo.scopes.every(scope=>typeof scope=="string")||typeof authInfo.expiresAt!="number"||!Number.isFinite(authInfo.expiresAt)||authInfo.expiresAt<=Date.now()/1e3)throw invalidToken("Token verifier returned invalid authentication information")}function assertMappedExtra(mapped){if(mapped===null||typeof mapped!="object"||!("user"in mapped)||mapped.user===void 0||!isRecord(mapped.payload)||!Array.isArray(mapped.permissions)||!mapped.permissions.every(permission=>typeof permission=="string"))throw invalidToken("Token identity mapping must return user, payload, and string permissions")}function requireAbsoluteOrigin(value,name){let url=parseAbsoluteUrl(value,name);if(url.pathname!=="/"||url.search!==""||url.hash!==""||url.username!==""||url.password!=="")throw new Error(`${name} must be an absolute origin without a path`);return url}function appendBasePath(origin,basePath){let resource=new URL(origin.origin);return resource.pathname=basePath,resource}function normalizeBasePath(basePath){if(!basePath.startsWith("/")||basePath.includes("?")||basePath.includes("#"))throw new Error("basePath must be an absolute URL pathname");return normalizePathname(basePath)}function normalizePathname(pathname){if(pathname==="/")return"/";let end=pathname.length;for(;end>0&&pathname.charCodeAt(end-1)===47;)end--;return pathname.slice(0,end)}function oauthCustomProvider(options){if(options===null||typeof options!="object"||typeof options.createTokenVerifier!="function"||typeof options.mapAuthInfo!="function")throw new TypeError("oauthCustomProvider requires createTokenVerifier, oauthMetadata, and mapAuthInfo");if(options.setup!==void 0&&typeof options.setup!="function")throw new TypeError("setup must be a function when provided");if(assertOAuthMetadata(options.oauthMetadata),options.resource!==void 0&&assertResourceUrl(options.resource),assertStringArray(options.requiredScopes,"requiredScopes"),assertStringArray(options.scopesSupported,"scopesSupported"),options.resourceName!==void 0&&(typeof options.resourceName!="string"||options.resourceName.trim().length===0))throw new TypeError("resourceName must be a non-empty string");if(options.serviceDocumentationUrl!==void 0){if(!(options.serviceDocumentationUrl instanceof URL))throw new TypeError("serviceDocumentationUrl must be a URL");assertSecureHttpUrl(options.serviceDocumentationUrl,"serviceDocumentationUrl")}return{createTokenVerifier:options.createTokenVerifier,oauthMetadata:options.oauthMetadata,mapAuthInfo:options.mapAuthInfo,...options.setup!==void 0&&{setup:options.setup},...options.resource!==void 0&&{resource:options.resource},...options.requiredScopes!==void 0&&{requiredScopes:[...options.requiredScopes]},...options.scopesSupported!==void 0&&{scopesSupported:[...options.scopesSupported]},...options.resourceName!==void 0&&{resourceName:options.resourceName},...options.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:options.serviceDocumentationUrl}}}function assertOAuthMetadata(metadata){if(metadata===null||typeof metadata!="object"||!("issuer"in metadata)||typeof metadata.issuer!="string")throw new TypeError("oauthMetadata must include a string issuer");assertSecureHttpUrl(parseAbsoluteUrl(metadata.issuer,"oauthMetadata.issuer"),"oauthMetadata.issuer")}function assertResourceUrl(resource){assertSecureHttpUrl(parseAbsoluteUrl(resource,"resource"),"resource")}function assertStringArray(value,name){if(value!==void 0&&(!Array.isArray(value)||!value.every(item=>typeof item=="string")))throw new TypeError(`${name} must be an array of strings`)}export{isRecord,invalidToken,resolveConfiguredOAuthResource,resolveLocalOAuthResource,wrapOAuthTokenVerifier,getOAuthProviderOptions,createJwtVerifier,normalizedProviderUrl,providerEndpoint,payloadFromAuthInfo,requiredString,stringValue,booleanValue,recordValue,normalizedStrings,oauthCustomProvider};
1
+ function isRecord(value){return value!==null&&typeof value=="object"&&!Array.isArray(value)}function isLocalhost(url){let hostname=url.hostname.toLowerCase();return hostname==="localhost"||hostname.endsWith(".localhost")||hostname==="[::1]"||/^127(?:\.\d{1,3}){3}$/.test(hostname)}function parseAbsoluteUrl(value,name){let url;try{url=new URL(value)}catch{throw new Error(`${name} must be an absolute URL`)}if(url.origin==="null"||url.username!==""||url.password!=="")throw new Error(`${name} must be an absolute URL without credentials`);return url}function assertSecureHttpUrl(url,name){if(url.protocol!=="https:"&&!(url.protocol==="http:"&&isLocalhost(url)))throw new Error(`${name} must use HTTPS, or HTTP for localhost`)}import{OAuthError,OAuthErrorCode}from"@modelcontextprotocol/server";function invalidToken(message,cause){let error=new OAuthError(OAuthErrorCode.InvalidToken,message);return cause!==void 0&&(error.cause=cause),error}import{OAuthError as OAuthError2}from"@modelcontextprotocol/server";import{createRemoteJWKSet,jwtVerify,errors}from"jose";function createJwtVerifier(options){let key=options.key??createRemoteJWKSet(options.jwksUrl),configuredResource=configuredResourceUrl(options.resource),configuredAudience=verifierAudience(options.audience);if(configuredAudience!==void 0&&options.issuerBoundAccessTokens===!0)throw new TypeError("JWT verifier cannot combine audience and issuer-bound access tokens");return{async verifyAccessToken(token){try{let{payload}=await jwtVerify(token,key,{issuer:options.issuer,...configuredAudience!==void 0&&{audience:configuredAudience},...options.algorithms!==void 0&&{algorithms:[...options.algorithms]},requiredClaims:["exp","sub"]}),claims={...payload},clientId=requiredString(claims,"client_id")??requiredString(claims,"azp"),expiresAt=requiredFutureNumber(claims,"exp"),resource=verifiedResource(claims,configuredResource,configuredAudience!==void 0||options.issuerBoundAccessTokens===!0);return{token,clientId:clientId??"",scopes:normalizedStrings(claims.scope),expiresAt,extra:{payload:claims},resource}}catch(error){throw error instanceof OAuthError2?error:isCredentialFailure(error)?(process.env.MCP_USE_OAUTH_DEBUG&&logJwtFailure(token,error),invalidToken("JWT verification failed",error)):error}}}}function normalizedProviderUrl(value,name){let raw=typeof value=="string"&&!value.includes("://")?`https://${value}`:value,url;try{url=new URL(raw)}catch{throw new TypeError(`${name} must be an absolute HTTP(S) URL`)}if(!isAllowedHttpUrl(url))throw new TypeError(`${name} must use HTTPS, or HTTP for localhost, without credentials, query, or fragment`);return url.pathname=url.pathname.replace(/\/+$/,"")||"/",url}function providerEndpoint(issuer,path){let base=new URL(issuer);return base.pathname=`${base.pathname.replace(/\/+$/,"")}/`,new URL(path.replace(/^\/+/,""),base).href}function payloadFromAuthInfo(authInfo){let payload=authInfo.extra?.payload;if(!isRecord(payload))throw invalidToken("Verified token payload is missing");return payload}function requiredString(claims,name){let value=claims[name];return typeof value=="string"&&value.trim().length>0?value:void 0}function stringValue(claims,name){let value=claims[name];return typeof value=="string"?value:void 0}function booleanValue(claims,name){let value=claims[name];return typeof value=="boolean"?value:void 0}function numberValue(claims,name){let value=claims[name];return typeof value=="number"&&Number.isFinite(value)?value:void 0}function recordValue(claims,name){let value=claims[name];return isRecord(value)?value:void 0}function normalizedStrings(value){return typeof value=="string"?value.split(/\s+/).filter(Boolean):Array.isArray(value)?value.filter(item=>typeof item=="string"&&item.length>0):[]}function requiredFutureNumber(claims,name){let value=numberValue(claims,name);if(value===void 0||value<=Date.now()/1e3)throw invalidToken(`Missing or expired ${name} claim`);return value}function verifiedResource(claims,configuredResource,providerBindingWasValidated){let value=claims.resource;if(value!==void 0){if(typeof value!="string")throw invalidToken("Token resource claim must be an absolute URL");if(canonicalUrl(value).href!==configuredResource.href)throw invalidToken("Token resource claim does not match protected resource");return configuredResource}if(providerBindingWasValidated)return configuredResource;let audience=claims.aud;if(!validAudience(audience))throw invalidToken("Token audience claim must be a string or string array");if(!(typeof audience=="string"?[audience]:audience).includes(configuredResource.href))throw invalidToken("Token audience does not include the protected resource");return configuredResource}function verifierAudience(value){if(value!==void 0){if(typeof value=="string"&&value.trim().length>0)return value;if(Array.isArray(value)&&value.length>0&&value.every(audience=>typeof audience=="string"&&audience.trim().length>0))return[...value];throw new TypeError("JWT verifier audience must be a non-empty string or string array")}}function validAudience(value){return typeof value=="string"||Array.isArray(value)&&value.length>0&&value.every(item=>typeof item=="string")}function configuredResourceUrl(value){let url;try{url=new URL(value)}catch{throw new TypeError(RESOURCE_URL_REQUIREMENT)}if(!isAllowedHttpUrl(url))throw new TypeError(RESOURCE_URL_REQUIREMENT);return url.pathname=url.pathname==="/"?"/":url.pathname.replace(/\/+$/,""),url}var RESOURCE_URL_REQUIREMENT="resource must use HTTPS, or HTTP for localhost, without credentials, query, or fragment";function canonicalUrl(value){try{let url=new URL(value);if(!isAllowedHttpUrl(url))throw new TypeError;return url.pathname=url.pathname==="/"?"/":url.pathname.replace(/\/+$/,""),url}catch{throw invalidToken("Token resource claim must be an absolute HTTPS URL, or HTTP URL for localhost")}}function isAllowedHttpUrl(url){return/^https?:$/.test(url.protocol)&&!url.username&&!url.password&&!url.search&&!url.hash&&(url.protocol!=="http:"||isLocalhost(url))}function isCredentialFailure(error){return error instanceof errors.JWTClaimValidationFailed||error instanceof errors.JWTExpired||error instanceof errors.JOSEAlgNotAllowed||error instanceof errors.JOSENotSupported||error instanceof errors.JWSInvalid||error instanceof errors.JWTInvalid||error instanceof errors.JWSSignatureVerificationFailed||error instanceof errors.JWKSNoMatchingKey}var JWT_DEBUG_CLAIMS=["iss","aud","azp","sub","exp","iat","nbf","client_id","scope","typ","jti"];function debugErrorText(error){return error instanceof Error?error.message:String(error)}function logJwtFailure(token,error){try{let decodeSegment2=function(segment,label){try{return Buffer.from(segment,"base64url").toString("utf8")}catch(decodeError){console.error(`[oauth-debug] ${label} decode failed: ${debugErrorText(decodeError)}`);return}};var decodeSegment=decodeSegment2;let name=error instanceof Error?error.constructor.name:typeof error;console.error(`[oauth-debug] JWT verify failed: ${name}: ${debugErrorText(error)}`),error instanceof errors.JWTClaimValidationFailed&&console.error(`[oauth-debug] claim=${error.claim} reason=${error.reason}`);let segments=token.split(".");if(console.error(`[oauth-debug] token segments: ${segments.length}`),segments.length!==3){let preview=token.length>12?`${token.slice(0,12)}\u2026`:token;console.error(`[oauth-debug] non-JWT token preview=${preview} length=${token.length}`);return}let headerJson=decodeSegment2(segments[0],"header");headerJson!==void 0&&console.error(`[oauth-debug] header=${headerJson}`);let payloadJson=decodeSegment2(segments[1],"payload");if(payloadJson===void 0)return;try{let payload=JSON.parse(payloadJson),selected={};for(let claim of JWT_DEBUG_CLAIMS)claim in payload&&(selected[claim]=payload[claim]);selected.now=Math.floor(Date.now()/1e3),console.error(`[oauth-debug] payload=${JSON.stringify(selected)}`)}catch(decodeError){console.error(`[oauth-debug] payload decode failed: ${debugErrorText(decodeError)}`)}}catch{}}function wrapOAuthTokenVerifier(provider,expectedResource){let canonicalResource=normalizeResourceUrl(expectedResource),tokenVerifier=provider.createTokenVerifier(new URL(canonicalResource.href));if(tokenVerifier===null||typeof tokenVerifier!="object"||typeof tokenVerifier.verifyAccessToken!="function")throw new TypeError("OAuth provider createTokenVerifier must return an OAuthTokenVerifier");return{async verifyAccessToken(token){let authInfo=await tokenVerifier.verifyAccessToken(token);assertVerifiedAuthInfo(authInfo),assertResourceBinding(authInfo,canonicalResource);let mapped;try{mapped=provider.mapAuthInfo(authInfo)}catch(error){throw invalidToken("Token identity mapping failed",error)}return assertMappedExtra(mapped),{...authInfo,scopes:[...authInfo.scopes],extra:{...authInfo.extra,...mapped}}}}}function assertResourceBinding(authInfo,expectedResource){if(authInfo.resource===void 0)throw invalidToken("Token verifier did not return a validated protected resource");if(parseTokenResource(authInfo.resource).href!==normalizeResourceUrl(expectedResource).href)throw invalidToken("Token resource does not match the protected resource")}function parseTokenResource(value){if(!(value instanceof URL))throw invalidToken("Token resource must be an absolute HTTPS URL, or HTTP URL for localhost");let resource=value;if(!/^https?:$/.test(resource.protocol)||resource.username!==""||resource.password!==""||resource.search!==""||resource.hash!==""||resource.protocol==="http:"&&!isLocalhost(resource))throw invalidToken("Token resource must be an absolute HTTPS URL, or HTTP URL for localhost");return normalizeResourceUrl(resource)}function normalizeResourceUrl(resource){let normalized=new URL(resource);return normalized.pathname=normalized.pathname==="/"?"/":normalized.pathname.replace(/\/+$/,""),normalized}function getOAuthProviderOptions(provider){return{oauthMetadata:provider.oauthMetadata,...provider.requiredScopes!==void 0&&{requiredScopes:[...provider.requiredScopes]},...provider.scopesSupported!==void 0&&{scopesSupported:[...provider.scopesSupported]},...provider.resourceName!==void 0&&{resourceName:provider.resourceName},...provider.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:provider.serviceDocumentationUrl}}}function assertVerifiedAuthInfo(authInfo){if(authInfo===null||typeof authInfo!="object"||typeof authInfo.token!="string"||authInfo.token.length===0||typeof authInfo.clientId!="string"||!Array.isArray(authInfo.scopes)||!authInfo.scopes.every(scope=>typeof scope=="string")||typeof authInfo.expiresAt!="number"||!Number.isFinite(authInfo.expiresAt)||authInfo.expiresAt<=Date.now()/1e3)throw invalidToken("Token verifier returned invalid authentication information")}function assertMappedExtra(mapped){if(mapped===null||typeof mapped!="object"||!("user"in mapped)||mapped.user===void 0||!isRecord(mapped.payload)||!Array.isArray(mapped.permissions)||!mapped.permissions.every(permission=>typeof permission=="string"))throw invalidToken("Token identity mapping must return user, payload, and string permissions")}function oauthCustomProvider(options){if(options===null||typeof options!="object"||typeof options.createTokenVerifier!="function"||typeof options.mapAuthInfo!="function")throw new TypeError("oauthCustomProvider requires createTokenVerifier, oauthMetadata, and mapAuthInfo");if(options.setup!==void 0&&typeof options.setup!="function")throw new TypeError("setup must be a function when provided");if(assertOAuthMetadata(options.oauthMetadata),options.resource!==void 0&&assertResourceUrl(options.resource),assertStringArray(options.requiredScopes,"requiredScopes"),assertStringArray(options.scopesSupported,"scopesSupported"),options.resourceName!==void 0&&(typeof options.resourceName!="string"||options.resourceName.trim().length===0))throw new TypeError("resourceName must be a non-empty string");if(options.serviceDocumentationUrl!==void 0){if(!(options.serviceDocumentationUrl instanceof URL))throw new TypeError("serviceDocumentationUrl must be a URL");assertSecureHttpUrl(options.serviceDocumentationUrl,"serviceDocumentationUrl")}return{createTokenVerifier:options.createTokenVerifier,oauthMetadata:options.oauthMetadata,mapAuthInfo:options.mapAuthInfo,...options.setup!==void 0&&{setup:options.setup},...options.resource!==void 0&&{resource:options.resource},...options.requiredScopes!==void 0&&{requiredScopes:[...options.requiredScopes]},...options.scopesSupported!==void 0&&{scopesSupported:[...options.scopesSupported]},...options.resourceName!==void 0&&{resourceName:options.resourceName},...options.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:options.serviceDocumentationUrl}}}function assertOAuthMetadata(metadata){if(metadata===null||typeof metadata!="object"||!("issuer"in metadata)||typeof metadata.issuer!="string")throw new TypeError("oauthMetadata must include a string issuer");assertSecureHttpUrl(parseAbsoluteUrl(metadata.issuer,"oauthMetadata.issuer"),"oauthMetadata.issuer")}function assertResourceUrl(resource){assertSecureHttpUrl(parseAbsoluteUrl(resource,"resource"),"resource")}function assertStringArray(value,name){if(value!==void 0&&(!Array.isArray(value)||!value.every(item=>typeof item=="string")))throw new TypeError(`${name} must be an array of strings`)}export{isRecord,invalidToken,wrapOAuthTokenVerifier,getOAuthProviderOptions,createJwtVerifier,normalizedProviderUrl,providerEndpoint,payloadFromAuthInfo,requiredString,stringValue,booleanValue,recordValue,normalizedStrings,oauthCustomProvider};
@@ -0,0 +1 @@
1
+ import{a as o}from"./chunk-EI7MMDWY.js";import{hostHeaderValidationResponse as m,originValidationResponse as g}from"@modelcontextprotocol/server";var p=new WeakMap;function S(t){let e=p.get(t);return e===void 0&&(e={},p.set(t,e)),e}o(S,"getRequestBag");function b(t,...e){return async n=>{let r=0,i=o(async()=>{if(r<e.length){let s=e[r];return r+=1,s(n,i)}return t(n)},"dispatch");return i()}}o(b,"composeFetch");function l(t){return new URL(t.url).pathname}o(l,"pathnameOf");function O(t,e){return l(t)===e}o(O,"matchesPath");function q(t,e){let n=l(t);return n===e||n.startsWith(`${e}/`)}o(q,"matchesPathPrefix");function k(t,e){let n=e.replace(/^\/+/,"");return t==="/"?`/${n}`:`${t}/${n}`}o(k,"pathUnderBase");function E(t){if(t.method!=="GET"&&t.method!=="HEAD")return!1;let e=t.headers.get("accept");return e===null?!1:e.split(",").some(n=>{let[r,...i]=n.split(";");return r?.trim().toLowerCase()!=="text/html"?!1:!i.some(s=>{let[a,u]=s.trim().toLowerCase().split("=");return a==="q"&&Number(u)===0})})}o(E,"isHtmlNavigationRequest");function T(){return async(t,e)=>{let n=S(t);if(n.parsedBody!==void 0||!(t.headers.get("content-type")??"").includes("application/json"))return e();try{n.parsedBody=await t.clone().json()}catch{return new Response("Invalid JSON",{status:400})}return e()}}o(T,"jsonBodyMiddleware");function M(t){return async(e,n)=>m(e,t)??n()}o(M,"hostValidationMiddleware");function $(t,e=!0){return async(n,r)=>e&&(n.method==="GET"||n.method==="HEAD")?r():g(n,t)??r()}o($,"originValidationMiddleware");var w="securitySchemes",f='each security scheme must be { type: "noauth" } or { type: "oauth2", scopes: string[] }',x=/^[\x21\x23-\x5B\x5D-\x7E]+$/;function R(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}o(R,"isRecord");function v(t,e){return[...new Set([...t,...e])]}o(v,"unionScopes");function C(t,e,n){let r=o(u=>{throw new TypeError(`Tool "${t}": ${u}`)},"fail");if(e===void 0)return[{type:"oauth2",scopes:[...n.baselineScopes]}];(!Array.isArray(e)||e.length===0)&&r("securitySchemes must be a non-empty array; omit it to require sign-in with the provider's requiredScopes");let i=!1,s;for(let u of e){R(u)||r(f);let{type:h}=u,y=h==="oauth2"?["type","scopes"]:["type"];for(let c of Object.keys(u))y.includes(c)||r(`unknown security scheme field ${JSON.stringify(c)}; ${f}`);if(h==="noauth")i&&r("declares more than one noauth scheme"),i=!0;else if(h==="oauth2"){s!==void 0&&r("declares more than one oauth2 scheme; a sign-in challenge can only ask for one scope set");let{scopes:c}=u;Array.isArray(c)||r("oauth2 scopes must be an array of scope strings");for(let d of c)(typeof d!="string"||!x.test(d))&&r(`invalid oauth2 scope ${JSON.stringify(d)}; each scope must be one non-empty token without whitespace, ", or \\`);s=c}else r(`unsupported security scheme type ${JSON.stringify(h)}; use "noauth" or "oauth2"`)}i&&!n.mixedAuth&&r(n.hasOAuth?"noauth requires mixedAuth: true on the server. Without it, every request needs a token, so signed-out callers could never use it":"noauth requires an OAuth provider with mixedAuth: true. A server without OAuth serves every tool signed out, so remove securitySchemes"),s!==void 0&&!n.hasOAuth&&r("oauth2 requires an OAuth provider to verify tokens"),s!==void 0&&s.length===0&&n.baselineScopes.length===0&&r("oauth2 scopes are empty and the OAuth provider has no requiredScopes. ChatGPT ignores an oauth2 scheme without scopes and would never offer sign-in; list at least one scope");let a=[];return i&&a.push({type:"noauth"}),s!==void 0&&a.push({type:"oauth2",scopes:v(n.baselineScopes,s)}),a}o(C,"resolveSecuritySchemes");function H(t){return!t.some(e=>e.type==="noauth")}o(H,"requiresSignIn");function P(t){for(let e of t)if(e.type==="oauth2")return e.scopes;return[]}o(P,"schemeScopes");function _(t,e,n){let r=e._meta?.[w];if(r!==void 0){if(e.securitySchemes!==void 0)return JSON.stringify(r)===JSON.stringify(e.securitySchemes)?void 0:`[mcp-use] Tool "${t}": _meta.securitySchemes is replaced by the top-level securitySchemes. Remove the _meta entry.`;if(n.mixedAuth)return`[mcp-use] Tool "${t}": _meta.securitySchemes is advertised but not enforced, so the tool requires sign-in. Move it to the top-level securitySchemes field.`}}o(_,"handWrittenSecuritySchemesWarning");export{S as a,b,l as c,O as d,q as e,k as f,E as g,T as h,M as i,$ as j,w as k,C as l,H as m,P as n,_ as o};
@@ -0,0 +1 @@
1
+ import{a as E,m as M,n as O}from"./chunk-YI27EOFM.js";import{a as r}from"./chunk-EI7MMDWY.js";import{PROTOCOL_VERSION_META_KEY as z,OAuthError as B,OAuthErrorCode as y,bearerAuthChallengeResponse as F,verifyBearerToken as D}from"@modelcontextprotocol/server";import{OAuthError as L,OAuthErrorCode as w,bearerAuthChallengeResponse as j}from"@modelcontextprotocol/server";var G="mcp/www_authenticate",H=/chatgpt|openai/i;function N(e,t){return e==="missing_token"?"Authentication is required for this request.":e==="invalid_token"?"The access token is invalid or expired.":t.length>0?`Additional permissions are required: ${t.join(" ")}.`:"Additional permissions are required."}r(N,"defaultDescription");function q(e){return{reason:e.reason,description:e.description??N(e.reason,e.missingScopes??[]),scopes:[...e.scopes],resourceMetadataUrl:e.resourceMetadataUrl}}r(q,"createAuthChallenge");function R(e){return j(new L(e.reason==="insufficient_scope"?w.InsufficientScope:w.InvalidToken,e.description),{requiredScopes:[...e.scopes],resourceMetadataUrl:e.resourceMetadataUrl})}r(R,"authChallengeHttpResponse");function k(e){let t=R(e).headers.get("WWW-Authenticate");return{content:[{type:"text",text:e.description}],isError:!0,_meta:{[G]:t===null?[]:[t]}}}r(k,"authChallengeToolResult");function U(e){return H.test(e.headers.get("user-agent")??"")}r(U,"prefersToolResultChallenge");var K=new Set(["initialize","server/discover","ping","tools/list","resources/list","resources/templates/list","prompts/list","logging/setLevel"]);function g(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}r(g,"isRecord");function S(e){if(!g(e)||typeof e.method!="string")return;let t=e.id,o=e.params;return{method:e.method,id:typeof t=="string"||typeof t=="number"?t:void 0,params:g(o)?o:void 0}}r(S,"parseMessage");function V(e){let t=e.params?._meta;return g(t)&&t[z]!==void 0}r(V,"isModernEnvelope");function x(e){try{return new URL(e).toString()}catch{return e}}r(x,"normalizeResourceUri");function I(e,t){let o=e?.[t];return typeof o=="string"?o:void 0}r(I,"stringParam");function Y(e){if(K.has(e.method)||e.id===void 0&&e.method.startsWith("notifications/"))return!1;if(e.method==="subscriptions/listen"){let t=e.params?.notifications,o=g(t)?t.resourceSubscriptions:void 0;return o!==void 0&&(!Array.isArray(o)||o.length>0)}return!0}r(Y,"isSignInMethod");function te(e){let{verifier:t,resourceMetadataUrl:o,baselineScopes:C,mixedAuth:m,toolSchemes:v}=e,b=new Set([...e.openResourceUris].map(x)),p={required:!1,scopes:[]},l=r((n=[])=>({required:!0,scopes:[...new Set([...C,...n])]}),"signIn"),T=r(n=>{if(n===void 0)return m?p:l();if(n.method==="tools/call"){let i=I(n.params,"name"),a=i===void 0?void 0:v(i);return a===void 0?l():m&&!M(a)?p:l(O(a))}if(!m)return l();if(n.method==="resources/read"){let i=I(n.params,"uri");if(i!==void 0&&b.has(x(i)))return p}return Y(n)?l():p},"requirementFor"),W=r(n=>{if(!Array.isArray(n))return T(S(n));let i=new Set,a=!1;for(let u of n){let c=T(S(u));if(c.required){a=!0;for(let s of c.scopes)i.add(s)}}return{required:a,scopes:[...i]}},"requirementForBody"),h=r((n,i,a,u,c={})=>{let s=q({reason:a,scopes:u.required?u.scopes:C,resourceMetadataUrl:o,...c});return i===void 0||i.method!=="tools/call"||i.id===void 0||!U(n)?R(s):Response.json({jsonrpc:"2.0",id:i.id,result:{...V(i)&&{resultType:"complete"},...k(s)}})},"refuse");return async(n,i)=>{let a=E(n),u=a.parsedBody;if(u===void 0&&n.method.toUpperCase()==="POST")try{u=await n.clone().json()}catch{}let c=Array.isArray(u)?void 0:S(u),s=W(u),f,A=n.headers.get("authorization");if(A!==null||s.required)try{f=await D(A,{verifier:t})}catch(d){return!(d instanceof B)||d.code!==y.InvalidToken&&d.code!==y.InsufficientScope?F(d,{resourceMetadataUrl:o}):d.code===y.InsufficientScope?h(n,c,"insufficient_scope",s,{description:d.message}):A===null?h(n,c,"missing_token",s):h(n,c,"invalid_token",s,{description:d.message})}if(s.required&&f!==void 0){let d=new Set(f.scopes),_=s.scopes.filter(P=>!d.has(P));if(_.length>0)return h(n,c,"insufficient_scope",s,{missingScopes:_})}return f!==void 0&&(a.authInfo=f),i()}}r(te,"createOAuthGate");export{te as createOAuthGate};