{"record":{"id":"9f189ad86f0f6c46","repo":"microsoft/aspire","slug":"endpoint-must-be-a-string-endpoint-reference-or-reference","errorCode":null,"errorMessage":"Endpoint must be a string, endpoint reference, or reference expression.","messagePattern":"Endpoint must be a string, endpoint reference, or reference expression\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxBuilderExtensions.cs","lineNumber":292,"sourceCode":"    /// <ats-returns>The resource builder.</ats-returns>\n    [AspireExport(\"withMcpTool\")]\n    internal static IResourceBuilder<FoundryToolboxResource> WithMcpToolForPolyglot(\n        this IResourceBuilder<FoundryToolboxResource> builder,\n        string name,\n        [AspireUnion(typeof(string), typeof(EndpointReference), typeof(ReferenceExpression))] object endpoint,\n        FoundryToolboxMcpToolOptions? options = null)\n    {\n        ArgumentNullException.ThrowIfNull(endpoint);\n\n        return endpoint switch\n        {\n            string endpointString => builder.WithMcpTool(name, endpointString, options),\n            EndpointReference endpointReference => builder.WithMcpTool(name, endpointReference, options),\n            // ReferenceExpression lets polyglot callers compose URLs (e.g. `refExpr\\`${endpoint}/mcp\\``)\n            // because the polyglot type system can't express a templated string built from a typed\n            // endpoint reference any other way.\n            ReferenceExpression endpointExpression => builder.WithMcpTool(name, endpointExpression, options),\n            _ => throw new ArgumentException(\"Endpoint must be a string, endpoint reference, or reference expression.\", nameof(endpoint))\n        };\n    }\n\n    /// <summary>\n    /// Adds an Azure AI Search tool definition to the Toolbox.\n    /// </summary>\n    /// <param name=\"builder\">The resource builder for the Toolbox.</param>\n    /// <param name=\"name\">The tool name.</param>\n    /// <param name=\"search\">The Azure AI Search resource backing the tool.</param>\n    /// <param name=\"indexName\">The search index name.</param>\n    /// <param name=\"description\">An optional description of the Azure AI Search tool.</param>\n    /// <returns>A reference to the <see cref=\"IResourceBuilder{T}\"/> for chaining.</returns>\n    /// <ats-returns>The resource builder.</ats-returns>\n    [AspireExport]\n    public static IResourceBuilder<FoundryToolboxResource> WithAISearchTool(\n        this IResourceBuilder<FoundryToolboxResource> builder,\n        string name,\n        IResourceBuilder<AzureSearchResource> search,","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxBuilderExtensions.cs#L274-L310","documentation":"Thrown by WithMcpToolForPolyglot when the endpoint argument is not one of the three supported shapes: string, EndpointReference, or ReferenceExpression. This polyglot-facing overload does a runtime type switch because non-.NET languages cannot express the overloads, and any other object type falls into the discard arm.","triggerScenarios":"Calling WithMcpToolForPolyglot with a Uri instance, a custom endpoint wrapper type, null boxed object, or any type other than string/EndpointReference/ReferenceExpression.","commonSituations":"Polyglot (Python/TypeScript) callers passing their language's native URL object which marshals to Uri or another unmapped type; refactoring code that previously used a different endpoint type; passing an endpoint built by an incompatible library version.","solutions":["Pass the endpoint as a plain string (absolute https URL).","Pass an EndpointReference from a project/container resource endpoint.","Compose dynamic URLs as a ReferenceExpression (e.g. ReferenceExpression.Create($\"{endpoint}/mcp\")).","Convert unsupported types to string before calling (e.g. uri.ToString())."],"exampleFix":"// before\nbuilder.WithMcpToolForPolyglot(\"search\", new Uri(\"https://host/mcp\"));\n// after\nbuilder.WithMcpToolForPolyglot(\"search\", \"https://host/mcp\");","handlingStrategy":"type-guard","validationCode":"if (endpoint is not (string or EndpointReference or ReferenceExpression))\n{\n    throw new ArgumentException($\"Unsupported endpoint type {endpoint.GetType().Name}; use string, EndpointReference, or ReferenceExpression.\", nameof(endpoint));\n}","typeGuard":"static bool IsValidEndpointShape(object? e) => e is string or EndpointReference or ReferenceExpression;","tryCatchPattern":"try\n{\n    builder.WithMcpToolForPolyglot(name, endpoint, options);\n}\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must be a string, endpoint reference\"))\n{\n    logger.LogError(ex, \"Unsupported endpoint type {Type}.\", endpoint?.GetType().Name);\n    throw;\n}","preventionTips":["Normalize endpoint values to string early in polyglot interop layers.","Convert Uri instances with .ToString()/AbsoluteUri before calling the polyglot overload.","Document the three accepted endpoint shapes at the interop boundary."],"tags":["validation","type-mismatch","polyglot","foundry-toolbox"],"backgroundTag":"type-mismatch","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}