Skip to content

Commit 3e1be88

Browse files
dotsetgregclaude
andcommitted
fix(everything): allow re-registration of session resources
When a tool like `gzip-file-as-resource` is called multiple times with the same output name (especially the default `README.md.gz`), the server would throw "Resource already registered" because the SDK doesn't allow registering duplicate URIs. This fix: - Tracks registered resources by URI in a module-level Map - Before registering a new resource, checks if the URI already exists - If it does, removes the old resource using the SDK's `remove()` method - Then registers the new resource with fresh content This allows tools to be called repeatedly with the same parameters without errors, which is important for LLM agents that may retry tool calls. Found using Bellwether (https://bellwether.sh), an MCP server validation tool. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 549dd02 commit 3e1be88

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

src/everything/resources/session.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1+
import { McpServer, RegisteredResource } from "@modelcontextprotocol/sdk/server/mcp.js";
22
import { Resource, ResourceLink } from "@modelcontextprotocol/sdk/types.js";
33

4+
/**
5+
* Tracks registered session resources by URI to allow updating/removing on re-registration.
6+
* This prevents "Resource already registered" errors when a tool creates a resource
7+
* with the same URI multiple times during a session.
8+
*/
9+
const registeredResources = new Map<string, RegisteredResource>();
10+
411
/**
512
* Generates a session-scoped resource URI string based on the provided resource name.
613
*
@@ -47,17 +54,27 @@ export const registerSessionResource = (
4754
blob: payload,
4855
};
4956

57+
// Check if a resource with this URI is already registered and remove it
58+
const existingResource = registeredResources.get(uri);
59+
if (existingResource) {
60+
existingResource.remove();
61+
registeredResources.delete(uri);
62+
}
63+
5064
// Register file resource
51-
server.registerResource(
65+
const registeredResource = server.registerResource(
5266
name,
5367
uri,
5468
{ mimeType, description, title, annotations, icons, _meta },
55-
async (uri) => {
69+
async () => {
5670
return {
5771
contents: [resourceContent],
5872
};
5973
}
6074
);
6175

76+
// Track the registered resource for potential future removal
77+
registeredResources.set(uri, registeredResource);
78+
6279
return { type: "resource_link", ...resource };
6380
};

0 commit comments

Comments
 (0)