mcp-use 2.1.2-canary.9 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +1 -1
- package/dist/chunk-3FHYLNH3.js +1 -0
- package/dist/chunk-DOOKCABV.js +1 -0
- package/dist/{chunk-CN3XGFLA.js → chunk-R5E3UOG6.js} +1 -1
- package/dist/{chunk-MIZQEWZS.js → chunk-ZSPSHXAE.js} +1 -1
- package/dist/index-node.js +5 -5
- package/dist/index.js +1 -1
- package/dist/internal/usage.js +1 -1
- package/dist/oauth/auth0.js +1 -1
- package/dist/oauth/better-auth.js +1 -1
- package/dist/oauth/clerk.js +1 -1
- package/dist/oauth/index.d.ts +1 -0
- package/dist/oauth/index.js +1 -1
- package/dist/oauth/jwt.d.ts +18 -3
- package/dist/oauth/keycloak.js +1 -1
- package/dist/oauth/supabase.js +1 -1
- package/dist/oauth/workos.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-6P4FCE42.js +0 -1
- package/dist/chunk-IS7FKXFR.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{resolvePublicFilePath,servePublicFile}from"./chunk-ZMU5USAZ.js";import{hasExplicitAssetsBase,originFromAssetsBase,resolveAssetsBase,resolveServerOrigin}from"./chunk-6KY574WV.js";import{registerOpenAPITools}from"./chunk-Y26DNVWA.js";import{completable,normalizeCompletions}from"./chunk-OJF6B5EU.js";import{isUsageDisabled,recordUsage}from"./chunk-CN3XGFLA.js";import{inheritBufferedResponse,toNodeHandler,trackBufferedResponse}from"./chunk-V2VQP73V.js";import{authInfoFromRequest,composeFetch,getOAuthProtectedResourceMetadataUrl,getRequestBag,hostValidationMiddleware,isHtmlNavigationRequest,jsonBodyMiddleware,matchesPath,matchesPathPrefix,oauthMetadata,originValidationMiddleware,pathUnderBase,pathnameOf,requireBearerAuth}from"./chunk-MIZQEWZS.js";import{getOAuthProviderOptions,resolveConfiguredOAuthResource,resolveLocalOAuthResource,wrapOAuthTokenVerifier}from"./chunk-IS7FKXFR.js";import{localhostAllowedHostnames,localhostAllowedOrigins,McpServer as SdkMcpServer,ResourceTemplate,CLIENT_CAPABILITIES_META_KEY as CLIENT_CAPABILITIES_META_KEY3,CLIENT_INFO_META_KEY as CLIENT_INFO_META_KEY3,PROTOCOL_VERSION_META_KEY,isJSONRPCRequest as isJSONRPCRequest2,isInputRequiredResult as isInputRequiredResult3}from"@modelcontextprotocol/server";import{createServer as createNodeHttpServer}from"#mcp-use-node-http";import{Hono}from"hono";var FAVICON_CACHE_CONTROL="public, max-age=31536000, immutable",FAVICON_REDIRECT_CACHE_CONTROL="public, max-age=300";function protocolOf(value){return/^([a-z][a-z\d+.-]*):/i.exec(value)?.[1]?.toLowerCase()}function publicAssetPath(basePath,source){return`${basePath==="/"?"":basePath}/_mcp-use/public/${source.split("/").map(segment=>encodeURIComponent(segment)).join("/")}`}function isLocalPublicSource(source){return protocolOf(source)===void 0}function selectFaviconFromIcons(icons){return icons[0]}function assertLocalPublicSource(source,field){if(source.startsWith("/")||source.includes("\\")||source.includes("?")||source.includes("#")||source.split("/").some(segment=>segment===""||segment===".."))throw new TypeError(`${field} must be an http(s) URL, image data URL, or safe path relative to public/`)}function parseDataImage(source,field){let comma=source.indexOf(",");if(comma<0)throw new TypeError(`${field} must be a valid image data URL`);let metadata=source.slice(5,comma),payload=source.slice(comma+1),parts=metadata.split(";"),mimeType=parts[0]?.toLowerCase()??"";if(!mimeType.startsWith("image/"))throw new TypeError(`${field} data URL must use an image MIME type`);try{if(parts.includes("base64")){let binary2=atob(payload);return{mimeType,bytes:Uint8Array.from(binary2,character=>character.charCodeAt(0))}}return{mimeType,bytes:new TextEncoder().encode(decodeURIComponent(payload))}}catch{throw new TypeError(`${field} must be a valid image data URL`)}}function assertBrandingSource(source,field){if(typeof source!="string"||source.length===0)throw new TypeError(`${field} must be a non-empty string`);let protocol=protocolOf(source);if(protocol===void 0)return assertLocalPublicSource(source,field),source;if(protocol==="data")return parseDataImage(source,field),source;if(protocol!=="http"&&protocol!=="https")throw new TypeError(`${field} must be an http(s) URL, image data URL, or safe path relative to public/`);try{new URL(source)}catch{throw new TypeError(`${field} must be a valid absolute http(s) URL`)}return source}function normalizeServerBranding(config){let websiteUrl;if(config.websiteUrl!==void 0){if(typeof config.websiteUrl!="string"||config.websiteUrl.length===0)throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL");let parsed;try{parsed=new URL(config.websiteUrl)}catch{throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL")}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:")throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL");websiteUrl=config.websiteUrl}let icons;if(config.icons!==void 0){if(!Array.isArray(config.icons))throw new TypeError("icons must be an array of MCP Icon objects");icons=Object.freeze(config.icons.map((value,index)=>{if(typeof value!="object"||value===null)throw new TypeError(`icons[${index}] must be an MCP Icon object`);let icon=value,src=assertBrandingSource(icon.src,`icons[${index}].src`),mimeType=icon.mimeType;if(mimeType!==void 0&&(typeof mimeType!="string"||!mimeType.toLowerCase().startsWith("image/")))throw new TypeError(`icons[${index}].mimeType must be an image MIME type when provided`);let sizes=icon.sizes;if(sizes!==void 0&&(!Array.isArray(sizes)||sizes.some(size=>typeof size!="string"||size.length===0)))throw new TypeError(`icons[${index}].sizes must be an array of non-empty strings when provided`);let normalizedSizes=sizes===void 0?void 0:sizes.map(size=>size),theme=icon.theme;if(theme!==void 0&&theme!=="light"&&theme!=="dark")throw new TypeError(`icons[${index}].theme must be "light" or "dark" when provided`);return Object.freeze({src,...mimeType!==void 0&&{mimeType},...normalizedSizes!==void 0&&{sizes:Object.freeze(normalizedSizes)},...theme!==void 0&&{theme}})}))}let explicitFavicon=config.favicon===void 0?void 0:assertBrandingSource(config.favicon,"favicon"),inferred=explicitFavicon===void 0?selectFaviconFromIcons(icons??[]):void 0,favicon=explicitFavicon??inferred?.src,faviconMimeType=inferred?.mimeType??icons?.find(icon=>icon.src===explicitFavicon)?.mimeType;return Object.freeze({...favicon!==void 0&&{favicon},...faviconMimeType!==void 0&&{faviconMimeType},...icons!==void 0&&{icons},...websiteUrl!==void 0&&{websiteUrl}})}function resolveImplementationIcons(icons,request,basePath){if(icons!==void 0)return icons.map(icon=>({...icon,src:request!==void 0&&isLocalPublicSource(icon.src)?`${resolveAssetsBase(request)}${publicAssetPath(basePath,icon.src)}`:icon.src,...icon.sizes!==void 0&&{sizes:[...icon.sizes]}}))}function hasLocalBrandingAsset(branding){return branding.favicon!==void 0&&isLocalPublicSource(branding.favicon)||branding.icons?.some(icon=>isLocalPublicSource(icon.src))===!0}function createFaviconHandler(branding,options){let source=branding.favicon;if(source!==void 0)return async request=>{if(request.method!=="GET"&&request.method!=="HEAD")return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, HEAD"}});if(new URL(request.url).pathname!=="/favicon.ico")return new Response("Not Found",{status:404});let protocol=protocolOf(source);if(protocol==="http"||protocol==="https")return new Response(null,{status:307,headers:{Location:source,"Cache-Control":FAVICON_REDIRECT_CACHE_CONTROL}});if(protocol==="data"){let data=parseDataImage(source,"favicon");return new Response(request.method==="HEAD"?null:data.bytes.buffer,{status:200,headers:{"Content-Type":branding.faviconMimeType??data.mimeType,"Cache-Control":FAVICON_CACHE_CONTROL,"X-Content-Type-Options":"nosniff"}})}let{join}=await import("path"),publicRoot=options.dev?join(options.projectRoot,"public"):join(options.projectRoot,".mcp-use/build/views/public"),diskPath=await resolvePublicFilePath(publicRoot,source);if(diskPath===null)return new Response("Not Found",{status:404,headers:{"Cache-Control":"no-store"}});let response=await servePublicFile(diskPath,{...options.deferCors===!0&&{deferCors:!0},...request.method==="HEAD"&&{head:!0}});return response.headers.set("Cache-Control",FAVICON_CACHE_CONTROL),response.headers.set("X-Content-Type-Options","nosniff"),branding.faviconMimeType!==void 0&&response.headers.set("Content-Type",branding.faviconMimeType),response}}function assertServerConfig(config){if(config.basePath!==void 0){if(typeof config.basePath!="string")throw new TypeError("basePath must be an absolute URL pathname without empty segments, trailing slash, query, fragment, or whitespace");let{basePath}=config;if(!basePath.startsWith("/")||basePath.includes("?")||basePath.includes("#")||/\s/.test(basePath)||basePath.includes("//")||basePath.length>1&&basePath.endsWith("/"))throw new TypeError("basePath must be an absolute URL pathname without empty segments, trailing slash, query, fragment, or whitespace")}if(config.port!==void 0&&(typeof config.port!="number"||!Number.isInteger(config.port)||config.port<0||config.port>65535))throw new TypeError("port must be an integer between 0 and 65535");if(config.skills!==void 0&&typeof config.skills!="boolean"){if(typeof config.skills!="object"||config.skills===null||Array.isArray(config.skills))throw new TypeError("skills must be a boolean or configuration object");let directory=config.skills.directory;if(directory!==void 0&&typeof directory!="string")throw new TypeError("skills.directory must be a string when provided")}}var DEFAULT_LISTEN_HOST="127.0.0.1";function resolveListenHost(explicitHost,configuredHost,env=process.env){if(explicitHost!==void 0)return explicitHost;let envHost=env.HOST?.trim();return envHost!==void 0&&envHost!==""?envHost:configuredHost??DEFAULT_LISTEN_HOST}function resolveListenPort(explicitPort,configuredPort,env=process.env){if(explicitPort!==void 0)return explicitPort;let envPort=parsePort(env.PORT);return envPort!==void 0?envPort:configuredPort??3e3}function parsePort(value){if(value===void 0||value.trim()==="")return;let port=Number(value);return Number.isInteger(port)&&port>=0&&port<=65535?port:void 0}import{CLIENT_CAPABILITIES_META_KEY as CLIENT_CAPABILITIES_META_KEY2,CLIENT_INFO_META_KEY}from"@modelcontextprotocol/server";import{HonoRequest}from"hono/request";import{CLIENT_CAPABILITIES_META_KEY}from"@modelcontextprotocol/server";var UI_EXTENSION_ID="io.modelcontextprotocol/ui",UI_MIME_TYPE="text/html;profile=mcp-app",UI_RESOURCE_URI_PREFIX="ui://views/";var UI_RESOURCE_URI_META_KEY="ui/resourceUri";function viewResourceUri(viewName){return`${UI_RESOURCE_URI_PREFIX}${viewName}.html`}var clientCapabilitiesByRequest=new WeakMap;function stashClientCapabilities(request,capabilities){clientCapabilitiesByRequest.set(request,capabilities)}function extractClientCapabilitiesFromBody(body){if(typeof body!="object"||body===null)return;let params=body.params;if(typeof params!="object"||params===null)return;let meta=params._meta;if(typeof meta!="object"||meta===null)return;let capabilities=meta[CLIENT_CAPABILITIES_META_KEY];if(!(typeof capabilities!="object"||capabilities===null))return capabilities}function supportsViews(capabilities){let extensions=capabilities?.extensions;if(extensions===void 0)return!1;let uiExtension=extensions[UI_EXTENSION_ID];if(typeof uiExtension!="object"||uiExtension===null)return!1;let mimeTypes=uiExtension.mimeTypes;return Array.isArray(mimeTypes)?mimeTypes.includes(UI_MIME_TYPE):!1}function requireOAuthAuthInfo(authInfo){if(authInfo===void 0||authInfo.extra===void 0||authInfo.expiresAt===void 0)throw new Error("OAuth callback did not receive mapped AuthInfo.extra")}function stringValue(value){return typeof value=="string"?value:void 0}function coordinateValue(value){return typeof value=="string"||typeof value=="number"&&Number.isFinite(value)?value:void 0}function normalizeUserContext(meta){if(meta===void 0)return;let locale=stringValue(meta["openai/locale"])??stringValue(meta["webplus/i18n"]),userAgent=stringValue(meta["openai/userAgent"]),subject=stringValue(meta["openai/subject"]),conversationId=stringValue(meta["openai/session"]),organizationId=stringValue(meta["openai/organization"]),rawLocation=meta["openai/userLocation"],location;if(typeof rawLocation=="object"&&rawLocation!==null&&!Array.isArray(rawLocation)){let values=rawLocation,normalized={city:stringValue(values.city),region:stringValue(values.region),country:stringValue(values.country),timezone:stringValue(values.timezone),latitude:coordinateValue(values.latitude),longitude:coordinateValue(values.longitude)},entries=Object.entries(normalized).filter(entry=>entry[1]!==void 0);entries.length>0&&(location=Object.fromEntries(entries))}if(!(locale===void 0&&userAgent===void 0&&location===void 0&&subject===void 0&&conversationId===void 0&&organizationId===void 0))return{...locale!==void 0&&{locale},...userAgent!==void 0&&{userAgent},...location!==void 0&&{location},...subject!==void 0&&{subject},...conversationId!==void 0&&{conversationId},...organizationId!==void 0&&{organizationId}}}function toClientContext(ctx){let envelope=ctx.mcpReq.envelope,capabilities={...envelope?.[CLIENT_CAPABILITIES_META_KEY2]??{}},info={...envelope?.[CLIENT_INFO_META_KEY]??{}},user=normalizeUserContext(ctx.mcpReq._meta);return{can(capability){return Object.hasOwn(capabilities,capability)},capabilities(){return{...capabilities}},extension(id){let settings=capabilities.extensions?.[id];return settings===void 0?void 0:{...settings}},info(){return{...info}},user(){return user===void 0?void 0:{...user,...user.location!==void 0&&{location:{...user.location}}}},supportsViews(){return supportsViews(capabilities)}}}function toRequestContext(ctx){let rawRequest=ctx.http?.req,http=rawRequest===void 0?void 0:getRequestBag(rawRequest).honoContext,request=http?.req??(rawRequest===void 0?void 0:new HonoRequest(rawRequest)),additions={signal:ctx.mcpReq.signal,...request!==void 0&&{request},...ctx.mcpReq.inputResponses!==void 0&&{inputResponses:ctx.mcpReq.inputResponses},client:toClientContext(ctx),requestState:()=>ctx.mcpReq.requestState(),async sendNotification(method,params){await ctx.mcpReq.notify({method,...params!==void 0&&{params}})},async reportProgress(progress,total,message){let progressToken=ctx.mcpReq._meta?.progressToken;return progressToken===void 0?!1:(await ctx.mcpReq.notify({method:"notifications/progress",params:{progressToken,progress,...total!==void 0&&{total},...message!==void 0&&{message}}}),!0)},async sendLog(level,data,logger){await ctx.mcpReq.notify({method:"notifications/message",params:{level,data,...logger!==void 0&&{logger}}})}};return http!==void 0?Object.assign(http,additions):{...additions,...request!==void 0&&{req:request}}}function toAuthenticatedRequestContext(ctx){let authInfo=ctx.http?.authInfo;return requireOAuthAuthInfo(authInfo),Object.assign(toRequestContext(ctx),{auth:{user:authInfo.extra.user,payload:authInfo.extra.payload,accessToken:authInfo.token,scopes:[...authInfo.scopes],permissions:[...authInfo.extra.permissions],...authInfo.clientId.length>0&&{clientId:authInfo.clientId},expiresAt:authInfo.expiresAt,...authInfo.resource!==void 0&&{resource:authInfo.resource}}})}import{isInputRequiredResult}from"@modelcontextprotocol/server";function isReadResourceResult(result){return"contents"in result&&Array.isArray(result.contents)}function isGetPromptResult(result){return"messages"in result&&Array.isArray(result.messages)}function toResourceResult(result,uri){if(isReadResourceResult(result))return result;let mime=result._meta&&typeof result._meta=="object"&&typeof result._meta.mimeType=="string"?result._meta.mimeType:void 0,contents=[];for(let block of result.content??[]){let mapped=contentBlockToResourceContents(block,uri,mime);mapped!==void 0&&contents.push(mapped)}return contents.length===0&&result.structuredContent!==void 0&&contents.push({uri,mimeType:"application/json",text:JSON.stringify(result.structuredContent)}),contents.length===0&&contents.push({uri,mimeType:"text/plain",text:""}),{contents}}function contentBlockToResourceContents(block,uri,mimeHint){if(block.type==="text")return{uri,mimeType:mimeHint??"text/plain",text:block.text};if(block.type==="image"||block.type==="audio")return{uri,mimeType:block.mimeType,blob:block.data};if(block.type==="resource")return{...block.resource}}function toPromptResult(result){if(isInputRequiredResult(result)||isGetPromptResult(result))return result;let messages=(result.content??[]).map(content=>({role:"user",content}));return messages.length===0&&result.structuredContent!==void 0&&messages.push({role:"user",content:{type:"text",text:JSON.stringify(result.structuredContent)}}),messages.length===0&&messages.push({role:"user",content:{type:"text",text:""}}),{messages}}var DEFAULT_METHODS=["GET","HEAD","POST","OPTIONS"],DEFAULT_ALLOWED_HEADERS=["Content-Type","Authorization","mcp-protocol-version","mcp-method","mcp-name"];function resolveAllowedOrigin(origin,requestOrigin){return origin===void 0?requestOrigin:typeof origin=="function"?origin(requestOrigin):origin==="*"?"*":Array.isArray(origin)?requestOrigin!==null&&origin.includes(requestOrigin)?requestOrigin:null:origin}function corsHeaders(options,request){if(request.headers.has("Access-Control-Allow-Origin"))return;let requestOrigin=request.headers.get("Origin"),allowedOrigin=resolveAllowedOrigin(options.origin,requestOrigin);if(allowedOrigin===null)return;let headers={"Access-Control-Allow-Origin":allowedOrigin,"Access-Control-Allow-Methods":options.methods.join(", "),"Access-Control-Allow-Headers":options.allowedHeaders.join(", ")};return options.credentials&&(headers["Access-Control-Allow-Credentials"]="true"),allowedOrigin!=="*"&&(headers.Vary="Origin"),headers}function mergeCorsHeaders(response,headers){if(response.headers.has("Access-Control-Allow-Origin"))return response;let merged=new Headers(response.headers);return new Headers(headers).forEach((value,key)=>{merged.set(key,value)}),inheritBufferedResponse(response,new Response(response.body,{status:response.status,statusText:response.statusText,headers:merged}))}function corsFetchMiddleware(options){if(!(options.enabled!==!1))return async(_request,next)=>next();let resolved={...options.origin!==void 0&&{origin:options.origin},methods:options.methods??DEFAULT_METHODS,allowedHeaders:options.allowedHeaders??DEFAULT_ALLOWED_HEADERS,credentials:options.credentials??!1};return async(request,next)=>{let headers=corsHeaders(resolved,request);if(headers===void 0)return next();if(request.method==="OPTIONS")return new Response(null,{status:204,headers});let response=await next();return mergeCorsHeaders(response,headers)}}function isGlobalCorsEnabled(cors){return cors!==void 0&&cors.enabled!==!1}import{CallToolResultSchema,GetPromptResultSchema,ListPromptsResultSchema,ListResourcesResultSchema,ListToolsResultSchema,ReadResourceResultSchema}from"@modelcontextprotocol/core";import{isInputRequiredResult as isInputRequiredResult2}from"@modelcontextprotocol/server";var MCP_MIDDLEWARE_METHODS=["tools/call","tools/list","resources/read","resources/list","prompts/get","prompts/list"];function withMcpMiddlewareParams(request,params){if(typeof request!="object"||request===null||Array.isArray(request))throw new TypeError("[mcp-use] MCP middleware received an invalid downstream request");return{...request,params}}function createMcpMiddlewareEntry(pattern,handler){let normalizedPattern=normalizeMcpMiddlewarePattern(pattern),invoke=handler;if(normalizedPattern!=="*"&&!isMcpMiddlewareMethod(normalizedPattern))throw new TypeError(`Unsupported MCP middleware pattern "${pattern}". Use an exact MCP method or "mcp:*".`);return normalizedPattern==="*"?{pattern:normalizedPattern,handler:async(ctx,next)=>{let downstreamCalled=!1,downstreamResult;if(await invoke(ctx,async()=>{downstreamResult=await next(),downstreamCalled=!0}),!downstreamCalled)throw new Error(`Wildcard MCP middleware "${normalizedPattern}" must call next()`);return downstreamResult}}:{pattern:normalizedPattern,handler:(ctx,next)=>invoke(ctx,next)}}function createMcpEventListenerEntry(pattern,handler){let{pattern:normalizedPattern,phase}=parseMcpPattern(pattern),invoke=handler;return{pattern:normalizedPattern,phase,handler:(ctx,result)=>invoke(ctx,result)}}function matchesPattern(pattern,method){if(pattern==="*")return!0;if(pattern.endsWith("/*")){let prefix=pattern.slice(0,-1);return method.startsWith(prefix)}return pattern===method}function isMcpMiddlewareMethod(value){return MCP_MIDDLEWARE_METHODS.some(method=>method===value)}function composeMiddleware(entries,method,innerFn){let matching=entries.filter(entry=>matchesPattern(entry.pattern,method));return matching.length===0?_ctx=>innerFn():ctx=>{let index=-1,dispatch=i=>i<=index?Promise.reject(new Error("next() called multiple times")):(index=i,i===matching.length?innerFn():matching[i].handler(ctx,()=>dispatch(i+1)));return dispatch(0)}}function freezeMiddlewareContext(ctx){return Object.freeze({method:ctx.method,params:Object.freeze({...ctx.params}),...ctx.request!==void 0&&{request:ctx.request},...ctx.req!==void 0&&{req:ctx.req},...ctx.session!==void 0&&{session:Object.freeze({...ctx.session})},...ctx.auth!==void 0&&{auth:ctx.auth},state:new Map(ctx.state)})}async function runMcpOperation(middlewares,events,method,ctx,innerFn){dispatchMcpEvents(events,method,"before",ctx);let result=await composeMiddleware(middlewares,method,innerFn)(ctx);return assertValidMiddlewareResult(method,result),dispatchMcpEvents(events,method,"complete",ctx,result),result}function assertValidMiddlewareResult(method,result){if((method==="tools/call"||method==="resources/read"||method==="prompts/get")&&isInputRequiredResult2(result))return;let validation=(()=>{switch(method){case"tools/call":return assertArrayProperty(method,result,"content"),CallToolResultSchema.safeParse(result);case"tools/list":return assertArrayResult(method,result),ListToolsResultSchema.safeParse({tools:result});case"resources/read":return assertArrayProperty(method,result,"contents"),ReadResourceResultSchema.safeParse(result);case"resources/list":return assertArrayResult(method,result),ListResourcesResultSchema.safeParse({resources:result});case"prompts/get":return assertArrayProperty(method,result,"messages"),GetPromptResultSchema.safeParse(result);case"prompts/list":return assertArrayResult(method,result),ListPromptsResultSchema.safeParse({prompts:result});default:throw new TypeError(`Unsupported MCP middleware method "${method}"`)}})();if(!validation.success)throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: ${validation.error.message}`)}function assertArrayResult(method,result){if(!Array.isArray(result))throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: expected an array`)}function assertArrayProperty(method,result,property){if(typeof result!="object"||result===null||!Array.isArray(result[property]))throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: expected a ${property} array`)}function dispatchMcpEvents(events,method,phase,ctx,result){let frozen=freezeMiddlewareContext(ctx);for(let entry of events)if(!(entry.phase!==phase||!matchesPattern(entry.pattern,method)))try{entry.handler(frozen,result)}catch(error2){console.error(`[mcp-use] MCP event listener for "${entry.pattern}" (${phase}) threw:`,error2)}}function parseMcpPattern(raw){let pattern=raw.startsWith("mcp:")?raw.slice(4):raw;return pattern.endsWith(":complete")?{pattern:pattern.slice(0,-9),phase:"complete"}:{pattern,phase:"before"}}function normalizeMcpMiddlewarePattern(raw){return raw.startsWith("mcp:")?raw.slice(4):raw}import{CLIENT_INFO_META_KEY as CLIENT_INFO_META_KEY2,isJSONRPCRequest}from"@modelcontextprotocol/server";function colorsEnabled(){return typeof process>"u"||process.env?.NO_COLOR!==void 0?!1:process.stdout?.isTTY===!0}function ansi(open,close){return text2=>colorsEnabled()?`\x1B[${open}m${text2}\x1B[${close}m`:text2}var bold=ansi(1,22),dim=ansi(2,22),red=ansi(31,39),green=ansi(32,39),yellow=ansi(33,39),blue=ansi(34,39),magenta=ansi(35,39),cyan=ansi(36,39),gray=ansi(90,39);function resolveLogLevel(configured){let raw=typeof process>"u"?void 0:process.env?.MCP_USE_LOG_LEVEL?.toLowerCase();return raw==="info"||raw==="debug"||raw==="trace"?raw:configured??"info"}function formatClientInfo(info){if(info!==void 0)return typeof info.version=="string"&&info.version!==""?`${info.name}/${info.version}`:info.name}var detailFormatters={initialize:p=>({subject:formatClientInfo(p.clientInfo)}),ping:()=>({}),"server/discover":()=>({}),"completion/complete":p=>({subject:p.ref.type==="ref/prompt"?p.ref.name:p.ref.uri,input:p.argument}),"logging/setLevel":p=>({subject:p.level}),"prompts/get":p=>({subject:p.name,input:p.arguments}),"prompts/list":()=>({}),"resources/list":()=>({}),"resources/templates/list":()=>({}),"resources/read":p=>({subject:p.uri}),"resources/subscribe":p=>({subject:p.uri}),"resources/unsubscribe":p=>({subject:p.uri}),"subscriptions/listen":()=>({}),"tools/call":p=>({subject:p.name,input:p.arguments}),"tools/list":()=>({}),"sampling/createMessage":()=>({}),"elicitation/create":()=>({}),"roots/list":()=>({})};function isKnownMethod(method){return Object.prototype.hasOwnProperty.call(detailFormatters,method)}function formatDetail(message){if(!isKnownMethod(message.method))return{};try{let formatter=detailFormatters[message.method],detail=formatter(message.params);return typeof detail.subject=="string"||detail.subject===void 0?detail:{}}catch{return{}}}var INLINE_JSON_MAX_LENGTH=80;function inlineJson(value){let text2;try{text2=JSON.stringify(value)??String(value)}catch{text2=String(value)}return text2.length>INLINE_JSON_MAX_LENGTH?`${text2.slice(0,INLINE_JSON_MAX_LENGTH)}...`:text2}function formatClientIdentity(message){let meta=message.params?._meta;if(meta===void 0)return;let info=meta[CLIENT_INFO_META_KEY2];if(!(typeof info!="object"||info===null||typeof info.name!="string"))return formatClientInfo(info)}function sanitize(text2){return text2.replace(/[\u0000-\u001F\u007F-\u009F]+/g," ")}function methodStyle(method){return method.startsWith("tools/")?cyan:method.startsWith("resources/")?green:method.startsWith("prompts/")?magenta:method==="initialize"||method==="ping"?gray:blue}var REDACTED_HEADERS=new Set(["authorization","proxy-authorization","cookie","set-cookie","x-api-key"]);function redactHeaders(headers){return Object.fromEntries(Object.entries(headers).map(([name,value])=>[name,REDACTED_HEADERS.has(name.toLowerCase())?"[REDACTED]":value]))}async function extractResponseOutcome(res){if(!res.body)return{errorMessage:null};let text2;try{text2=await res.clone().text()}catch{return{errorMessage:null}}if(!text2)return{errorMessage:null};let isSse=(res.headers.get("content-type")??"").includes("text/event-stream"),payloads=[],tryParse=raw=>{try{payloads.push(JSON.parse(raw))}catch{}};if(isSse){for(let line of text2.split(/\r?\n/))if(line.startsWith("data:")){let data=line.slice(5).trim();data&&tryParse(data)}}else tryParse(text2);let result;for(let payload of payloads){if(payload===null||typeof payload!="object")continue;let message=payload;if(typeof message.error?.message=="string")return{errorMessage:message.error.message};if(message.result?.isError===!0){let textBlock=(Array.isArray(message.result.content)?message.result.content:[]).find(b=>b?.type==="text"&&typeof b.text=="string");return{errorMessage:textBlock?String(textBlock.text):"tool error"}}"result"in message&&(result=message.result)}return{errorMessage:null,result}}function compactToolResult(result){if(result===null||typeof result!="object")return result;let{structuredContent,content}=result;if(structuredContent!==void 0)return structuredContent;if(Array.isArray(content)){let[block]=content;if(content.length===1&&block?.type==="text")return block.text}return content}function formatForDump(value){function truncate(val){return typeof val=="string"&&val.length>100?`${val.slice(0,100)}...`:Array.isArray(val)?val.map(truncate):val!==null&&typeof val=="object"?Object.fromEntries(Object.entries(val).map(([k,v])=>[k,truncate(v)])):val}try{return JSON.stringify(truncate(value),null,2)}catch{return String(value)}}var DUMP_BODY_MAX_LENGTH=1e4;async function printTraceDump(response,requestHeaders,requestBody,readResponseBody){console.log(`
|
|
1
|
+
import{resolvePublicFilePath,servePublicFile}from"./chunk-ZMU5USAZ.js";import{hasExplicitAssetsBase,originFromAssetsBase,resolveAssetsBase,resolveServerOrigin}from"./chunk-6KY574WV.js";import{registerOpenAPITools}from"./chunk-Y26DNVWA.js";import{completable,normalizeCompletions}from"./chunk-OJF6B5EU.js";import{isUsageDisabled,recordUsage}from"./chunk-R5E3UOG6.js";import{inheritBufferedResponse,toNodeHandler,trackBufferedResponse}from"./chunk-V2VQP73V.js";import{authInfoFromRequest,composeFetch,getOAuthProtectedResourceMetadataUrl,getRequestBag,hostValidationMiddleware,isHtmlNavigationRequest,jsonBodyMiddleware,matchesPath,matchesPathPrefix,oauthMetadata,originValidationMiddleware,pathUnderBase,pathnameOf,requireBearerAuth}from"./chunk-ZSPSHXAE.js";import{getOAuthProviderOptions,resolveConfiguredOAuthResource,resolveLocalOAuthResource,wrapOAuthTokenVerifier}from"./chunk-3FHYLNH3.js";import{localhostAllowedHostnames,localhostAllowedOrigins,McpServer as SdkMcpServer,ResourceTemplate,CLIENT_CAPABILITIES_META_KEY as CLIENT_CAPABILITIES_META_KEY3,CLIENT_INFO_META_KEY as CLIENT_INFO_META_KEY3,PROTOCOL_VERSION_META_KEY,isJSONRPCRequest as isJSONRPCRequest2,isInputRequiredResult as isInputRequiredResult3}from"@modelcontextprotocol/server";import{createServer as createNodeHttpServer}from"#mcp-use-node-http";import{Hono}from"hono";var FAVICON_CACHE_CONTROL="public, max-age=31536000, immutable",FAVICON_REDIRECT_CACHE_CONTROL="public, max-age=300";function protocolOf(value){return/^([a-z][a-z\d+.-]*):/i.exec(value)?.[1]?.toLowerCase()}function publicAssetPath(basePath,source){return`${basePath==="/"?"":basePath}/_mcp-use/public/${source.split("/").map(segment=>encodeURIComponent(segment)).join("/")}`}function isLocalPublicSource(source){return protocolOf(source)===void 0}function selectFaviconFromIcons(icons){return icons[0]}function assertLocalPublicSource(source,field){if(source.startsWith("/")||source.includes("\\")||source.includes("?")||source.includes("#")||source.split("/").some(segment=>segment===""||segment===".."))throw new TypeError(`${field} must be an http(s) URL, image data URL, or safe path relative to public/`)}function parseDataImage(source,field){let comma=source.indexOf(",");if(comma<0)throw new TypeError(`${field} must be a valid image data URL`);let metadata=source.slice(5,comma),payload=source.slice(comma+1),parts=metadata.split(";"),mimeType=parts[0]?.toLowerCase()??"";if(!mimeType.startsWith("image/"))throw new TypeError(`${field} data URL must use an image MIME type`);try{if(parts.includes("base64")){let binary2=atob(payload);return{mimeType,bytes:Uint8Array.from(binary2,character=>character.charCodeAt(0))}}return{mimeType,bytes:new TextEncoder().encode(decodeURIComponent(payload))}}catch{throw new TypeError(`${field} must be a valid image data URL`)}}function assertBrandingSource(source,field){if(typeof source!="string"||source.length===0)throw new TypeError(`${field} must be a non-empty string`);let protocol=protocolOf(source);if(protocol===void 0)return assertLocalPublicSource(source,field),source;if(protocol==="data")return parseDataImage(source,field),source;if(protocol!=="http"&&protocol!=="https")throw new TypeError(`${field} must be an http(s) URL, image data URL, or safe path relative to public/`);try{new URL(source)}catch{throw new TypeError(`${field} must be a valid absolute http(s) URL`)}return source}function normalizeServerBranding(config){let websiteUrl;if(config.websiteUrl!==void 0){if(typeof config.websiteUrl!="string"||config.websiteUrl.length===0)throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL");let parsed;try{parsed=new URL(config.websiteUrl)}catch{throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL")}if(parsed.protocol!=="http:"&&parsed.protocol!=="https:")throw new TypeError("websiteUrl must be a non-empty absolute http(s) URL");websiteUrl=config.websiteUrl}let icons;if(config.icons!==void 0){if(!Array.isArray(config.icons))throw new TypeError("icons must be an array of MCP Icon objects");icons=Object.freeze(config.icons.map((value,index)=>{if(typeof value!="object"||value===null)throw new TypeError(`icons[${index}] must be an MCP Icon object`);let icon=value,src=assertBrandingSource(icon.src,`icons[${index}].src`),mimeType=icon.mimeType;if(mimeType!==void 0&&(typeof mimeType!="string"||!mimeType.toLowerCase().startsWith("image/")))throw new TypeError(`icons[${index}].mimeType must be an image MIME type when provided`);let sizes=icon.sizes;if(sizes!==void 0&&(!Array.isArray(sizes)||sizes.some(size=>typeof size!="string"||size.length===0)))throw new TypeError(`icons[${index}].sizes must be an array of non-empty strings when provided`);let normalizedSizes=sizes===void 0?void 0:sizes.map(size=>size),theme=icon.theme;if(theme!==void 0&&theme!=="light"&&theme!=="dark")throw new TypeError(`icons[${index}].theme must be "light" or "dark" when provided`);return Object.freeze({src,...mimeType!==void 0&&{mimeType},...normalizedSizes!==void 0&&{sizes:Object.freeze(normalizedSizes)},...theme!==void 0&&{theme}})}))}let explicitFavicon=config.favicon===void 0?void 0:assertBrandingSource(config.favicon,"favicon"),inferred=explicitFavicon===void 0?selectFaviconFromIcons(icons??[]):void 0,favicon=explicitFavicon??inferred?.src,faviconMimeType=inferred?.mimeType??icons?.find(icon=>icon.src===explicitFavicon)?.mimeType;return Object.freeze({...favicon!==void 0&&{favicon},...faviconMimeType!==void 0&&{faviconMimeType},...icons!==void 0&&{icons},...websiteUrl!==void 0&&{websiteUrl}})}function resolveImplementationIcons(icons,request,basePath){if(icons!==void 0)return icons.map(icon=>({...icon,src:request!==void 0&&isLocalPublicSource(icon.src)?`${resolveAssetsBase(request)}${publicAssetPath(basePath,icon.src)}`:icon.src,...icon.sizes!==void 0&&{sizes:[...icon.sizes]}}))}function hasLocalBrandingAsset(branding){return branding.favicon!==void 0&&isLocalPublicSource(branding.favicon)||branding.icons?.some(icon=>isLocalPublicSource(icon.src))===!0}function createFaviconHandler(branding,options){let source=branding.favicon;if(source!==void 0)return async request=>{if(request.method!=="GET"&&request.method!=="HEAD")return new Response("Method Not Allowed",{status:405,headers:{Allow:"GET, HEAD"}});if(new URL(request.url).pathname!=="/favicon.ico")return new Response("Not Found",{status:404});let protocol=protocolOf(source);if(protocol==="http"||protocol==="https")return new Response(null,{status:307,headers:{Location:source,"Cache-Control":FAVICON_REDIRECT_CACHE_CONTROL}});if(protocol==="data"){let data=parseDataImage(source,"favicon");return new Response(request.method==="HEAD"?null:data.bytes.buffer,{status:200,headers:{"Content-Type":branding.faviconMimeType??data.mimeType,"Cache-Control":FAVICON_CACHE_CONTROL,"X-Content-Type-Options":"nosniff"}})}let{join}=await import("path"),publicRoot=options.dev?join(options.projectRoot,"public"):join(options.projectRoot,".mcp-use/build/views/public"),diskPath=await resolvePublicFilePath(publicRoot,source);if(diskPath===null)return new Response("Not Found",{status:404,headers:{"Cache-Control":"no-store"}});let response=await servePublicFile(diskPath,{...options.deferCors===!0&&{deferCors:!0},...request.method==="HEAD"&&{head:!0}});return response.headers.set("Cache-Control",FAVICON_CACHE_CONTROL),response.headers.set("X-Content-Type-Options","nosniff"),branding.faviconMimeType!==void 0&&response.headers.set("Content-Type",branding.faviconMimeType),response}}function assertServerConfig(config){if(config.basePath!==void 0){if(typeof config.basePath!="string")throw new TypeError("basePath must be an absolute URL pathname without empty segments, trailing slash, query, fragment, or whitespace");let{basePath}=config;if(!basePath.startsWith("/")||basePath.includes("?")||basePath.includes("#")||/\s/.test(basePath)||basePath.includes("//")||basePath.length>1&&basePath.endsWith("/"))throw new TypeError("basePath must be an absolute URL pathname without empty segments, trailing slash, query, fragment, or whitespace")}if(config.port!==void 0&&(typeof config.port!="number"||!Number.isInteger(config.port)||config.port<0||config.port>65535))throw new TypeError("port must be an integer between 0 and 65535");if(config.skills!==void 0&&typeof config.skills!="boolean"){if(typeof config.skills!="object"||config.skills===null||Array.isArray(config.skills))throw new TypeError("skills must be a boolean or configuration object");let directory=config.skills.directory;if(directory!==void 0&&typeof directory!="string")throw new TypeError("skills.directory must be a string when provided")}}var DEFAULT_LISTEN_HOST="127.0.0.1";function resolveListenHost(explicitHost,configuredHost,env=process.env){if(explicitHost!==void 0)return explicitHost;let envHost=env.HOST?.trim();return envHost!==void 0&&envHost!==""?envHost:configuredHost??DEFAULT_LISTEN_HOST}function resolveListenPort(explicitPort,configuredPort,env=process.env){if(explicitPort!==void 0)return explicitPort;let envPort=parsePort(env.PORT);return envPort!==void 0?envPort:configuredPort??3e3}function parsePort(value){if(value===void 0||value.trim()==="")return;let port=Number(value);return Number.isInteger(port)&&port>=0&&port<=65535?port:void 0}import{CLIENT_CAPABILITIES_META_KEY as CLIENT_CAPABILITIES_META_KEY2,CLIENT_INFO_META_KEY}from"@modelcontextprotocol/server";import{HonoRequest}from"hono/request";import{CLIENT_CAPABILITIES_META_KEY}from"@modelcontextprotocol/server";var UI_EXTENSION_ID="io.modelcontextprotocol/ui",UI_MIME_TYPE="text/html;profile=mcp-app",UI_RESOURCE_URI_PREFIX="ui://views/";var UI_RESOURCE_URI_META_KEY="ui/resourceUri";function viewResourceUri(viewName){return`${UI_RESOURCE_URI_PREFIX}${viewName}.html`}var clientCapabilitiesByRequest=new WeakMap;function stashClientCapabilities(request,capabilities){clientCapabilitiesByRequest.set(request,capabilities)}function extractClientCapabilitiesFromBody(body){if(typeof body!="object"||body===null)return;let params=body.params;if(typeof params!="object"||params===null)return;let meta=params._meta;if(typeof meta!="object"||meta===null)return;let capabilities=meta[CLIENT_CAPABILITIES_META_KEY];if(!(typeof capabilities!="object"||capabilities===null))return capabilities}function supportsViews(capabilities){let extensions=capabilities?.extensions;if(extensions===void 0)return!1;let uiExtension=extensions[UI_EXTENSION_ID];if(typeof uiExtension!="object"||uiExtension===null)return!1;let mimeTypes=uiExtension.mimeTypes;return Array.isArray(mimeTypes)?mimeTypes.includes(UI_MIME_TYPE):!1}function requireOAuthAuthInfo(authInfo){if(authInfo===void 0||authInfo.extra===void 0||authInfo.expiresAt===void 0)throw new Error("OAuth callback did not receive mapped AuthInfo.extra")}function stringValue(value){return typeof value=="string"?value:void 0}function coordinateValue(value){return typeof value=="string"||typeof value=="number"&&Number.isFinite(value)?value:void 0}function normalizeUserContext(meta){if(meta===void 0)return;let locale=stringValue(meta["openai/locale"])??stringValue(meta["webplus/i18n"]),userAgent=stringValue(meta["openai/userAgent"]),subject=stringValue(meta["openai/subject"]),conversationId=stringValue(meta["openai/session"]),organizationId=stringValue(meta["openai/organization"]),rawLocation=meta["openai/userLocation"],location;if(typeof rawLocation=="object"&&rawLocation!==null&&!Array.isArray(rawLocation)){let values=rawLocation,normalized={city:stringValue(values.city),region:stringValue(values.region),country:stringValue(values.country),timezone:stringValue(values.timezone),latitude:coordinateValue(values.latitude),longitude:coordinateValue(values.longitude)},entries=Object.entries(normalized).filter(entry=>entry[1]!==void 0);entries.length>0&&(location=Object.fromEntries(entries))}if(!(locale===void 0&&userAgent===void 0&&location===void 0&&subject===void 0&&conversationId===void 0&&organizationId===void 0))return{...locale!==void 0&&{locale},...userAgent!==void 0&&{userAgent},...location!==void 0&&{location},...subject!==void 0&&{subject},...conversationId!==void 0&&{conversationId},...organizationId!==void 0&&{organizationId}}}function toClientContext(ctx){let envelope=ctx.mcpReq.envelope,capabilities={...envelope?.[CLIENT_CAPABILITIES_META_KEY2]??{}},info={...envelope?.[CLIENT_INFO_META_KEY]??{}},user=normalizeUserContext(ctx.mcpReq._meta);return{can(capability){return Object.hasOwn(capabilities,capability)},capabilities(){return{...capabilities}},extension(id){let settings=capabilities.extensions?.[id];return settings===void 0?void 0:{...settings}},info(){return{...info}},user(){return user===void 0?void 0:{...user,...user.location!==void 0&&{location:{...user.location}}}},supportsViews(){return supportsViews(capabilities)}}}function toRequestContext(ctx){let rawRequest=ctx.http?.req,http=rawRequest===void 0?void 0:getRequestBag(rawRequest).honoContext,request=http?.req??(rawRequest===void 0?void 0:new HonoRequest(rawRequest)),additions={signal:ctx.mcpReq.signal,...request!==void 0&&{request},...ctx.mcpReq.inputResponses!==void 0&&{inputResponses:ctx.mcpReq.inputResponses},client:toClientContext(ctx),requestState:()=>ctx.mcpReq.requestState(),async sendNotification(method,params){await ctx.mcpReq.notify({method,...params!==void 0&&{params}})},async reportProgress(progress,total,message){let progressToken=ctx.mcpReq._meta?.progressToken;return progressToken===void 0?!1:(await ctx.mcpReq.notify({method:"notifications/progress",params:{progressToken,progress,...total!==void 0&&{total},...message!==void 0&&{message}}}),!0)},async sendLog(level,data,logger){await ctx.mcpReq.notify({method:"notifications/message",params:{level,data,...logger!==void 0&&{logger}}})}};return http!==void 0?Object.assign(http,additions):{...additions,...request!==void 0&&{req:request}}}function toAuthenticatedRequestContext(ctx){let authInfo=ctx.http?.authInfo;return requireOAuthAuthInfo(authInfo),Object.assign(toRequestContext(ctx),{auth:{user:authInfo.extra.user,payload:authInfo.extra.payload,accessToken:authInfo.token,scopes:[...authInfo.scopes],permissions:[...authInfo.extra.permissions],...authInfo.clientId.length>0&&{clientId:authInfo.clientId},expiresAt:authInfo.expiresAt,...authInfo.resource!==void 0&&{resource:authInfo.resource}}})}import{isInputRequiredResult}from"@modelcontextprotocol/server";function isReadResourceResult(result){return"contents"in result&&Array.isArray(result.contents)}function isGetPromptResult(result){return"messages"in result&&Array.isArray(result.messages)}function toResourceResult(result,uri){if(isReadResourceResult(result))return result;let mime=result._meta&&typeof result._meta=="object"&&typeof result._meta.mimeType=="string"?result._meta.mimeType:void 0,contents=[];for(let block of result.content??[]){let mapped=contentBlockToResourceContents(block,uri,mime);mapped!==void 0&&contents.push(mapped)}return contents.length===0&&result.structuredContent!==void 0&&contents.push({uri,mimeType:"application/json",text:JSON.stringify(result.structuredContent)}),contents.length===0&&contents.push({uri,mimeType:"text/plain",text:""}),{contents}}function contentBlockToResourceContents(block,uri,mimeHint){if(block.type==="text")return{uri,mimeType:mimeHint??"text/plain",text:block.text};if(block.type==="image"||block.type==="audio")return{uri,mimeType:block.mimeType,blob:block.data};if(block.type==="resource")return{...block.resource}}function toPromptResult(result){if(isInputRequiredResult(result)||isGetPromptResult(result))return result;let messages=(result.content??[]).map(content=>({role:"user",content}));return messages.length===0&&result.structuredContent!==void 0&&messages.push({role:"user",content:{type:"text",text:JSON.stringify(result.structuredContent)}}),messages.length===0&&messages.push({role:"user",content:{type:"text",text:""}}),{messages}}var DEFAULT_METHODS=["GET","HEAD","POST","OPTIONS"],DEFAULT_ALLOWED_HEADERS=["Content-Type","Authorization","mcp-protocol-version","mcp-method","mcp-name"];function resolveAllowedOrigin(origin,requestOrigin){return origin===void 0?requestOrigin:typeof origin=="function"?origin(requestOrigin):origin==="*"?"*":Array.isArray(origin)?requestOrigin!==null&&origin.includes(requestOrigin)?requestOrigin:null:origin}function corsHeaders(options,request){if(request.headers.has("Access-Control-Allow-Origin"))return;let requestOrigin=request.headers.get("Origin"),allowedOrigin=resolveAllowedOrigin(options.origin,requestOrigin);if(allowedOrigin===null)return;let headers={"Access-Control-Allow-Origin":allowedOrigin,"Access-Control-Allow-Methods":options.methods.join(", "),"Access-Control-Allow-Headers":options.allowedHeaders.join(", ")};return options.credentials&&(headers["Access-Control-Allow-Credentials"]="true"),allowedOrigin!=="*"&&(headers.Vary="Origin"),headers}function mergeCorsHeaders(response,headers){if(response.headers.has("Access-Control-Allow-Origin"))return response;let merged=new Headers(response.headers);return new Headers(headers).forEach((value,key)=>{merged.set(key,value)}),inheritBufferedResponse(response,new Response(response.body,{status:response.status,statusText:response.statusText,headers:merged}))}function corsFetchMiddleware(options){if(!(options.enabled!==!1))return async(_request,next)=>next();let resolved={...options.origin!==void 0&&{origin:options.origin},methods:options.methods??DEFAULT_METHODS,allowedHeaders:options.allowedHeaders??DEFAULT_ALLOWED_HEADERS,credentials:options.credentials??!1};return async(request,next)=>{let headers=corsHeaders(resolved,request);if(headers===void 0)return next();if(request.method==="OPTIONS")return new Response(null,{status:204,headers});let response=await next();return mergeCorsHeaders(response,headers)}}function isGlobalCorsEnabled(cors){return cors!==void 0&&cors.enabled!==!1}import{CallToolResultSchema,GetPromptResultSchema,ListPromptsResultSchema,ListResourcesResultSchema,ListToolsResultSchema,ReadResourceResultSchema}from"@modelcontextprotocol/core";import{isInputRequiredResult as isInputRequiredResult2}from"@modelcontextprotocol/server";var MCP_MIDDLEWARE_METHODS=["tools/call","tools/list","resources/read","resources/list","prompts/get","prompts/list"];function withMcpMiddlewareParams(request,params){if(typeof request!="object"||request===null||Array.isArray(request))throw new TypeError("[mcp-use] MCP middleware received an invalid downstream request");return{...request,params}}function createMcpMiddlewareEntry(pattern,handler){let normalizedPattern=normalizeMcpMiddlewarePattern(pattern),invoke=handler;if(normalizedPattern!=="*"&&!isMcpMiddlewareMethod(normalizedPattern))throw new TypeError(`Unsupported MCP middleware pattern "${pattern}". Use an exact MCP method or "mcp:*".`);return normalizedPattern==="*"?{pattern:normalizedPattern,handler:async(ctx,next)=>{let downstreamCalled=!1,downstreamResult;if(await invoke(ctx,async()=>{downstreamResult=await next(),downstreamCalled=!0}),!downstreamCalled)throw new Error(`Wildcard MCP middleware "${normalizedPattern}" must call next()`);return downstreamResult}}:{pattern:normalizedPattern,handler:(ctx,next)=>invoke(ctx,next)}}function createMcpEventListenerEntry(pattern,handler){let{pattern:normalizedPattern,phase}=parseMcpPattern(pattern),invoke=handler;return{pattern:normalizedPattern,phase,handler:(ctx,result)=>invoke(ctx,result)}}function matchesPattern(pattern,method){if(pattern==="*")return!0;if(pattern.endsWith("/*")){let prefix=pattern.slice(0,-1);return method.startsWith(prefix)}return pattern===method}function isMcpMiddlewareMethod(value){return MCP_MIDDLEWARE_METHODS.some(method=>method===value)}function composeMiddleware(entries,method,innerFn){let matching=entries.filter(entry=>matchesPattern(entry.pattern,method));return matching.length===0?_ctx=>innerFn():ctx=>{let index=-1,dispatch=i=>i<=index?Promise.reject(new Error("next() called multiple times")):(index=i,i===matching.length?innerFn():matching[i].handler(ctx,()=>dispatch(i+1)));return dispatch(0)}}function freezeMiddlewareContext(ctx){return Object.freeze({method:ctx.method,params:Object.freeze({...ctx.params}),...ctx.request!==void 0&&{request:ctx.request},...ctx.req!==void 0&&{req:ctx.req},...ctx.session!==void 0&&{session:Object.freeze({...ctx.session})},...ctx.auth!==void 0&&{auth:ctx.auth},state:new Map(ctx.state)})}async function runMcpOperation(middlewares,events,method,ctx,innerFn){dispatchMcpEvents(events,method,"before",ctx);let result=await composeMiddleware(middlewares,method,innerFn)(ctx);return assertValidMiddlewareResult(method,result),dispatchMcpEvents(events,method,"complete",ctx,result),result}function assertValidMiddlewareResult(method,result){if((method==="tools/call"||method==="resources/read"||method==="prompts/get")&&isInputRequiredResult2(result))return;let validation=(()=>{switch(method){case"tools/call":return assertArrayProperty(method,result,"content"),CallToolResultSchema.safeParse(result);case"tools/list":return assertArrayResult(method,result),ListToolsResultSchema.safeParse({tools:result});case"resources/read":return assertArrayProperty(method,result,"contents"),ReadResourceResultSchema.safeParse(result);case"resources/list":return assertArrayResult(method,result),ListResourcesResultSchema.safeParse({resources:result});case"prompts/get":return assertArrayProperty(method,result,"messages"),GetPromptResultSchema.safeParse(result);case"prompts/list":return assertArrayResult(method,result),ListPromptsResultSchema.safeParse({prompts:result});default:throw new TypeError(`Unsupported MCP middleware method "${method}"`)}})();if(!validation.success)throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: ${validation.error.message}`)}function assertArrayResult(method,result){if(!Array.isArray(result))throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: expected an array`)}function assertArrayProperty(method,result,property){if(typeof result!="object"||result===null||!Array.isArray(result[property]))throw new TypeError(`[mcp-use] ${method} middleware returned an invalid result: expected a ${property} array`)}function dispatchMcpEvents(events,method,phase,ctx,result){let frozen=freezeMiddlewareContext(ctx);for(let entry of events)if(!(entry.phase!==phase||!matchesPattern(entry.pattern,method)))try{entry.handler(frozen,result)}catch(error2){console.error(`[mcp-use] MCP event listener for "${entry.pattern}" (${phase}) threw:`,error2)}}function parseMcpPattern(raw){let pattern=raw.startsWith("mcp:")?raw.slice(4):raw;return pattern.endsWith(":complete")?{pattern:pattern.slice(0,-9),phase:"complete"}:{pattern,phase:"before"}}function normalizeMcpMiddlewarePattern(raw){return raw.startsWith("mcp:")?raw.slice(4):raw}import{CLIENT_INFO_META_KEY as CLIENT_INFO_META_KEY2,isJSONRPCRequest}from"@modelcontextprotocol/server";function colorsEnabled(){return typeof process>"u"||process.env?.NO_COLOR!==void 0?!1:process.stdout?.isTTY===!0}function ansi(open,close){return text2=>colorsEnabled()?`\x1B[${open}m${text2}\x1B[${close}m`:text2}var bold=ansi(1,22),dim=ansi(2,22),red=ansi(31,39),green=ansi(32,39),yellow=ansi(33,39),blue=ansi(34,39),magenta=ansi(35,39),cyan=ansi(36,39),gray=ansi(90,39);function resolveLogLevel(configured){let raw=typeof process>"u"?void 0:process.env?.MCP_USE_LOG_LEVEL?.toLowerCase();return raw==="info"||raw==="debug"||raw==="trace"?raw:configured??"info"}function formatClientInfo(info){if(info!==void 0)return typeof info.version=="string"&&info.version!==""?`${info.name}/${info.version}`:info.name}var detailFormatters={initialize:p=>({subject:formatClientInfo(p.clientInfo)}),ping:()=>({}),"server/discover":()=>({}),"completion/complete":p=>({subject:p.ref.type==="ref/prompt"?p.ref.name:p.ref.uri,input:p.argument}),"logging/setLevel":p=>({subject:p.level}),"prompts/get":p=>({subject:p.name,input:p.arguments}),"prompts/list":()=>({}),"resources/list":()=>({}),"resources/templates/list":()=>({}),"resources/read":p=>({subject:p.uri}),"resources/subscribe":p=>({subject:p.uri}),"resources/unsubscribe":p=>({subject:p.uri}),"subscriptions/listen":()=>({}),"tools/call":p=>({subject:p.name,input:p.arguments}),"tools/list":()=>({}),"sampling/createMessage":()=>({}),"elicitation/create":()=>({}),"roots/list":()=>({})};function isKnownMethod(method){return Object.prototype.hasOwnProperty.call(detailFormatters,method)}function formatDetail(message){if(!isKnownMethod(message.method))return{};try{let formatter=detailFormatters[message.method],detail=formatter(message.params);return typeof detail.subject=="string"||detail.subject===void 0?detail:{}}catch{return{}}}var INLINE_JSON_MAX_LENGTH=80;function inlineJson(value){let text2;try{text2=JSON.stringify(value)??String(value)}catch{text2=String(value)}return text2.length>INLINE_JSON_MAX_LENGTH?`${text2.slice(0,INLINE_JSON_MAX_LENGTH)}...`:text2}function formatClientIdentity(message){let meta=message.params?._meta;if(meta===void 0)return;let info=meta[CLIENT_INFO_META_KEY2];if(!(typeof info!="object"||info===null||typeof info.name!="string"))return formatClientInfo(info)}function sanitize(text2){return text2.replace(/[\u0000-\u001F\u007F-\u009F]+/g," ")}function methodStyle(method){return method.startsWith("tools/")?cyan:method.startsWith("resources/")?green:method.startsWith("prompts/")?magenta:method==="initialize"||method==="ping"?gray:blue}var REDACTED_HEADERS=new Set(["authorization","proxy-authorization","cookie","set-cookie","x-api-key"]);function redactHeaders(headers){return Object.fromEntries(Object.entries(headers).map(([name,value])=>[name,REDACTED_HEADERS.has(name.toLowerCase())?"[REDACTED]":value]))}async function extractResponseOutcome(res){if(!res.body)return{errorMessage:null};let text2;try{text2=await res.clone().text()}catch{return{errorMessage:null}}if(!text2)return{errorMessage:null};let isSse=(res.headers.get("content-type")??"").includes("text/event-stream"),payloads=[],tryParse=raw=>{try{payloads.push(JSON.parse(raw))}catch{}};if(isSse){for(let line of text2.split(/\r?\n/))if(line.startsWith("data:")){let data=line.slice(5).trim();data&&tryParse(data)}}else tryParse(text2);let result;for(let payload of payloads){if(payload===null||typeof payload!="object")continue;let message=payload;if(typeof message.error?.message=="string")return{errorMessage:message.error.message};if(message.result?.isError===!0){let textBlock=(Array.isArray(message.result.content)?message.result.content:[]).find(b=>b?.type==="text"&&typeof b.text=="string");return{errorMessage:textBlock?String(textBlock.text):"tool error"}}"result"in message&&(result=message.result)}return{errorMessage:null,result}}function compactToolResult(result){if(result===null||typeof result!="object")return result;let{structuredContent,content}=result;if(structuredContent!==void 0)return structuredContent;if(Array.isArray(content)){let[block]=content;if(content.length===1&&block?.type==="text")return block.text}return content}function formatForDump(value){function truncate(val){return typeof val=="string"&&val.length>100?`${val.slice(0,100)}...`:Array.isArray(val)?val.map(truncate):val!==null&&typeof val=="object"?Object.fromEntries(Object.entries(val).map(([k,v])=>[k,truncate(v)])):val}try{return JSON.stringify(truncate(value),null,2)}catch{return String(value)}}var DUMP_BODY_MAX_LENGTH=1e4;async function printTraceDump(response,requestHeaders,requestBody,readResponseBody){console.log(`
|
|
2
2
|
${cyan("=".repeat(80))}`),console.log(bold(cyan("[TRACE] Request Details"))),console.log(cyan("-".repeat(80))),Object.keys(requestHeaders).length>0&&(console.log(yellow("Request Headers:")),console.log(formatForDump(redactHeaders(requestHeaders)))),requestBody!==void 0&&(console.log(yellow("Request Body:")),console.log(typeof requestBody=="string"?requestBody:formatForDump(requestBody)));let responseHeaders={};if(response.headers.forEach((value,key)=>{responseHeaders[key]=value}),Object.keys(responseHeaders).length>0&&(console.log(yellow("Response Headers:")),console.log(formatForDump(redactHeaders(responseHeaders)))),!readResponseBody)console.log(`${yellow("Response Body:")} (streaming \u2014 not dumped)`);else if(response.body===null)console.log(`${yellow("Response Body:")} (no body)`);else try{let text2=await response.clone().text();if(text2.length===0)console.log(`${yellow("Response Body:")} (empty)`);else{console.log(yellow("Response Body:"));try{console.log(formatForDump(JSON.parse(text2)))}catch{console.log(text2.length>DUMP_BODY_MAX_LENGTH?`${text2.slice(0,DUMP_BODY_MAX_LENGTH)}
|
|
3
3
|
... (truncated, ${text2.length-DUMP_BODY_MAX_LENGTH} more characters)`:text2)}}}catch{console.log(`${yellow("Response Body:")} (unable to read)`)}console.log(`${cyan("=".repeat(80))}
|
|
4
4
|
`)}function styleStatus(status){let text2=String(status);return status>=500?magenta(text2):status>=400?red(text2):status>=300?yellow(text2):green(text2)}function isNoisyRequest(httpMethod,pathname){return httpMethod!=="GET"&&httpMethod!=="HEAD"?!1:pathname.endsWith("/favicon.ico")}function requestLogger(options={}){return options.enabled===!1?(_request,next)=>next():async(request,next)=>{let level=resolveLogLevel(options.level),startedAt=Date.now(),httpMethod=request.method,pathname=new URL(request.url).pathname;if(isNoisyRequest(httpMethod,pathname))return next();let requestHeaders={};level==="trace"&&request.headers.forEach((value,key)=>{requestHeaders[key]=value});let requestBody;if(httpMethod!=="GET"&&httpMethod!=="HEAD"){let parsedBody=getRequestBag(request).parsedBody;if(parsedBody!==void 0)requestBody=parsedBody;else try{requestBody=await request.clone().json()}catch{}}let response=await next(),durationMs=Date.now()-startedAt,timestamp=new Date().toISOString().substring(11,19),mcpRequest=isJSONRPCRequest(requestBody)?requestBody:void 0,isStreamingMethod=mcpRequest?.method==="subscriptions/listen",lines=[[dim(timestamp),bold(httpMethod),pathname,styleStatus(response.status),dim(`in ${durationMs}ms`)].join(" ")];if(mcpRequest!==void 0){let method=sanitize(mcpRequest.method),parts=[` ${methodStyle(method)(method)}`],detail=formatDetail(mcpRequest);detail.subject!==void 0&&parts.push(bold(sanitize(detail.subject)));let echoPayloads=level!=="info";echoPayloads&&detail.input!==void 0&&parts.push(inlineJson(detail.input));let outcome=isStreamingMethod?{errorMessage:null}:await extractResponseOutcome(response);if(echoPayloads&&mcpRequest.method==="tools/call"&&outcome.errorMessage===null&&outcome.result!==void 0&&parts.push(dim("->"),inlineJson(compactToolResult(outcome.result))),mcpRequest.method!=="initialize"){let client=formatClientIdentity(mcpRequest);client!==void 0&&parts.push(dim(sanitize(client)))}outcome.errorMessage!==null?parts.push(red(`ERROR ${sanitize(outcome.errorMessage)}`)):response.status>=400&&parts.push(red(`ERROR (HTTP ${response.status})`)),lines.push(parts.join(" "))}return console.log(lines.join(`
|
package/dist/internal/usage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{flushUsage,isUsageDisabled,recordUsage}from"../chunk-
|
|
1
|
+
import{flushUsage,isUsageDisabled,recordUsage}from"../chunk-R5E3UOG6.js";export{flushUsage,isUsageDisabled,recordUsage};
|
package/dist/oauth/auth0.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{booleanValue,createJwtVerifier,normalizedProviderUrl,normalizedStrings,
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{booleanValue,createJwtVerifier,invalidToken,normalizedProviderUrl,normalizedStrings,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthAuth0Provider(options={}){let domain=options.domain??oauthEnvironmentValue("MCP_USE_OAUTH_AUTH0_DOMAIN"),audience=oauthEnvironmentValue("MCP_USE_OAUTH_AUTH0_AUDIENCE");if(domain===void 0)throw new Error("Auth0 domain is required.");let resolvedOptions={...options,...options.resource===void 0&&audience!==void 0&&{resource:audience}},issuer=normalizedProviderUrl(domain,"Auth0 domain").href;return oauthCustomProvider({...resolvedOptions,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(issuer,".well-known/jwks.json")),resource}),oauthMetadata:{issuer,authorization_endpoint:providerEndpoint(issuer,"authorize"),token_endpoint:providerEndpoint(issuer,"oauth/token"),registration_endpoint:providerEndpoint(issuer,"oidc/register"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"]},mapAuthInfo:mapUser})}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub");if(id===void 0)throw invalidToken("Missing Auth0 subject");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("name",stringValue(payload,"name")),...optional("nickname",stringValue(payload,"nickname")),...optional("picture",stringValue(payload,"picture")),...optional("emailVerified",booleanValue(payload,"email_verified")),...optional("updatedAt",stringValue(payload,"updated_at")),roles:normalizedStrings(payload.roles)},payload,permissions:normalizedStrings(payload.permissions)}}function optional(key,value){return value===void 0?{}:{[key]:value}}export{oauthAuth0Provider};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{booleanValue,createJwtVerifier,normalizedProviderUrl,normalizedStrings,
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{booleanValue,createJwtVerifier,invalidToken,normalizedProviderUrl,normalizedStrings,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthBetterAuthProvider(options={}){let authURL=options.authURL??oauthEnvironmentValue("MCP_USE_OAUTH_BETTER_AUTH_URL");if(authURL===void 0)throw new Error("Better Auth authURL is required.");let issuer=normalizedProviderUrl(authURL,"Better Auth authURL").href.replace(/\/$/,"");return oauthCustomProvider({...options,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(issuer,"jwks")),resource}),oauthMetadata:metadata(issuer,options.scopesSupported),mapAuthInfo:mapUser})}function metadata(issuer,scopesSupported){return{issuer,authorization_endpoint:providerEndpoint(issuer,"oauth2/authorize"),token_endpoint:providerEndpoint(issuer,"oauth2/token"),registration_endpoint:providerEndpoint(issuer,"oauth2/register"),jwks_uri:providerEndpoint(issuer,"jwks"),response_types_supported:["code"],grant_types_supported:["authorization_code","client_credentials","refresh_token"],code_challenge_methods_supported:["S256"],scopes_supported:scopesSupported===void 0?["openid","profile","email","offline_access"]:[...scopesSupported]}}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub");if(id===void 0)throw invalidToken("Missing Better Auth subject");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("name",stringValue(payload,"name")),...optional("picture",stringValue(payload,"picture")),...optional("emailVerified",booleanValue(payload,"email_verified")),...optional("sessionId",stringValue(payload,"sid")),...optional("isAnonymous",booleanValue(payload,"is_anonymous")??booleanValue(payload,"isAnonymous")),roles:normalizedStrings(payload.roles)},payload,permissions:normalizedStrings(payload.permissions)}}function optional(key,value){return value===void 0?{}:{[key]:value}}export{oauthBetterAuthProvider};
|
package/dist/oauth/clerk.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{booleanValue,createJwtVerifier,normalizedProviderUrl,normalizedStrings,
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{booleanValue,createJwtVerifier,invalidToken,normalizedProviderUrl,normalizedStrings,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthClerkProvider(options={}){if(options.audience!==void 0&&(typeof options.audience!="string"||options.audience.trim().length===0))throw new TypeError("Clerk audience must be non-empty");let frontendApiUrl=options.frontendApiUrl??oauthEnvironmentValue("MCP_USE_OAUTH_CLERK_FRONTEND_API_URL");if(frontendApiUrl===void 0)throw new Error("Clerk frontendApiUrl is required.");let issuer=normalizedProviderUrl(frontendApiUrl,"Clerk frontendApiUrl").href.replace(/\/$/,"");return oauthCustomProvider({...options,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(issuer,".well-known/jwks.json")),resource,...options.audience!==void 0?{audience:options.audience}:{issuerBoundAccessTokens:!0}}),oauthMetadata:metadata(issuer),mapAuthInfo:authInfo=>mapUser(authInfo)})}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub");if(id===void 0)throw invalidToken("Missing Clerk subject");let organizationRole=stringValue(payload,"org_role");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("name",stringValue(payload,"name")),...optional("username",stringValue(payload,"username")),...optional("picture",stringValue(payload,"picture")),...optional("emailVerified",booleanValue(payload,"email_verified")),...optional("organizationId",stringValue(payload,"org_id")),...optional("organizationRole",organizationRole),...optional("organizationSlug",stringValue(payload,"org_slug")),roles:organizationRole===void 0?[]:[organizationRole]},payload,permissions:normalizedStrings(payload.org_permissions)}}function metadata(issuer){return{issuer,authorization_endpoint:providerEndpoint(issuer,"oauth/authorize"),token_endpoint:providerEndpoint(issuer,"oauth/token"),registration_endpoint:providerEndpoint(issuer,"oauth/register"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"]}}function optional(key,value){return value===void 0?{}:{[key]:value}}export{oauthClerkProvider};
|
package/dist/oauth/index.d.ts
CHANGED
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
export { OAuthError, OAuthErrorCode, bearerAuthChallengeResponse, getOAuthProtectedResourceMetadataUrl, oauthMetadataResponse, requireBearerAuth, verifyBearerToken, } from "@modelcontextprotocol/server";
|
|
7
7
|
export type { AuthInfo as OAuthAuthInfo, AuthMetadataOptions, BearerAuthOptions, OAuthMetadata, OAuthProtectedResourceMetadata, OAuthTokenVerifier, } from "@modelcontextprotocol/server";
|
|
8
8
|
export { bearerAuth, oauthMetadata } from "./adapters.js";
|
|
9
|
+
export { createJwtVerifier, type JwtVerifierOptions, type VerifiedPayload, } from "./jwt.js";
|
|
9
10
|
export { oauthCustomProvider, type CustomOAuthProviderOptions, type OAuthExtra, type OAuthProvider, type OAuthResourceOptions, } from "./provider.js";
|
package/dist/oauth/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{OAuthError,OAuthErrorCode,bearerAuth,bearerAuthChallengeResponse,getOAuthProtectedResourceMetadataUrl,oauthMetadata,oauthMetadataResponse,requireBearerAuth,verifyBearerToken}from"../chunk-
|
|
1
|
+
import{OAuthError,OAuthErrorCode,bearerAuth,bearerAuthChallengeResponse,getOAuthProtectedResourceMetadataUrl,oauthMetadata,oauthMetadataResponse,requireBearerAuth,verifyBearerToken}from"../chunk-ZSPSHXAE.js";import{createJwtVerifier,oauthCustomProvider}from"../chunk-3FHYLNH3.js";export{OAuthError,OAuthErrorCode,bearerAuth,bearerAuthChallengeResponse,createJwtVerifier,getOAuthProtectedResourceMetadataUrl,oauthCustomProvider,oauthMetadata,oauthMetadataResponse,requireBearerAuth,verifyBearerToken};
|
package/dist/oauth/jwt.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { type AuthInfo, type OAuthTokenVerifier } from "@modelcontextprotocol/server";
|
|
2
2
|
export { invalidToken } from "./errors.js";
|
|
3
|
-
/**
|
|
3
|
+
/** Record of claims extracted from a verified JWT. */
|
|
4
4
|
export type VerifiedPayload = Record<string, unknown>;
|
|
5
|
-
/**
|
|
5
|
+
/** Configures issuer, keys, and claims enforced by a JWT verifier. */
|
|
6
6
|
export interface JwtVerifierOptions {
|
|
7
|
+
/** Expected `iss` claim. Tokens from any other issuer are rejected. */
|
|
7
8
|
issuer: string;
|
|
9
|
+
/** JWKS endpoint the signing keys are fetched from and cached. */
|
|
8
10
|
jwksUrl: URL;
|
|
11
|
+
/** Canonical URL of this MCP resource, matched against the token binding. */
|
|
9
12
|
resource: URL;
|
|
10
13
|
/** Provider-specific JWT audience, when it differs from the MCP resource. */
|
|
11
14
|
audience?: string | string[];
|
|
@@ -15,10 +18,22 @@ export interface JwtVerifierOptions {
|
|
|
15
18
|
* than an aud/resource claim.
|
|
16
19
|
*/
|
|
17
20
|
issuerBoundAccessTokens?: boolean;
|
|
21
|
+
/** Permitted JWS algorithms. Defaults to whatever the JWKS advertises. */
|
|
18
22
|
algorithms?: readonly string[];
|
|
23
|
+
/** Symmetric key material, for providers that sign without a JWKS. */
|
|
19
24
|
key?: Uint8Array;
|
|
20
25
|
}
|
|
21
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Creates a verifier that rejects JWTs with invalid signatures or required claims.
|
|
28
|
+
*
|
|
29
|
+
* Use this when implementing a custom OAuth provider with
|
|
30
|
+
* {@link oauthCustomProvider}, so a provider that issues standard JWTs does not
|
|
31
|
+
* have to reimplement signature, issuer, audience and expiry checking.
|
|
32
|
+
*
|
|
33
|
+
* @param options - Issuer, keys, and claims to enforce.
|
|
34
|
+
* @returns A verifier accepted anywhere an `OAuthTokenVerifier` is taken.
|
|
35
|
+
* @throws TypeError if `audience` is combined with `issuerBoundAccessTokens`.
|
|
36
|
+
*/
|
|
22
37
|
export declare function createJwtVerifier(options: JwtVerifierOptions): OAuthTokenVerifier;
|
|
23
38
|
/** Validates and canonicalizes an authorization-server URL before JWKS setup. */
|
|
24
39
|
export declare function normalizedProviderUrl(value: URL | string, name: string): URL;
|
package/dist/oauth/keycloak.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{booleanValue,createJwtVerifier,normalizedProviderUrl,normalizedStrings,
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{booleanValue,createJwtVerifier,invalidToken,isRecord,normalizedProviderUrl,normalizedStrings,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,recordValue,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthKeycloakProvider(options={}){let serverUrlValue=options.serverUrl??oauthEnvironmentValue("MCP_USE_OAUTH_KEYCLOAK_SERVER_URL"),realm=options.realm??oauthEnvironmentValue("MCP_USE_OAUTH_KEYCLOAK_REALM"),audience=oauthEnvironmentValue("MCP_USE_OAUTH_KEYCLOAK_AUDIENCE");if(serverUrlValue===void 0||realm===void 0)throw new Error("Keycloak serverUrl and realm are required.");if(typeof realm!="string"||realm.trim().length===0||/[/?#]/.test(realm))throw new TypeError("Keycloak realm is invalid");let resolvedOptions={...options,...options.resource===void 0&&audience!==void 0&&{resource:audience}},serverUrl=normalizedProviderUrl(serverUrlValue,"Keycloak serverUrl"),issuer=providerEndpoint(serverUrl,`realms/${encodeURIComponent(realm)}`).replace(/\/$/,"");return oauthCustomProvider({...resolvedOptions,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(issuer,"protocol/openid-connect/certs")),resource}),oauthMetadata:{issuer,authorization_endpoint:providerEndpoint(issuer,"protocol/openid-connect/auth"),token_endpoint:providerEndpoint(issuer,"protocol/openid-connect/token"),registration_endpoint:providerEndpoint(issuer,"clients-registrations/openid-connect"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"]},mapAuthInfo:mapUser})}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub");if(id===void 0)throw invalidToken("Missing Keycloak subject");let realmAccess=recordValue(payload,"realm_access"),resourceAccess=recordValue(payload,"resource_access");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("name",stringValue(payload,"name")),...optional("preferredUsername",stringValue(payload,"preferred_username")),...optional("givenName",stringValue(payload,"given_name")),...optional("familyName",stringValue(payload,"family_name")),...optional("emailVerified",booleanValue(payload,"email_verified")),roles:realmAccess===void 0?[]:normalizedStrings(realmAccess.roles),...realmAccess!==void 0&&{realmAccess},...resourceAccess!==void 0&&{resourceAccess}},payload,permissions:resourcePermissions(resourceAccess)}}function optional(key,value){return value===void 0?{}:{[key]:value}}function resourcePermissions(resourceAccess){return resourceAccess===void 0?[]:Object.entries(resourceAccess).flatMap(([resource,value])=>isRecord(value)?normalizedStrings(value.roles).map(role=>`${resource}:${role}`):[])}export{oauthKeycloakProvider};
|
package/dist/oauth/supabase.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{createJwtVerifier,invalidToken,isRecord,normalizedProviderUrl,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,recordValue,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthSupabaseProvider(options={}){let projectId=options.projectId??oauthEnvironmentValue("MCP_USE_OAUTH_SUPABASE_PROJECT_ID"),configuredSupabaseUrl=options.supabaseUrl??oauthEnvironmentValue("MCP_USE_OAUTH_SUPABASE_URL"),jwtSecret=options.jwtSecret??oauthEnvironmentValue("MCP_USE_OAUTH_SUPABASE_JWT_SECRET"),resolvedOptions={...options,...projectId!==void 0&&{projectId},...configuredSupabaseUrl!==void 0&&{supabaseUrl:configuredSupabaseUrl},...jwtSecret!==void 0&&{jwtSecret}},supabaseUrl=resolveSupabaseUrl(resolvedOptions),issuer=providerEndpoint(supabaseUrl,"auth/v1").replace(/\/$/,""),secret=resolvedOptions.jwtSecret,audience=resolvedOptions.audience??"authenticated";if(typeof audience!="string"||audience.trim().length===0)throw new TypeError("Supabase audience must be non-empty");if(secret!==void 0&&new TextEncoder().encode(secret).length<32)throw new TypeError("Supabase jwtSecret must be at least 32 bytes");return oauthCustomProvider({...resolvedOptions,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(supabaseUrl,"auth/v1/.well-known/jwks.json")),...secret!==void 0?{key:new TextEncoder().encode(secret),algorithms:["HS256"]}:{algorithms:["ES256"]},resource,audience}),oauthMetadata:{issuer,authorization_endpoint:providerEndpoint(supabaseUrl,"auth/v1/oauth/authorize"),token_endpoint:providerEndpoint(supabaseUrl,"auth/v1/oauth/token"),registration_endpoint:providerEndpoint(supabaseUrl,"auth/v1/oauth/clients/register"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"]},mapAuthInfo:mapUser})}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub")??requiredString(payload,"user_id");if(id===void 0)throw invalidToken("Missing Supabase subject");let userMetadata=recordValue(payload,"user_metadata")??{},aal=stringValue(payload,"aal");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("name",stringValue(userMetadata,"name")),...optional("fullName",stringValue(userMetadata,"full_name")),...optional("username",stringValue(userMetadata,"username")),...optional("avatarUrl",stringValue(userMetadata,"avatar_url")),...optional("role",stringValue(payload,"role")),...optional("aal",aal),amr:supabaseAmr(payload.amr),...optional("sessionId",stringValue(payload,"session_id"))},payload,permissions:aal===void 0?[]:[`aal:${aal}`]}}function optional(key,value){return value===void 0?{}:{[key]:value}}function resolveSupabaseUrl(options){if(options.supabaseUrl!==void 0)return normalizedProviderUrl(options.supabaseUrl,"supabaseUrl");if(options.projectId===void 0||!/^[a-z0-9-]+$/i.test(options.projectId))throw new TypeError("Supabase requires projectId or supabaseUrl");return new URL(`https://${options.projectId}.supabase.co`)}function supabaseAmr(value){return Array.isArray(value)?value.flatMap(item=>{if(!isRecord(item))return[];let method=item.method,timestamp=item.timestamp;return typeof method!="string"||method.length===0?[]:timestamp!==void 0&&(typeof timestamp!="number"||!Number.isFinite(timestamp))?[]:[timestamp===void 0?{method}:{method,timestamp}]}):[]}export{oauthSupabaseProvider};
|
package/dist/oauth/workos.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{booleanValue,createJwtVerifier,normalizedProviderUrl,normalizedStrings,
|
|
1
|
+
import{oauthEnvironmentValue}from"../chunk-DOOKCABV.js";import{booleanValue,createJwtVerifier,invalidToken,normalizedProviderUrl,normalizedStrings,oauthCustomProvider,payloadFromAuthInfo,providerEndpoint,requiredString,stringValue}from"../chunk-3FHYLNH3.js";function oauthWorkOSProvider(options={}){let subdomain=options.subdomain??oauthEnvironmentValue("MCP_USE_OAUTH_WORKOS_SUBDOMAIN");if(subdomain===void 0)throw new Error("WorkOS subdomain is required.");let issuer=workosIssuer(subdomain);return oauthCustomProvider({...options,createTokenVerifier:resource=>createJwtVerifier({issuer,jwksUrl:new URL(providerEndpoint(issuer,"oauth2/jwks")),resource}),oauthMetadata:{issuer,authorization_endpoint:providerEndpoint(issuer,"oauth2/authorize"),token_endpoint:providerEndpoint(issuer,"oauth2/token"),registration_endpoint:providerEndpoint(issuer,"oauth2/register"),response_types_supported:["code"],grant_types_supported:["authorization_code","refresh_token"],code_challenge_methods_supported:["S256"]},mapAuthInfo:mapUser})}function mapUser(authInfo){let payload=payloadFromAuthInfo(authInfo),id=requiredString(payload,"sub");if(id===void 0)throw invalidToken("Missing WorkOS subject");return{user:{id,...optional("email",stringValue(payload,"email")),...optional("emailVerified",booleanValue(payload,"email_verified")),...optional("name",stringValue(payload,"name")),...optional("preferredUsername",stringValue(payload,"preferred_username")),...optional("firstName",stringValue(payload,"first_name")),...optional("lastName",stringValue(payload,"last_name")),...optional("picture",stringValue(payload,"picture")),roles:normalizedStrings(payload.roles),...optional("organizationId",stringValue(payload,"org_id")),...optional("sessionId",stringValue(payload,"sid"))},payload,permissions:normalizedStrings(payload.permissions)}}function optional(key,value){return value===void 0?{}:{[key]:value}}function workosIssuer(value){if(typeof value!="string"||value.trim().length===0)throw new TypeError("WorkOS subdomain is required");let url=normalizedProviderUrl(value,"WorkOS subdomain");if(url.pathname!=="/")throw new TypeError("WorkOS subdomain must be a hostname or HTTPS origin");return url.href.replace(/\/$/,"")}export{oauthWorkOSProvider};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-use",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"description": "MCP framework and CLI built on the official v2 SDK",
|
|
6
6
|
"author": "mcp-use, Inc.",
|
|
7
7
|
"license": "MIT",
|
|
@@ -110,11 +110,11 @@
|
|
|
110
110
|
"@modelcontextprotocol/server": "2.0.0",
|
|
111
111
|
"hono": "^4.12.34",
|
|
112
112
|
"jose": "^6.1.3",
|
|
113
|
-
"@mcp-use/
|
|
114
|
-
"@mcp-use/
|
|
113
|
+
"@mcp-use/inspector": "20.2.0",
|
|
114
|
+
"@mcp-use/cli": "4.1.2"
|
|
115
115
|
},
|
|
116
116
|
"peerDependencies": {
|
|
117
|
-
"@mcp-use/client": "^2.0.1 || ^2.1.0 || ^2.1.1 || ^2.1.2
|
|
117
|
+
"@mcp-use/client": "^2.0.1 || ^2.1.0 || ^2.1.1 || ^2.1.2",
|
|
118
118
|
"react": "^19.0.0",
|
|
119
119
|
"react-dom": "^19.0.0"
|
|
120
120
|
},
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
"typescript": "^7.0.2",
|
|
142
142
|
"vitest": "^4.1.9",
|
|
143
143
|
"zod": "^4.4.3",
|
|
144
|
-
"@mcp-use/client": "2.1.2
|
|
144
|
+
"@mcp-use/client": "2.1.2"
|
|
145
145
|
},
|
|
146
146
|
"publishConfig": {
|
|
147
147
|
"access": "public"
|
package/dist/chunk-6P4FCE42.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{invalidToken,isLocalhost,isRecord}from"./chunk-IS7FKXFR.js";function oauthEnvironmentValue(name){return process.env[name]}import{OAuthError}from"@modelcontextprotocol/server";import{createRemoteJWKSet,jwtVerify,errors}from"jose";function createJwtVerifier(options){let key=options.key??createRemoteJWKSet(options.jwksUrl),configuredResource=canonicalUrl(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 OAuthError?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 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{}}export{oauthEnvironmentValue,createJwtVerifier,normalizedProviderUrl,providerEndpoint,payloadFromAuthInfo,requiredString,stringValue,booleanValue,recordValue,normalizedStrings};
|
package/dist/chunk-IS7FKXFR.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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}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(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.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,isLocalhost,invalidToken,resolveConfiguredOAuthResource,resolveLocalOAuthResource,wrapOAuthTokenVerifier,getOAuthProviderOptions,oauthCustomProvider};
|