Skip to content

Add ResourceTemplate and related attribute(s) for implementing resource template handlers #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Redth opened this issue Mar 23, 2025 · 15 comments · Fixed by #391
Closed
Assignees
Labels
enhancement New feature or request

Comments

@Redth
Copy link
Contributor

Redth commented Mar 23, 2025

Is your feature request related to a problem? Please describe.
Just like McpToolType and McpTool works today, it would be great to have a way to use attributes to define resource templates.

Describe the solution you'd like
Would be nice to annotate a type and method(s) to specify resource templates.

Resource URI Templates per the spec should conform to RFC6570. I'm not sure if this is what ASP.NET uses, but perhaps there is some way to leverage the route parsing logic within the SDK here?

[ResourceTemplateType]
public static class SampleResourceTemplates {

  // RFC6570 URI Template
  [ResourceTemplate("nuget://{packageId}/{version}")]
  public static byte[] NuGetPackage(string packageId, string version) {
    // Implement Handler logic to fetch and return
  }

}

// in Program.cs
builder.Services
  .AddMcpServer()
  .WithStdioServerTransport()
  .WithTools()
  .WithResourceTemplates();

Additional context
This probably should be considered with #72 so that methods could return actual types marked as ResourceType and have that handled automatically.

@Redth
Copy link
Contributor Author

Redth commented Mar 23, 2025

For template parsing and wiring up to method calls, we could potentially use something like https://github.com/corvus-dotnet/Corvus.UriTemplates which already implements the RFC and has some patterns for programmatically extracting a dictionary of parameters given a URI template and URI.

@PederHP
Copy link
Collaborator

PederHP commented Apr 1, 2025

I really like this approach. I think it could work fine for Resource as well. Isn't a Resource effectively just a ResourceTemplate with no parameters?

@IvanMurzak
Copy link

Thanks for this idea! I was expected for the same approach as with Tools, it was a surprise to see the existed implementation which doesn't have Attributes.

@PederHP do you have any plans for this feature?

@stephentoub
Copy link
Contributor

We just haven't got to it yet.

@johnkors
Copy link

johnkors commented Apr 8, 2025

We just haven't got to it yet.

Is this why my MCP server logs go: No handler found for request resources/list for server Server?

My server:

        builder.Services.AddMcpServer()
            .WithStdioServerTransport()
            .WithPromptsFromAssembly()
            .WithToolsFromAssembly();

I'm using my MCP-server together with Claude and it looks like it asks for resources every 5 seconds or so. Shutting down Claude, and the polling for resources/lists stops.

Logs:


[06:17:22] WRN ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 No handler found for request resources/list for server Server (Loftbot.App 1.0.0.0)
[06:17:22] ERR ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler error for Server (Loftbot.App 1.0.0.0) with method resources/list
[06:17:22] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler called for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:22] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler completed for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:27] WRN ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 No handler found for request resources/list for server Server (Loftbot.App 1.0.0.0)
[06:17:27] ERR ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler error for Server (Loftbot.App 1.0.0.0) with method resources/list
[06:17:27] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler called for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:27] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler completed for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:32] WRN ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 No handler found for request resources/list for server Server (Loftbot.App 1.0.0.0)
[06:17:32] ERR ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler error for Server (Loftbot.App 1.0.0.0) with method resources/list
[06:17:32] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler called for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:32] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler completed for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:37] WRN ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 No handler found for request resources/list for server Server (Loftbot.App 1.0.0.0)
[06:17:37] ERR ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler error for Server (Loftbot.App 1.0.0.0) with method resources/list
[06:17:37] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler called for Server (Loftbot.App 1.0.0.0) with method prompts/list
[06:17:37] INF ModelContextProtocol.Server.McpServer bf23e145-b3c9-4c52-94ff-6e060dd62278 Request handler completed for Server (Loftbot.App 1.0.0.0) with method prompts/list

@IvanMurzak
Copy link

