fix: handle invalid mcp urls (#25019)
This commit is contained in:
@@ -114,6 +114,11 @@ function isMcpConfigured(entry: McpEntry): entry is ConfigMCP.Info {
|
|||||||
|
|
||||||
const sanitize = (s: string) => s.replace(/[^a-zA-Z0-9_-]/g, "_")
|
const sanitize = (s: string) => s.replace(/[^a-zA-Z0-9_-]/g, "_")
|
||||||
|
|
||||||
|
function remoteURL(key: string, value: string) {
|
||||||
|
if (URL.canParse(value)) return new URL(value)
|
||||||
|
log.warn("invalid remote mcp url", { key })
|
||||||
|
}
|
||||||
|
|
||||||
// Convert MCP tool definition to AI SDK Tool type
|
// Convert MCP tool definition to AI SDK Tool type
|
||||||
function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient, timeout?: number): Tool {
|
function convertMcpTool(mcpTool: MCPToolDef, client: MCPClient, timeout?: number): Tool {
|
||||||
const inputSchema = mcpTool.inputSchema
|
const inputSchema = mcpTool.inputSchema
|
||||||
@@ -267,6 +272,13 @@ export const layer = Layer.effect(
|
|||||||
) {
|
) {
|
||||||
const oauthDisabled = mcp.oauth === false
|
const oauthDisabled = mcp.oauth === false
|
||||||
const oauthConfig = typeof mcp.oauth === "object" ? mcp.oauth : undefined
|
const oauthConfig = typeof mcp.oauth === "object" ? mcp.oauth : undefined
|
||||||
|
const url = remoteURL(key, mcp.url)
|
||||||
|
if (!url) {
|
||||||
|
return {
|
||||||
|
client: undefined as MCPClient | undefined,
|
||||||
|
status: { status: "failed" as const, error: `Invalid MCP URL for "${key}"` },
|
||||||
|
}
|
||||||
|
}
|
||||||
let authProvider: McpOAuthProvider | undefined
|
let authProvider: McpOAuthProvider | undefined
|
||||||
|
|
||||||
if (!oauthDisabled) {
|
if (!oauthDisabled) {
|
||||||
@@ -291,14 +303,14 @@ export const layer = Layer.effect(
|
|||||||
const transports: Array<{ name: string; transport: TransportWithAuth }> = [
|
const transports: Array<{ name: string; transport: TransportWithAuth }> = [
|
||||||
{
|
{
|
||||||
name: "StreamableHTTP",
|
name: "StreamableHTTP",
|
||||||
transport: new StreamableHTTPClientTransport(new URL(mcp.url), {
|
transport: new StreamableHTTPClientTransport(url, {
|
||||||
authProvider,
|
authProvider,
|
||||||
requestInit: mcp.headers ? { headers: mcp.headers } : undefined,
|
requestInit: mcp.headers ? { headers: mcp.headers } : undefined,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "SSE",
|
name: "SSE",
|
||||||
transport: new SSEClientTransport(new URL(mcp.url), {
|
transport: new SSEClientTransport(url, {
|
||||||
authProvider,
|
authProvider,
|
||||||
requestInit: mcp.headers ? { headers: mcp.headers } : undefined,
|
requestInit: mcp.headers ? { headers: mcp.headers } : undefined,
|
||||||
}),
|
}),
|
||||||
@@ -722,6 +734,8 @@ export const layer = Layer.effect(
|
|||||||
if (!mcpConfig) throw new Error(`MCP server ${mcpName} not found or disabled`)
|
if (!mcpConfig) throw new Error(`MCP server ${mcpName} not found or disabled`)
|
||||||
if (mcpConfig.type !== "remote") throw new Error(`MCP server ${mcpName} is not a remote server`)
|
if (mcpConfig.type !== "remote") throw new Error(`MCP server ${mcpName} is not a remote server`)
|
||||||
if (mcpConfig.oauth === false) throw new Error(`MCP server ${mcpName} has OAuth explicitly disabled`)
|
if (mcpConfig.oauth === false) throw new Error(`MCP server ${mcpName} has OAuth explicitly disabled`)
|
||||||
|
const url = remoteURL(mcpName, mcpConfig.url)
|
||||||
|
if (!url) throw new Error(`Invalid MCP URL for "${mcpName}"`)
|
||||||
|
|
||||||
// OAuth config is optional - if not provided, we'll use auto-discovery
|
// OAuth config is optional - if not provided, we'll use auto-discovery
|
||||||
const oauthConfig = typeof mcpConfig.oauth === "object" ? mcpConfig.oauth : undefined
|
const oauthConfig = typeof mcpConfig.oauth === "object" ? mcpConfig.oauth : undefined
|
||||||
@@ -751,7 +765,7 @@ export const layer = Layer.effect(
|
|||||||
auth,
|
auth,
|
||||||
)
|
)
|
||||||
|
|
||||||
const transport = new StreamableHTTPClientTransport(new URL(mcpConfig.url), { authProvider })
|
const transport = new StreamableHTTPClientTransport(url, { authProvider })
|
||||||
|
|
||||||
return yield* Effect.tryPromise({
|
return yield* Effect.tryPromise({
|
||||||
try: () => {
|
try: () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user