@@ -852,24 +852,58 @@ handler to a Go function using reflection to derive its arguments. We provide
852
852
853
853
### Resources and resource templates
854
854
855
- Servers have Add and Remove methods for resources and resource templates:
855
+ To add a resource or resource template to a server, users call the ` AddResource` and
856
+ ` AddResourceTemplate` methods, passing the resource or template and a function for reading it:
857
+ ` ` ` go
858
+ type ReadResourceHandler func (context.Context , *ServerSession, *Resource, *ReadResourceParams) (*ReadResourceResult, error )
859
+
860
+ func (*Server) AddResource (*Resource, ReadResourceHandler)
861
+ func (*Server) AddResourceTemplate (*ResourceTemplate, ReadResourceHandler)
862
+ ` ` `
863
+ The ` Resource` is passed to the reader function even though it is redundant (the function could have closed over it)
864
+ so a single handler can support multiple resources.
865
+ If the incoming resource matches a template, a ` Resource` argument is constructed
866
+ from the fields in the ` ResourceTemplate` .
867
+ The ` ServerSession` argument is there so the reader can observe the client's roots.
856
868
869
+ To read files from the local filesystem, we recommend using ` FileReadResourceHandler` to construct a handler:
857
870
` ` ` go
858
- func (*Server) AddResources (resources ...*Resource)
859
- func (*Server) RemoveResources (names ...string )
860
- func (*Server) AddResourceTemplates (templates...*ResourceTemplate)
871
+ // FileReadResourceHandler returns a ReadResourceHandler that reads paths using dir as a root directory.
872
+ // It protects against path traversal attacks.
873
+ // It will not read any file that is not in the root set of the client requesting the resource.
874
+ func (*Server) FileReadResourceHandler (dir string ) ReadResourceHandler
875
+ ` ` `
876
+ It guards against [path traversal attacks](https://go.dev/blog/osroot)
877
+ and observes the client's roots.
878
+ Here is an example:
879
+ ` ` ` go
880
+ // Safely read "/public/puppies.txt".
881
+ s.AddResource (
882
+ &mcp.Resource {URI: " file:///puppies.txt" },
883
+ s.FileReadResourceHandler (" /public" ))
884
+ ` ` `
885
+
886
+ There are also server methods to remove resources and resource templates.
887
+ ` ` ` go
888
+ func (*Server) RemoveResources (uris ...string )
861
889
func (*Server) RemoveResourceTemplates (names ...string )
862
890
` ` `
891
+ Resource templates don't have unique identifiers, so removing a name will remove all
892
+ resource templates with that name.
863
893
864
894
Clients call ` ListResources` to list the available resources, ` ReadResource` to read
865
895
one of them, and ` ListResourceTemplates` to list the templates:
866
896
867
897
` ` ` go
868
898
func (*ClientSession) ListResources (context.Context , *ListResourcesParams) (*ListResourcesResult, error )
869
- func (*ClientSession) ReadResource (context.Context , *ReadResourceParams) (*ReadResourceResult, error )
870
899
func (*ClientSession) ListResourceTemplates (context.Context , *ListResourceTemplatesParams) (*ListResourceTemplatesResult, error )
900
+ func (*ClientSession) ReadResource (context.Context , *ReadResourceParams) (*ReadResourceResult, error )
871
901
` ` `
872
902
903
+ ` ReadResource` checks the incoming URI against the server's list of
904
+ resources and resource templates to make sure it matches one of them,
905
+ then returns the result of calling the associated reader function.
906
+
873
907
<!-- TODO: subscriptions -->
874
908
875
909
### ListChanged notifications
0 commit comments