microsoft/aspire · error · InvalidOperationException

MCP server configuration

Error message

MCP server configuration '{builder.Resource.Name}' has connector routes and cannot be marked as existing.

What it means

AsExisting marks an MCP server configuration resource as a read-only reference to pre-existing infrastructure. A configuration that already declares connector routes cannot be converted, because existing references must not carry modeled child connectors that would never be deployed. The library validates this invariant and throws before mutating IsExisting.

Solutions

  1. Remove the WithConnector call(s) before calling AsExisting.
  2. Create a separate, unconfigured builder (e.g. re-add the config) and mark that one AsExisting.
  3. If connectors must be modeled, keep the config in create mode instead of existing mode.

Example fix

// before
var mcp = ns.AddMcpServerConfig("tools", options).WithConnector("conn", connection, connectorOptions);
mcp.AsExisting(); // throws

// after
var mcp = ns.AddMcpServerConfig("tools", options); // no connectors
mcp.AsExisting();
Defensive patterns

Strategy: validation

Validate before calling

if (mcp.Resource.Connectors.Count == 0)
{
    mcp.AsExisting();
}

Try / catch

try
{
    mcp.AsExisting();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("has connector routes"))
{
    // strip WithConnector calls or keep the config in create mode
}

Prevention

When it happens

Trigger: Calling builder.AsExisting() on an AzureConnectorNamespaceMcpServerConfigResource after one or more WithConnector calls have populated Resource.Connectors.

Common situations: Flipping a fully-modeled MCP config to existing mode to avoid deployment, e.g. pointing at an already-provisioned config while keeping its WithConnector wiring.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/294a37311b9e3bec. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Azure.ConnectorNamespace/AzureConnectorNamespaceExtensions.cs:501

        config.Annotations.Add(ManifestPublishingCallbackAnnotation.Ignore);
        builder.Resource.McpServerConfigs.Add(config);
        return builder.ApplicationBuilder.AddResource(config);
    }

    /// <summary>
    /// Marks a managed MCP server configuration as an existing Azure resource.
    /// </summary>
    /// <param name="builder">The MCP server configuration resource builder.</param>
    /// <returns>The resource builder.</returns>
    /// <ats-returns>The resource builder.</ats-returns>
    [AspireExport("asExistingConnectorNamespaceMcpServerConfig", MethodName = "asExisting")]
    public static IResourceBuilder<AzureConnectorNamespaceMcpServerConfigResource> AsExisting(
        this IResourceBuilder<AzureConnectorNamespaceMcpServerConfigResource> builder)
    {
        ArgumentNullException.ThrowIfNull(builder);
        if (builder.Resource.Connectors.Count > 0)
        {
            throw new InvalidOperationException(
                $"MCP server configuration '{builder.Resource.Name}' has connector routes and cannot be marked as existing.");
        }

        if (!string.IsNullOrWhiteSpace(builder.Resource.Description))
        {
            throw new InvalidOperationException(
                $"MCP server configuration '{builder.Resource.Name}' configures a description and cannot be marked as existing.");
        }

        if (builder.Resource.AccessPolicies.Count > 0)
        {
            throw new InvalidOperationException(
                $"MCP server configuration '{builder.Resource.Name}' configures access policies and cannot be marked as existing.");
        }

        builder.Resource.IsExisting = true;
        return builder;
    }

View on GitHub (pinned to 25830f84bd)