alibaba/arthas · error · McpError

Resource with URI ' ' already exists

Error message

Resource with URI '${resourceUri}' already exists

What it means

McpNettyServer.addResource throws McpError (wrapped in CompletionException) when a resource with the same URI is already registered. Resources are stored in a map keyed by Resource.getUri(), and putIfAbsent returning a non-null value means the URI is taken; duplicate URIs would otherwise overwrite each other.

Solutions

  1. Call removeResource(uri) before addResource when refreshing.
  2. Check the existing resources map for the URI before adding.
  3. Ensure each resource exposes a unique URI.

Example fix

// before
server.addResource(spec); // uri 'jfr://file/123' already exists

// after
server.removeResource("jfr://file/123")
    .thenRun(() -> server.addResource(spec));
Defensive patterns

Strategy: validation

Validate before calling

String uri = spec.getResource().getUri();
boolean exists = server.getResources().stream()
    .anyMatch(r -> r.getResource().getUri().equals(uri));
if (exists) server.removeResource(uri).join();
server.addResource(spec).join();

Try / catch

try { server.addResource(spec).join(); }
catch (CompletionException e) {
  if (e.getCause() instanceof io.modelcontextprotocol.spec.McpError && e.getCause().getMessage().contains("already exists")) { server.removeResource(uri).thenRun(() -> server.addResource(spec)).join(); }
  else throw e;
}

Prevention

When it happens

Trigger: Calling addResource twice with resources whose getUri() is identical; hot reload without removeResource first; two providers contributing the same resource URI.

Common situations: Dynamic resource registration on reconnect; resource discovery registering the same URI across modules; URI normalization differences leading to an unexpected exact collision.

Related errors


AI-assisted analysis of alibaba/arthas@21cf2e9ba5 (2026-08-14). Data as JSON: /api/errors/15910fcf447feb54. Report an issue: GitHub.

Appendix: source

Thrown at arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/protocol/server/McpNettyServer.java:435

	// Resource Management
	// ---------------------------------------

	public CompletableFuture<Void> addResource(McpServerFeatures.ResourceSpecification resourceSpecification) {
		if (resourceSpecification == null || resourceSpecification.getResource() == null) {
			CompletableFuture<Void> future = new CompletableFuture<>();
			future.completeExceptionally(new McpError("Resource must not be null"));
			return future;
		}
		if (this.serverCapabilities.getResources() == null) {
			CompletableFuture<Void> future = new CompletableFuture<>();
			future.completeExceptionally(new McpError("Server must be configured with resource capabilities"));
			return future;
		}

		return CompletableFuture.supplyAsync(() -> {
			if (this.resources.putIfAbsent(resourceSpecification.getResource().getUri(),
					resourceSpecification) != null) {
				throw new CompletionException(new McpError(
						"Resource with URI '" + resourceSpecification.getResource().getUri() + "' already exists"));
			}
			logger.debug("Added resource handler: {}", resourceSpecification.getResource().getUri());
			return null;
		}).thenCompose(ignored -> {
			if (this.serverCapabilities.getResources().getListChanged()) {
				return notifyResourcesListChanged();
			}
			return CompletableFuture.completedFuture(null);
		}).exceptionally(ex -> {
			Throwable cause = ex instanceof CompletionException ? ex.getCause() : ex;
			logger.error("Error while adding resource '{}'", resourceSpecification.getResource().getUri(), cause);
			throw new CompletionException(cause);
		});
	}

	public CompletableFuture<Void> removeResource(String resourceUri) {
		if (resourceUri == null) {

View on GitHub (pinned to 21cf2e9ba5)