adityamparikh opened a new pull request, #273:
URL: https://github.com/apache/solr-mcp/pull/273
Closes #213.
Stacked on #269 (`./gradlew build` runs `buildSrc`'s tests) and #266
(google-java-format): the first two commits here are those PRs, and only the
top commit (`fix(mcp): report checked tool exceptions as readable tool errors`)
is new.
## Problem
#213 was written against Spring AI 1.1, which reported only the root cause's
message. On 2.0.1 the wrapper message and the root cause both reach the client,
so the four parse sites the issue lists already show their detail; this PR
leaves them alone.
What is still broken is the checked-exception path. Spring AI 2.0.1 turns a
`RuntimeException` from an `@McpTool` method into an `isError` result, but
wraps a checked exception in `UndeclaredThrowableException` and rethrows it
(`AbstractMcpToolMethodCallback`, `SyncStatelessMcpToolMethodCallback`;
unchanged on Spring AI `main` and `2.1.0-M1`). The MCP SDK then answers with a
protocol error instead of a tool result:
```
{"jsonRpcError":{"code":-32603,"message":"Failed to handle request. Check
server logs for details."}}
```
14 of the 15 tools declare `SolrServerException`/`IOException`, so with Solr
unreachable the model gets no text it can act on. `SearchService`'s own "unable
to communicate with Solr" hint was rethrown as a checked exception and never
reached the client either.
## Changes
- **`McpToolExceptionAspect`** (new, `config/`): `@Around` every `@McpTool`
method.
- Runtime exceptions and errors are rethrown unchanged. Spring AI already
reports them as tool errors, and method security's `AccessDeniedException` is
one of them.
- Any checked exception is logged at WARN and replaced by an
`IllegalStateException`: `<tool> failed: unable to communicate with Solr. Retry
later; if it persists, ask the operator to check Solr availability and
connection settings.` It has no cause, because Spring AI appends the root
cause's message to the tool error and SolrJ's text names the internal Solr URL.
- Spring AI has no hook for this (spring-projects/spring-ai#4488);
`toolCallExceptionClass` is deprecated and ignored.
- **`SearchService`**: drop the `SolrServerException`/`IOException` catches
and `CONNECTION_ERROR`, which the aspect replaces. Correct the comments that
said MCP reports only the root cause.
- **`CollectionService.getCollectionStats`**: log the Solr 404 and throw the
`list-collections` hint without it as the cause, as
`SearchService.withRemediationHint` already does.
Every checked exception a tool throws today comes from SolrJ, which is what
the message assumes. A future tool with a non-Solr checked exception
(index-url's HTTP fetch, #208) has to translate it before it reaches the aspect.
## Tests
- `McpToolBackendUnavailableIntegrationTest` (new): HTTP server with
`solr.url=http://127.0.0.1:1/solr/`, calling all 14 Solr-backed tools. Each
must return `isError=true`, start with `<tool> failed`, and not contain the
Solr address. Before the fix, all 14 fail with the `-32603` above.
- `McpToolExceptionAspectTest` (new): the aspect in a minimal Spring context
with fixture tools, so the proxy is generated by AOT and the test runs under
`nativeTest` too. Covers checked → translated, runtime and
`AccessDeniedException` → same instance, normal return, and methods without
`@McpTool` left alone.
- `McpClientIntegrationTestBase` (HTTP and stdio): malformed XML and invalid
YAML front matter return their parser detail; `get-collection-stats` on an
unknown collection returns the `list-collections` hint without `Error from
server`.
- `SearchServiceTest`, `SearchServiceIntegrationTest`,
`CollectionServiceTest`: drop the checked cases from search's backend-failure
loop, assert no cause on the not-found error, and reword the "MCP must not
unwrap" messages.
Until spring-projects/spring-ai#6949 ships, a cause-less error message
appears twice in the tool error (spring-projects/spring-ai#6948). Assertions
use `contains`/`startsWith`, so that fix needs no test changes.
`./gradlew build`: 490 tests, 0 failures, 0 skipped. `./gradlew nativeTest
-Pnative`: 329 successful, 0 failed, including `McpToolExceptionAspectTest` and
`McpToolBackendUnavailableIntegrationTest`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]