Repository navigation
feat(mcp): surface MCP resources and prompts in the SDK - #6196
Open
xxwtiancai wants to merge 5 commits into
Open
xxwtiancai wants to merge 5 commits into
xxwtiancai wants to merge 5 commits into
Conversation
A chat-completions stream that yields no chunks reassembles to None in _transport_call and _atransport_call, tripping the ModelResponse assertion. That AssertionError is not in LLM_RETRY_EXCEPTIONS, so an empty stream from the provider was neither retried nor classified as the retryable no-response failure. Raise LLMNoResponseError from the streaming branch when the reassembly returns None, so the existing num_retries/backoff policy applies, and add sync/async retry and exhaustion tests. Addresses item 2 of the streaming audit in issue 4077, superseding the stale draft PR 4095. Co-authored-by: openhands <[email protected]>
openhands.sdk.mcp was tools-only: servers that also advertise resources (static or templated content) or prompts (server-rendered message templates) exposed none of that to OpenHands users, forcing duplication into AGENTS.md or nonstandard wrapper tools. Add resources_prompts with four functions over the existing native dict[str, MCPServer] config: list_mcp_resources (resources plus templates with parsed RFC 6570 parameters), read_mcp_resource (text or base64 blob with URI and MIME type), list_mcp_prompts (declared arguments with required flags), and render_mcp_prompt (messages preserving role and content type). Each call opens one single-server client through the existing _prepare_mcp_config boundary, so every result carries the true server key and the server's original URIs — the composite client's URI rewriting would lose them. A method-not-found answer maps to a catchable MCPCapabilityNotSupportedError; other failures name the server and the resource or prompt involved. Content flows only through explicit selection: the new example composes a provenance-carrying user message from a resource read and a rendered prompt and needs no LLM. Closes OpenHands#6191 Co-authored-by: openhands <[email protected]>
Contributor
|
📁 PR Artifacts Notice This PR adds or changes temporary PR-specific documents under |
xxwtiancai
marked this pull request as ready for review
October 24, 2026 10:07
Merge of upstream main brings the fastmcp 4 / mcp 2 migration (OpenHands#6540): mcp.shared.exceptions.McpError no longer exists. Import the preserved fastmcp.exceptions.McpError instead and build it with the new positional (code, message) constructor in the capability test. Co-authored-by: openhands <[email protected]>
…prompts-6191 # Conflicts: # openhands-sdk/openhands/sdk/llm/llm.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
HUMAN:
Summary
Implements SDK-level support for MCP resources and prompts (#6191) as the foundational step of the SDK-first rollout. Server REST APIs and TypeScript clients are deferred to follow-up PRs.
Key Changes
openhands.sdk.mcp.resources_prompts):list_mcp_resources: Returns resources, templates, and parsed RFC 6570 parameters.read_mcp_resource: Reads text/binary payloads with original URI and MIME types preserved.list_mcp_prompts: Returns prompts with parameter schemas and required flags.render_mcp_prompt: Preserves message roles and block content types._prepare_mcp_config, inheriting existing OAuth/credential expansions.fastmcpcomposite client URI rewrites (protocol://{server}/path) to guarantee exact URI attribution across single and multi-server setups. Leavescreate_mcp_toolsuntouched.-32601, inspected via cause chain) map to catchableMCPCapabilityNotSupportedError.MCPErrorandMCPTimeoutError.usermessages ([MCP resource server=... uri=...]) without LLM overhead (EXAMPLE_COST: 0).Verification
tests/sdk/mcppassed (164 passed, 1 pre-existing sandbox 502).getattrhook rules).AGENT:
Why
openhands.sdk.mcpis tools-only today. MCP servers that also advertise resources (static or templated content, e.g. server-provided usage documentation) and prompts (server-rendered, parameterized message templates) expose none of that to OpenHands users, so the only options are duplicating the content into AGENTS.md or wrapping it in nonstandard tools.Summary
openhands.sdk.mcp.resources_promptsmodule with four functions over the existing nativedict[str, MCPServer]config:list_mcp_resources(config, server=None)→{server: MCPResourceListing}with resources plus resource templates, each template's RFC 6570 parameters parsed out;read_mcp_resource(config, server, uri)→ content blocks carrying the server key, URI, MIME type, and eithertextor base64blob_b64;list_mcp_prompts(config, server=None)→ prompts with declared arguments and required flags;render_mcp_prompt(config, server, name, arguments)→ messages preserving each message's role and content-block type (text / image / audio / embedded resource)._prepare_mcp_configboundary (OAuth, secret expansion included) and closes it. This is deliberate: the composite client rewrites resource URIs toprotocol://{server}/path, which would lose the server's original URIs, and per-server connections make attribution exact and identical for single- and multi-server configs.create_mcp_toolsand tools-only configs are untouched — same tools, same system prompt behavior, no new connections.MCPCapabilityNotSupportedError(server, capability); fastmcp-based servers that implementresources/listwith an empty result surface as an ordinary empty listing. Any other failure raises anMCPErrornaming the server and the resource URI or prompt; timeouts raiseMCPTimeoutErrorwith the server name, matchingcreate_mcp_tools.Messagewith a provenance header, and sends it viaconversation.send_message. Nothing is loaded implicitly.examples/01_standalone_sdk/60_mcp_resources_prompts/(registered in_TARGET_DIRECTORIES) demonstrates the full flow — list, static read, template resolution, prompt listing and rendering, and message composition — against a local stdio server, with no LLM (EXAMPLE_COST: 0).Issue Number
Closes #6191
How to Test
The tests run a real stdio FastMCP server (resources, a template, a binary blob, a prompt, plus the existing tools-only server for the multi-server attribution case) and cover: listing with parsed template parameters, static and resolved-template reads, binary blob round-trip, prompt listing/rendering with preserved roles, per-server attribution across two servers, unknown server key, failed read naming server and URI, and the method-not-found →
MCPCapabilityNotSupportedErrormapping. The fulltests/sdk/mcpsuite passes (164 passed; the one failure is the pre-existing localhost-502 environment failure that also fails on unmodified main in this sandbox).Video/Screenshots
Not a visual change; example output is shown in How to Test.
Design Doc
.pr/design.md — covers the per-server-connection decision and the error mapping.
Type
Notes