feat(mcp): add resource template listing (#33546)

This commit is contained in:
Shoubhit Dash 2026-06-24 01:59:12 +05:30 committed by GitHub
commit c6cc13e183
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 151 additions and 8 deletions

View file

@ -17,6 +17,7 @@ interface MockClientState {
listToolsCalls: number
listPromptsCalls: number
listResourcesCalls: number
listResourceTemplatesCalls: number
getPromptTimeout?: number
readResourceTimeout?: number
requestCalls: number
@ -26,6 +27,7 @@ interface MockClientState {
listResourcesShouldFail: boolean
prompts: Array<{ name: string; description?: string }>
resources: Array<{ name: string; uri: string; description?: string }>
resourceTemplates: Array<{ name: string; uriTemplate: string; description?: string }>
toolPages: Record<
string,
{
@ -38,6 +40,10 @@ interface MockClientState {
string,
{ resources: Array<{ name: string; uri: string; description?: string }>; nextCursor?: string }
>
resourceTemplatePages: Record<
string,
{ resourceTemplates: Array<{ name: string; uriTemplate: string; description?: string }>; nextCursor?: string }
>
closed: boolean
clientOptions?: { capabilities?: { roots?: { listChanged?: boolean } } }
requestHandlers: Map<unknown, (...args: any[]) => Promise<any>>
@ -67,6 +73,7 @@ function getOrCreateClientState(name?: string): MockClientState {
listToolsCalls: 0,
listPromptsCalls: 0,
listResourcesCalls: 0,
listResourceTemplatesCalls: 0,
requestCalls: 0,
listToolsShouldFail: false,
listToolsError: "listTools failed",
@ -74,9 +81,11 @@ function getOrCreateClientState(name?: string): MockClientState {
listResourcesShouldFail: false,
prompts: [],
resources: [],
resourceTemplates: [],
toolPages: {},
promptPages: {},
resourcePages: {},
resourceTemplatePages: {},
closed: false,
requestHandlers: new Map(),
notificationHandlers: new Map(),
@ -224,6 +233,13 @@ void mock.module("@modelcontextprotocol/sdk/client/index.js", () => ({
return { resources: this._state?.resources ?? [] }
}
async listResourceTemplates(params?: { cursor?: string }) {
if (this._state) this._state.listResourceTemplatesCalls++
const page = this._state?.resourceTemplatePages[params === undefined ? "initial" : (params.cursor ?? "")]
if (page) return page
return { resourceTemplates: this._state?.resourceTemplates ?? [] }
}
async getPrompt(_params: unknown, options?: { timeout?: number }) {
if (this._state) this._state.getPromptTimeout = options?.timeout
return { messages: [] }
@ -353,6 +369,13 @@ it.instance(
initial: { resources: [{ name: "resource-one", uri: "test://one" }], nextCursor: "resources-2" },
"resources-2": { resources: [{ name: "resource-two", uri: "test://two" }] },
}
serverState.resourceTemplatePages = {
initial: {
resourceTemplates: [{ name: "template-one", uriTemplate: "test://one/{id}" }],
nextCursor: "resource-templates-2",
},
"resource-templates-2": { resourceTemplates: [{ name: "template-two", uriTemplate: "test://two/{id}" }] },
}
yield* mcp.add("paged-server", {
type: "local",
@ -362,9 +385,14 @@ it.instance(
expect(Object.keys(yield* mcp.tools())).toEqual(["mcp__paged-server__tool-one", "mcp__paged-server__tool-two"])
expect(Object.keys(yield* mcp.prompts())).toEqual(["paged-server:prompt-one", "paged-server:prompt-two"])
expect(Object.keys(yield* mcp.resources())).toEqual(["paged-server:test://one", "paged-server:test://two"])
expect(Object.keys(yield* mcp.resourceTemplates())).toEqual([
"paged-server:test://one/{id}",
"paged-server:test://two/{id}",
])
expect(serverState.listToolsCalls).toBe(2)
expect(serverState.listPromptsCalls).toBe(2)
expect(serverState.listResourcesCalls).toBe(2)
expect(serverState.listResourceTemplatesCalls).toBe(2)
}),
),
{ config: { mcp: {} } },

View file

@ -116,6 +116,7 @@ const mcp = Layer.succeed(
tools: () => Effect.succeed({}),
prompts: () => Effect.succeed({}),
resources: () => Effect.succeed({}),
resourceTemplates: () => Effect.succeed({}),
add: () => Effect.succeed({ status: { status: "disabled" as const } }),
connect: () => Effect.void,
disconnect: () => Effect.void,

View file

@ -40,6 +40,7 @@ const mcp = Layer.succeed(
tools: () => Effect.succeed({}),
prompts: () => Effect.succeed({}),
resources: () => Effect.succeed({}),
resourceTemplates: () => Effect.succeed({}),
add: () => Effect.succeed({ status: { status: "disabled" as const } }),
connect: () => Effect.void,
disconnect: () => Effect.void,