Skip to content

Add remove_prompt() and remove_resource() for parity with remove_tool() #2331

Description

@rgoldstein1989

Description

MCPServer exposes remove_tool(name) (added in #1322) but has no equivalent for prompts or resources. This was part of the original ask in #711 ("removing a tool or resource dynamically"), which was closed when remove_tool() landed — but the resource and prompt sides were never addressed.

Use case

Multi-tenant / multi-instance deployments where the same server image serves different clients. Today users can filter tools per-instance via remove_tool(), but for prompts and resources they're forced to reach into private internals:

# Current workaround — fragile, undocumented
del mcp._prompt_manager._prompts["some_prompt"]
del mcp._resource_manager._resources[str(uri)]

(This is the same pattern @lukehsiao described in #711 (comment) for tools, before remove_tool() existed.)

Current state

Primitive add_* remove_*
Tool add_tool() / @tool() remove_tool() ✅
Prompt add_prompt() / @prompt() missing
Resource add_resource() / @resource() missing
Resource Template add_template() missing

Proposed API

Add these methods, mirroring the existing remove_tool() pattern exactly:

  • PromptManager.remove_prompt(name: str) — raises PromptError if not found
  • ResourceManager.remove_resource(uri: str) — raises ResourceError if not found
  • ResourceManager.remove_template(uri_template: str) — raises ResourceError if not found
  • MCPServer.remove_prompt(name) — thin wrapper delegating to the manager
  • MCPServer.remove_resource(uri) — thin wrapper delegating to the manager
  • MCPServer.remove_resource_template(uri_template) — thin wrapper delegating to the manager
  • PromptError exception class in exceptions.py (for symmetry with ToolError and ResourceError)

This is ~15 lines of implementation across 4 source files, plus tests. Purely additive, no breaking changes.

References

Activity

  1. added a commit that references this issue on Mar 22, 2026
    c1053d5
  2. goingforstudying-ctrl commented on Mar 22, 2026

    @goingforstudying-ctrl

    Submitted PR #2333 to implement this: #2333

    This adds remove_prompt(), remove_resource(), and remove_resource_template()
    following the same pattern as remove_tool(). Please review when you have time. Thanks!

  3. added a commit that references this issue on Mar 22, 2026
    a1e2c67
  4. rgoldstein1989 commented on Mar 22, 2026

    @rgoldstein1989
    Author

    Submitted PR #2335 as an alternative to #2333. It covers the same implementation scope but adds:

    1. Tests — 11 tests mirroring the existing remove_tool patterns (remove existing, remove nonexistent, remove-and-list via client, remove-and-access via client) for all three primitives. Required to pass CI's 100% coverage gate.
    2. AnyUrl | str type on remove_resource — normalizes with str(uri) before lookup, matching how get_resource() handles it.
  5. Kludex commented on Apr 5, 2026

    @Kludex
    Member

    I don't think this is the way the specification wants us to go.

    I believe we should offer an API that should depend on the client i.e. I would like to remove a tool for a single client, not all of them.


    I don't think we should merge this without clarifying that first.

  6. rgoldstein1989 commented on Apr 6, 2026

    @rgoldstein1989
    Author

    I don't think this is the way the specification wants us to go.

    I believe we should offer an API that should depend on the client i.e. I would like to remove a tool for a single client, not all of them.

    I don't think we should merge this without clarifying that first.

    I'm not sure im following you, like remove a tool depending on the client that is connecting?

  7. added
    enhancementRequest for a new feature that's not currently supported
    P3Nice to haves, rare edge cases
    needs decisionIssue is actionable, needs maintainer decision on whether to implement
    on Aug 14, 2026
  8. rgoldstein1989 commented on Oct 9, 2026

    @rgoldstein1989
    Author

    Still relevant on v2, but the ask is smaller than when I opened this.

    remove_prompt() landed in v2 — thanks for that. Resources are the remaining gap:

    add remove
    tools add_tool remove_tool
    prompts add_prompt remove_prompt ✅ v2
    resources add_resource —
    resource templates add_template —

    MCPServer.remove_prompt() delegates to PromptManager.remove_prompt(). ResourceManager keeps _resources and _templates as plain dicts with add_resource() / add_template() and no removal for either, so the same shape would apply.

    Repro (v2, main)

    from mcp.server import MCPServer
    
    mcp = MCPServer("demo")
    
    @mcp.resource("config://settings")
    def settings() -> str:
        return "..."
    
    mcp.remove_tool("some_tool")      # ok
    mcp.remove_prompt("some_prompt")  # ok, new in v2
    mcp.remove_resource("config://settings")
    # AttributeError: 'MCPServer' object has no attribute 'remove_resource'

    Use case

    We run one server image as nine Azure Container Apps. Each deployment serves a different surface, selected at startup from an environment variable naming the tools that deployment should expose — a customer-facing endpoint gets three tools, an internal one gets thirty-four, and so on.

    Tools are filtered with remove_tool(), and prompts can now be filtered with remove_prompt(). Resources cannot, so a deployment that deliberately excludes a feature still publishes that feature's resources. Concretely: we recently moved one integration's tools onto a dedicated endpoint and removed them from the shared one, and its resources stayed behind on both — the split is complete for tools and prompts and incomplete for resources, purely because there is no public API for it.

    The workaround is reaching into _resource_manager._resources, which is the same shape as the one noted earlier in this thread.

    remove_resource(uri) and remove_template(uri_template), mirroring the prompt implementation, would close it.


    For anyone following the history: #2335 was closed as part of the v2 backlog sweep, not on the merits. Happy to open a PR against v2 for just the resource side if that would help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Nice to haves, rare edge casesenhancementRequest for a new feature that's not currently supportedneeds decisionIssue is actionable, needs maintainer decision on whether to implement

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions