Skip to content

Rebase concrete exceptions onto Mcp\Exception base classes - #39

Open
chr-hertel wants to merge 2 commits into
mainfrom
fix/issue-20-exception-hierarchy
Open

Rebase concrete exceptions onto Mcp\Exception base classes#39
chr-hertel wants to merge 2 commits into
mainfrom
fix/issue-20-exception-hierarchy

Conversation

@chr-hertel

@chr-hertel chr-hertel commented Aug 22, 2026

Copy link
Copy Markdown
Owner

All concrete SDK exceptions that extended the global \RuntimeException / \InvalidArgumentException / \Exception directly now extend the corresponding Mcp\Exception\* base class, so catch (\Mcp\Exception\RuntimeException) and friends actually catch them. Mcp\Exception\RuntimeException loses final to serve as a parent.

BC-safe: the Mcp bases extend the same global classes, so every existing catch and instanceof (including the \InvalidArgumentException echo branches in Protocol and StatelessProtocol) keeps matching identically.

Adds ExceptionHierarchyTest asserting every exception in src/Exception is catchable through an Mcp base class.

MessageFactory::createMessage() now re-throws InvalidInputMessageException unchanged instead of re-wrapping it (its catch on Mcp's InvalidArgumentException would otherwise match it after this rehoming, erasing subtypes), with a regression test.

Follow-up idea (not implemented here): the "safe to echo to the client" decision in both protocols still keys off \InvalidArgumentException; an explicit opt-in marker interface (e.g. ClientVisibleMessageInterface) implemented by Mcp\Exception\InvalidArgumentException would make that contract explicit with identical behavior.

Closes #20

Confidence: 9/10 — mechanical parent-class swap with unchanged catch/instanceof semantics, full unit suite, php-cs-fixer and phpstan green; small residual risk only from downstream code relying on exact-class checks.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[B6] Two competing exception roots, and the choice decides what leaks to clients

1 participant