import { o as logger } from "./logger-CtGm8dC_.js";
import { t as fetchWithProxy } from "./fetch-AchwhzAC.js";
import { rt as renderVarsInObject } from "./util-C2QcRmEx.js";
//#region src/util/oauth.ts
/**
* Buffer time before token expiry to trigger proactive refresh (60 seconds)
*/
const TOKEN_REFRESH_BUFFER_MS = 6e4;
/**
* Fetch an OAuth token from a token endpoint.
* Handles both client_credentials and password grant types.
*
* @param config - OAuth configuration with rendered/resolved values
* @returns Token and expiration timestamp
*/
async function fetchOAuthToken(config) {
	const now = Date.now();
	logger.debug("[OAuth] Fetching new token");
	const tokenRequestBody = new URLSearchParams();
	tokenRequestBody.append("grant_type", config.grantType);
	if (config.clientId) tokenRequestBody.append("client_id", config.clientId);
	if (config.clientSecret) tokenRequestBody.append("client_secret", config.clientSecret);
	if (config.grantType === "password") {
		if (config.username) tokenRequestBody.append("username", config.username);
		if (config.password) tokenRequestBody.append("password", config.password);
	}
	if (config.scopes && config.scopes.length > 0) tokenRequestBody.append("scope", config.scopes.join(" "));
	const response = await fetchWithProxy(config.tokenUrl, {
		method: "POST",
		headers: { "Content-Type": "application/x-www-form-urlencoded" },
		body: tokenRequestBody.toString()
	});
	if (!response.ok) {
		const errorText = await response.text();
		throw new Error(`OAuth token request failed with status ${response.status} ${response.statusText}: ${errorText}`);
	}
	const tokenData = await response.json();
	if (!tokenData.access_token) throw new Error("OAuth token response missing access_token");
	const expiresAt = now + (tokenData.expires_in || 3600) * 1e3;
	logger.debug("[OAuth] Successfully fetched token");
	return {
		accessToken: tokenData.access_token,
		expiresAt
	};
}
//#endregion
//#region src/providers/mcp/util.ts
function isMcpToolNameFilter(tools) {
	const isPlainToolName = (tool) => typeof tool === "string" && !tool.startsWith("file://");
	return isPlainToolName(tools) || Array.isArray(tools) && tools.every((tool) => isPlainToolName(tool));
}
/**
* Returns true when an MCP tool call surfaced a failure: either the SDK call
* threw (`error` is set) or the tool resolved with a protocol-level
* `isError: true` result.
*/
function isMcpErrorResult(result) {
	return Boolean(result.error || result.isError);
}
/**
* Resolve a human-readable message for a failed MCP tool call. Prefers the
* thrown-error message, falls back to the tool's own error content, and finally
* to a generic message for tools that signal `isError` without any detail.
*/
function getMcpErrorMessage(result) {
	return result.error || result.content || "Tool returned an error result";
}
/**
* Render environment variables in server config auth fields.
* Supports {{VAR_NAME}} syntax for variable substitution.
*/
function renderAuthVars(server, vars) {
	if (!server.auth) return server;
	const renderVars = vars || process.env;
	return {
		...server,
		auth: renderVarsInObject(server.auth, renderVars)
	};
}
const oauthTokenCache = /* @__PURE__ */ new Map();
/**
* Get the cache key for an OAuth config
*/
function getOAuthCacheKey(auth, tokenUrl) {
	return `${tokenUrl}:${auth.grantType}:${"clientId" in auth ? auth.clientId : ""}:${"username" in auth ? auth.username : ""}:${auth.scopes?.join(" ") ?? ""}`;
}
const tokenEndpointCache = /* @__PURE__ */ new Map();
function isValidTokenEndpoint(tokenEndpoint) {
	try {
		const parsedUrl = new URL(tokenEndpoint);
		return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
	} catch {
		return false;
	}
}
/**
* Discover the OAuth token endpoint from the server's well-known metadata.
* Follows RFC 8414 OAuth 2.0 Authorization Server Metadata.
* Only requires token_endpoint from the response (unlike SDK which requires authorization_endpoint).
*/
async function discoverTokenEndpoint(serverUrl) {
	const cached = tokenEndpointCache.get(serverUrl);
	if (cached) {
		logger.debug(`[MCP Auth] Using cached token endpoint for ${serverUrl}`);
		return cached;
	}
	const url = new URL(serverUrl);
	const baseUrl = `${url.protocol}//${url.host}`;
	const discoveryUrls = [];
	if (url.pathname && url.pathname !== "/") {
		discoveryUrls.push(`${baseUrl}${url.pathname}/.well-known/oauth-authorization-server`);
		discoveryUrls.push(`${baseUrl}/.well-known/oauth-authorization-server${url.pathname}`);
	}
	discoveryUrls.push(`${baseUrl}/.well-known/oauth-authorization-server`);
	for (const discoveryUrl of discoveryUrls) try {
		logger.debug(`[MCP Auth] Trying OAuth discovery at ${discoveryUrl}`);
		const response = await fetchWithProxy(discoveryUrl);
		if (!response.ok) {
			logger.debug(`[MCP Auth] Discovery failed at ${discoveryUrl}: ${response.status}`);
			continue;
		}
		const metadata = await response.json();
		if (metadata.token_endpoint && isValidTokenEndpoint(metadata.token_endpoint)) {
			logger.debug(`[MCP Auth] Discovered token endpoint: ${metadata.token_endpoint}`);
			tokenEndpointCache.set(serverUrl, metadata.token_endpoint);
			return metadata.token_endpoint;
		}
		logger.debug(`[MCP Auth] No valid token_endpoint in metadata from ${discoveryUrl}`);
	} catch (error) {
		logger.debug(`[MCP Auth] Error fetching ${discoveryUrl}: ${error}`);
	}
	throw new Error(`Failed to discover OAuth token endpoint for ${serverUrl}. Please configure tokenUrl explicitly in the auth config.`);
}
/**
* Get OAuth token with expiration info, fetching a new one if needed.
* If tokenUrl is not configured, attempts OAuth discovery to find the token endpoint.
* Caches tokens and returns cached version if still valid.
*/
async function getOAuthTokenWithExpiry(auth, serverUrl) {
	let tokenUrl = auth.tokenUrl;
	if (!tokenUrl) {
		if (!serverUrl) throw new Error("Either tokenUrl or serverUrl is required for OAuth token fetching");
		tokenUrl = await discoverTokenEndpoint(serverUrl);
	}
	const cacheKey = getOAuthCacheKey(auth, tokenUrl);
	const cached = oauthTokenCache.get(cacheKey);
	if (cached && Date.now() + 6e4 < cached.expiresAt) {
		logger.debug("[MCP Auth] Using cached OAuth token");
		return {
			accessToken: cached.accessToken,
			expiresAt: cached.expiresAt
		};
	}
	const result = await fetchOAuthToken({
		tokenUrl,
		grantType: auth.grantType,
		clientId: auth.clientId,
		clientSecret: auth.clientSecret,
		username: "username" in auth ? auth.username : void 0,
		password: "password" in auth ? auth.password : void 0,
		scopes: auth.scopes
	});
	oauthTokenCache.set(cacheKey, {
		accessToken: result.accessToken,
		expiresAt: result.expiresAt
	});
	logger.debug("[MCP Auth] Cached OAuth token");
	return result;
}
/**
* Get OAuth token, fetching a new one if needed.
* Requires tokenUrl to be configured - throws if not provided.
*/
async function getOAuthToken(auth) {
	return (await getOAuthTokenWithExpiry(auth)).accessToken;
}
/**
* Get authentication headers for an MCP server configuration.
* Returns headers for bearer, basic, and api_key (header placement) auth types.
* For OAuth, use getOAuthToken() first then pass the token.
* For api_key with query placement, use getAuthQueryParams() instead.
*/
function getAuthHeaders(server, oauthToken) {
	if (!server.auth) return {};
	switch (server.auth.type) {
		case "bearer":
			if (!server.auth.token) return {};
			return { Authorization: `Bearer ${server.auth.token}` };
		case "basic": return { Authorization: `Basic ${Buffer.from(`${server.auth.username}:${server.auth.password}`).toString("base64")}` };
		case "api_key": {
			const apiKeyAuth = server.auth;
			const value = apiKeyAuth.value || apiKeyAuth.api_key;
			if (!value) return {};
			if ((apiKeyAuth.placement || "header") === "header") return { [apiKeyAuth.keyName || "X-API-Key"]: value };
			return {};
		}
		case "oauth":
			if (oauthToken) return { Authorization: `Bearer ${oauthToken}` };
			logger.warn("[MCP Auth] OAuth auth configured but no token provided");
			return {};
		default: return {};
	}
}
/**
* Get authentication query parameters for api_key auth with query placement.
* Returns an object with key-value pairs to be added to the URL.
*/
function getAuthQueryParams(server) {
	if (!server.auth || server.auth.type !== "api_key") return {};
	const apiKeyAuth = server.auth;
	const value = apiKeyAuth.value || apiKeyAuth.api_key;
	if (!value) return {};
	if ((apiKeyAuth.placement || "header") !== "query") return {};
	return { [apiKeyAuth.keyName || "X-API-Key"]: value };
}
/**
* Apply query parameters to a URL
*/
function applyQueryParams(url, params) {
	if (Object.keys(params).length === 0) return url;
	const urlObj = new URL(url);
	for (const [key, value] of Object.entries(params)) urlObj.searchParams.append(key, value);
	return urlObj.toString();
}
/**
* Check if auth requires async token fetching (OAuth)
*/
function requiresAsyncAuth(server) {
	return server.auth?.type === "oauth";
}
//#endregion
export { getOAuthToken as a, isMcpToolNameFilter as c, TOKEN_REFRESH_BUFFER_MS as d, getMcpErrorMessage as i, renderAuthVars as l, getAuthHeaders as n, getOAuthTokenWithExpiry as o, getAuthQueryParams as r, isMcpErrorResult as s, applyQueryParams as t, requiresAsyncAuth as u };

//# sourceMappingURL=util-C1iIGfEN.js.map