- accept single-segment library ids like /whisper-rtx2080 returned by
resolve-library-id in get-library-docs
- accept common owner-qualified aliases such as /mozempk/whisper-rtx2080
when the indexed repo is stored as a single-segment name
- accept single-segment ids with explicit versions such as
/whisper-rtx2080/v0.0.1
- relax resolve-library-id scoring across separator-only differences so
queries like whisperrtx2080 still match whisper-rtx2080
- update MCP tool descriptions to document the accepted id formats
Validated with focused regression tests:
- TrueRefMcpToolsTest
- LibraryResolverTest
- register a Jackson mixin for io.modelcontextprotocol.spec.McpError
- strip Throwable internals such as stackTrace, cause and suppressed
from SDK-owned MCP HTTP error responses
- keep malformed Streamable HTTP requests bounded to a minimal JSON body
like {"message":"Session ID missing"}
Validated locally:
- POST /mcp tools/list without Mcp-Session-Id -> 400 {"message":"Session ID missing"}
- POST /mcp initialize -> 200
- align all io.modelcontextprotocol.sdk artifacts to 0.18.1 via
dependencyManagement so Spring AI transitives no longer pull mcp 0.10.0
- exclude Spring AI's legacy MCP server/webmvc auto-config, which is binary-
incompatible with the 0.18.1 streamable transport APIs
- build McpSyncServer directly against WebMvcStreamableServerTransportProvider
and adapt Spring AI ToolCallbacks to MCP SyncToolSpecifications manually
- keep /mcp as the sole Streamable HTTP endpoint for both initialize/tool calls
and optional SSE event streams
- update MCP transport documentation to match the new runtime
Validated locally with:
- POST /mcp initialize -> HTTP 200 + Mcp-Session-Id
- POST /mcp tools/list -> returns resolve-library-id + get-library-docs
- Upgrade mcp-spring-webmvc from 0.10.0 to 0.18.1 (adds
WebMvcStreamableServerTransportProvider alongside the legacy SSE provider)
- Add mcp-json-jackson2 0.18.1 for JacksonMcpJsonMapper adapter
- Exclude McpWebMvcServerAutoConfiguration (SSE transport) via
spring.autoconfigure.exclude; register WebMvcStreamableServerTransportProvider
and its RouterFunction manually in McpConfig so Spring AI's
McpServerAutoConfiguration picks up the correct transport bean
- Remove sse-message-endpoint / sse-endpoint from application.yml;
all MCP traffic now flows through POST+GET /mcp
- Remove McpSseMethodNotAllowed workaround from WebConfig and drop
'sse' from SPA fallback exclusions (no longer needed)
Clients should connect with type: http at https://trueref.sal.giize.com/mcp
Modern MCP clients (Claude Code, etc.) probe for Streamable HTTP transport by
POSTing an InitializeRequest to the server URL first. Per MCP spec 2025-11-25,
they fall back to legacy HTTP+SSE only on 400/404/405.
Previously, POST /sse fell through the SPA resource resolver (which had 'sse'
missing from EXCLUDED_PREFIXES) and returned 500, causing clients to abort
instead of retrying with the GET-based SSE handshake.
Fix:
- Add 'sse' to EXCLUDED_PREFIXES so the SPA resolver ignores that path
- Add explicit @PostMapping("/sse") returning 405 Method Not Allowed with
Allow: GET header — the correct signal for Streamable HTTP probe fallback
AsyncRequestNotUsableException is thrown when the SSE client disconnects
before the server finishes writing (normal: browser tab close, MCP
client reconnect). The catch-all handler was logging it at ERROR level
and then attempting to write a JSON ErrorResponse onto a text/event-stream
response that no longer had a converter, producing a second spurious
HttpMessageNotWritableException log entry.
Fix: add a dedicated @ExceptionHandler(AsyncRequestNotUsableException)
that logs at DEBUG only and returns void (no body).
- .gitignore had bare 'out/' matching source directories; changed to '/out/'
- All 45 files under trueref-domain/port/out and trueref-adapters/.../out
were silently excluded from the initial commit
- Added .dockerignore to exclude data/, runtime/, logs/ from build context
- Replace type=gha cache (disabled on this runner) with type=registry cache
- Upgrade docker/build-push-action v5 → v6 (matches whisper-rtx2080 pattern)
- Switch auth to REGISTRY_USERNAME/REGISTRY_TOKEN repo secrets
- Split into two parallel jobs (build-cpu / build-gpu) for visibility
- Use github.ref conditions (Gitea compat) instead of is_default_branch