fix: duplicate any listed resource URI, not only a registered one

Copilot on #2281: the option's contract said an unregistered URI is ignored,
but `withDuplicateResources` runs on the assembled list, which also carries
whatever a resource template's `list` callback contributed — so a
template-listed URI was duplicated in contradiction of its own doc.

Broadened rather than restricted, because scoping it to `registeredResources`
would leave half the surface unreproducible: both kinds of entry land in the
same Resources sidebar list and collide on the same React key. The contract now
says so on `ServerConfig.duplicateResourceUris` and on the config-file mirror,
and an integration case covers a template-listed URI — it fails if the override
is narrowed to `state.registeredResources`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018yVgAJz4wpkS4mkGk7DQnp
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-06 20:15:20 -04:00
commit 339c5f4e27

View file

@ -8,6 +8,7 @@ import {
type TestServerHttp,
createTestServerInfo,
createNumberedResources,
createFileResourceTemplate,
loadConfig,
resolveConfig,
} from "@modelcontextprotocol/inspector-test-server";
@ -107,6 +108,28 @@ describe("duplicate resource URIs in resources/list (#2206)", () => {
]);
});
// The option matches the assembled list, not `state.registeredResources`, so
// a URI a resource template contributed is duplicated too (Copilot). Both
// kinds land in the same Resources sidebar list and collide on the same React
// key, so the fixture has to be able to reproduce either.
it("duplicates a URI a resource template listed", async () => {
const started = await start({
resources: [],
resourceTemplates: [
createFileResourceTemplate(undefined, () => ["file:///notes.md"]),
],
duplicateResourceUris: ["file:///notes.md"],
});
const connected = await connect(started.url);
const { resources } = await connected.listAllResources();
expect(resources.map((r) => r.uri)).toEqual([
"file:///notes.md",
"file:///notes.md",
]);
expect(resources.at(-1)?.title).toBe("file:///notes.md (duplicate)");
});
it("ignores a URI that is not registered", async () => {
const started = await start({
duplicateResourceUris: ["test://not_a_resource"],