feat(mcp): expose list_resources, list_resource_templates, and read_resource on MCPServer#2721
feat(mcp): expose list_resources, list_resource_templates, and read_resource on MCPServer#2721adityasingh2400 wants to merge 9 commits intoopenai:mainfrom
Conversation
…esource The MCP specification defines a Resources primitive alongside Tools and Prompts, and the underlying ClientSession already implements list_resources(), list_resource_templates(), and read_resource(), but none of these were surfaced through MCPServer or its concrete implementations. This adds them in three places: - Abstract methods on MCPServer (parallel to list_prompts/get_prompt) - Concrete implementations on _MCPServerWithClientSession, delegating to session.list_resources() / .list_resource_templates() / .read_resource(uri) via _maybe_serialize_request - Stub implementations in all test helpers that subclass MCPServer Six tests cover the new surface: - Raises UserError when not connected (x3) - Delegates to the underlying session and returns its result (x3) Closes: (new feature — no existing issue)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c59c740b23
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…bclasses Per Codex P1 review: adding abstract methods to the public MCPServer base class would break any existing user-defined subclass that only implements the previously required methods. Changed list_resources, list_resource_templates, and read_resource to concrete methods with a descriptive NotImplementedError default. Existing subclasses continue to instantiate; they only raise at call time if the user actually invokes a resource method they haven't implemented. Also adds a regression test verifying the NotImplementedError path.
|
Fixed the P1 Codex issue — |
…types mypy requires AnyUrl (not str) for: - ClientSession.read_resource(uri) argument - Resource.uri and TextResourceContents.uri fields Convert str -> AnyUrl at the call site in _MCPServerWithClientSession so the public API stays str (ergonomic) while satisfying the type checker.
Head branch was pushed to by a user without write access
mcp.types re-exports AnyUrl at runtime but mypy reports it as not explicitly exported ([attr-defined]). Import directly from pydantic where AnyUrl originates.
…ve duplicate mcp.types AnyUrl
… not recognized by mypy)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4fbb7efc06
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/agents/mcp/server.py
Outdated
| raise UserError("Server not initialized. Make sure you call `connect()` first.") | ||
| session = self.session | ||
| assert session is not None | ||
| return await self._maybe_serialize_request(lambda: session.list_resources()) |
There was a problem hiding this comment.
Expose cursor arguments for paginated resource lists
list_resources/list_resource_templates always call the session methods with no pagination arguments, and the new public methods also expose no cursor/params input. On MCP servers that paginate these endpoints, callers can only ever retrieve the first page (despite getting a nextCursor in the result), so resource discovery becomes incomplete for larger datasets. Please forward pagination inputs through these wrappers so clients can fetch subsequent pages.
Useful? React with 👍 / 👎.
seratch
left a comment
There was a problem hiding this comment.
Can you resolve all the points mentioned by codex?
|
I found one issue with the PR.
|
…templates seratch's review correctly noted that callers had no way to page through results beyond the first page on servers that paginate these endpoints. Changes: - MCPServer.list_resources(cursor=None) / list_resource_templates(cursor=None) base methods now accept an optional opaque cursor string - _MCPServerWithClientSession concrete implementations forward the cursor to session.list_resources(cursor) / session.list_resource_templates(cursor) - Docstrings document the nextCursor / cursor round-trip pattern - Test helpers updated to match the new signature - Two new tests verify cursor is forwarded correctly for both methods
|
Fixed — |
|
@codex review this in depth again |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e4bd5224c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
tests/mcp/helpers.py
Outdated
| async def list_resources(self) -> ListResourcesResult: | ||
| """Return empty list of resources for fake server.""" | ||
| return ListResourcesResult(resources=[]) | ||
|
|
||
| async def list_resource_templates(self) -> ListResourceTemplatesResult: | ||
| """Return empty list of resource templates for fake server.""" |
There was a problem hiding this comment.
Match FakeMCPServer resource method signatures to MCPServer
FakeMCPServer narrows the new interface by omitting the optional cursor parameter on list_resources and list_resource_templates. Any test or helper code that calls these through an MCPServer reference with cursor=... will raise TypeError, so pagination behavior cannot be exercised with this shared fake server.
Useful? React with 👍 / 👎.
seratch
left a comment
There was a problem hiding this comment.
one last request before merging
| """Read the contents of a specific resource by URI. | ||
|
|
||
| Args: | ||
| uri: The URI of the resource to read (e.g. ``file:///path/to/file.txt`` or |
There was a problem hiding this comment.
can you simply mention AnyUrl docstring as reference? We'd like to avoid mentioning specific examples and having our own comment, which can be outdated in the future.
| """Read the contents of a specific resource by URI. | ||
|
|
||
| Args: | ||
| uri: The URI of the resource to read (e.g. ``file:///path/to/file.txt``). |
There was a problem hiding this comment.
can you simply mention AnyUrl docstring as reference? We'd like to avoid mentioning specific examples and having our own comment, which can be outdated in the future.
Problem
The MCP specification defines a Resources primitive alongside Tools and Prompts. The underlying
ClientSessionfrom the MCP Python SDK already implementslist_resources(),list_resource_templates(), andread_resource(uri), but none of these are surfaced throughMCPServeror its concrete implementations.This means callers cannot retrieve file contents, database records, or any other server-managed resources even though the transport layer fully supports it.
Solution
Add the three resource methods in three places, following the exact same pattern as the existing
list_prompts/get_promptpair:MCPServer— establishing the contract for all server types_MCPServerWithClientSession— delegating tosession.list_resources(),session.list_resource_templates(), andsession.read_resource(uri)via_maybe_serialize_request(so serialization and retry logic apply automatically)FakeMCPServerand the other test-only subclasses remain concreteTests
Six new tests in
tests/mcp/test_mcp_resources.py:test_list_resources_raises_when_not_connectedtest_list_resource_templates_raises_when_not_connectedtest_read_resource_raises_when_not_connectedtest_list_resources_returns_resulttest_list_resource_templates_returns_resulttest_read_resource_returns_resultUsage