@johnkors I don't think so. You just need to set the handler. I made 3 static functions to make it pretty.

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithPromptsFromAssembly()
    .WithToolsFromAssembly()
    .WithListResourceTemplatesHandler(ResourceRouter.ListResourceTemplates)
    .WithListResourcesHandler(ResourceRouter.ListResources)
    .WithReadResourceHandler(ResourceRouter.ReadResource);

@stephentoub
Copy link
Contributor

stephentoub commented Apr 8, 2025

Is this why my MCP server logs go: No handler found for request resources/list for server Server?

That looks like an issue with Claude. If the server doesn't advertise a resources capability, the client shouldn't be issuing requests to list resources.

@johnkors
Copy link

johnkors commented Apr 8, 2025

You just need to set the handler.

I don't have resources, so adding a resource handler would only avoid the error messages. Wouldn't it make more sense for the server to return an empty list if none defined instead of erroring out?

That looks like an issue with Claude. If the server doesn't advertise a resources capability, the client shouldn't be issuing requests to list resources.

Yeah, Copilot in VS Code does not poll - so probably an issue with Claude. Didn't they invent the spec, though? :)

@stephentoub
Copy link
Contributor

Wouldn't it make more sense for the server to return an empty list if none defined instead of erroring out?

It could, but the spec actually states it should be an error:

"Error Handling
Servers SHOULD return standard JSON-RPC errors for common failure cases:
Resource not found: -32002"

@PederHP
Copy link
Collaborator

PederHP commented Apr 8, 2025

Yeah, Copilot in VS Code does not poll - so probably an issue with Claude. Didn't they invent the spec, though? :)

They did, but the Python and TypeScript SDKs have a number of open issues, and there have been a few odd implementation choices (the initial prompt implementation in the app comes to mind) so the Claude desktop app should not be considered a reference client. The mcp-inspector is probably thing that exists to a reference client.

@johnkors
Copy link

johnkors commented Apr 10, 2025

It could, but the spec actually states it should be an error:

I understand, but would it be too magic if there always were a default no-op implementation, so I don't need to do this to avoid error logs?

.WithListResourcesHandler((ctx, ct) => new NoOpListResourceHandler()) // returns empty lists

Or just lower the log level. Some client asking for resources when there aren't any, WRN instead of ERR?

@stephentoub
Copy link
Contributor

Or just lower the log level.

That's reasonable

@Tyler-R-Kendrick
Copy link
Contributor

Tyler-R-Kendrick commented Apr 10, 2025

In your implementation, would you have to list each resource independently, or would you also be able to expose directories?

As an aside, in python there is a package called fsspec that abstracts away the file-system being referenced (similar to the dotnet FileProvider APIs). This package implements the Composite Design Pattern for file-system-providers, allowing developers to specify fallback provider for file lookup (similar to the way dotnet Configurations allow for Composite configuration providers to specify that a secret could be in user-secrets, env vars, etc.).

Would the pattern you use here prevent that from being implemented with dotnet File Providers?
Could you do something like use multiple attributes with different protocols to emulate the pattern?

@johnkors
Copy link

It could, but the spec actually states it should be an error:

"Error Handling Servers SHOULD return standard JSON-RPC errors for common failure cases: Resource not found: -32002"

To me, the spec reads "Resource not found" to be returned when a specific resource does not exists amongst the ones present in resources/list. It does not state (at least explicitly) that the resource/list itself should return an RPC-message with Resource not found.

Check the example they follow that statement with: , they specifically link that to a resource, not the capability of exposing resources on it's own.

Servers SHOULD return standard JSON-RPC errors for common failure cases:

  • Resource not found: -32002
  • Internal errors: -32603

Example error:

{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32002,
    "message": "Resource not found",
    "data": {
      "uri": "file:///nonexistent.txt"
    }
  }
}

Are you sure you are not mixing the two concepts here?

@johnkors
Copy link

I was thinking either just logging and returning,

Is notifying the client on par with the spec?: johnkors@ba89760

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants