Description
Translator::get_client_for_file (used by every per-file tool handler) distinguishes two distinct failure modes when no server can serve a request:
Error::NoServerForLanguage(lang) — no server at all is configured/applicable for the file's language.
Error::NoServerForTool { language_id, tool } — a server is configured for the language, but no server's handles list (or catch-all) claims this specific tool.
Translator::handle_workspace_symbol, which has no file to detect a language from and resolves via ToolRouter::resolve_any instead of resolve, collapses both cases into the single generic Error::NoServerConfigured ("no LSP server configured").
Since #228 introduced per-tool handles routing, it is now possible to have a fully configured, running LSP server for a language that simply does not claim workspace_symbols in its handles list (with no catch-all for that language) — ToolRouter::from_configs even logs a tracing::warn! for exactly this case at startup. When a client then calls the workspace_symbol_search MCP tool, it gets the same "no LSP server configured" message it would get if nothing were running at all, which is misleading and unhelpful for diagnosing a routing/config mistake.
Reproduction Steps
- Configure a single
[[lsp_servers]] entry for a language with handles = ["hover"] (no catch-all, so workspace_symbols is unclaimed).
- Start mcpls; observe the startup warning:
language '<lang>' has no catch-all server and does not claim: ... workspace_symbols ....
- Call the
workspace_symbol_search MCP tool.
- Observe the error:
no LSP server configured.
Expected Behavior
An error that names the specific gap, analogous to the per-file path, e.g. no server handles tool 'workspace_symbols' — or at minimum distinguishes "nothing running" from "nothing claims this tool" the same way resolve/get_client_for_file already do.
Actual Behavior
Generic Error::NoServerConfigured in both cases, indistinguishable from an empty configuration.
Environment
Logs / Evidence
crates/mcpls-core/src/bridge/translator.rs: get_client_for_file (~line 675) vs handle_workspace_symbol (~line 1247) resolution paths.
crates/mcpls-core/src/config/routing.rs: ToolRouter::resolve_any has no equivalent of resolve's explicit/catch-all distinction surfaced to the caller, and no has_language-style helper for the language-less case.
Description
Translator::get_client_for_file(used by every per-file tool handler) distinguishes two distinct failure modes when no server can serve a request:Error::NoServerForLanguage(lang)— no server at all is configured/applicable for the file's language.Error::NoServerForTool { language_id, tool }— a server is configured for the language, but no server'shandleslist (or catch-all) claims this specific tool.Translator::handle_workspace_symbol, which has no file to detect a language from and resolves viaToolRouter::resolve_anyinstead ofresolve, collapses both cases into the single genericError::NoServerConfigured("no LSP server configured").Since #228 introduced per-tool
handlesrouting, it is now possible to have a fully configured, running LSP server for a language that simply does not claimworkspace_symbolsin itshandleslist (with no catch-all for that language) —ToolRouter::from_configseven logs atracing::warn!for exactly this case at startup. When a client then calls theworkspace_symbol_searchMCP tool, it gets the same "no LSP server configured" message it would get if nothing were running at all, which is misleading and unhelpful for diagnosing a routing/config mistake.Reproduction Steps
[[lsp_servers]]entry for a language withhandles = ["hover"](no catch-all, soworkspace_symbolsis unclaimed).language '<lang>' has no catch-all server and does not claim: ... workspace_symbols ....workspace_symbol_searchMCP tool.no LSP server configured.Expected Behavior
An error that names the specific gap, analogous to the per-file path, e.g.
no server handles tool 'workspace_symbols'— or at minimum distinguishes "nothing running" from "nothing claims this tool" the same wayresolve/get_client_for_filealready do.Actual Behavior
Generic
Error::NoServerConfiguredin both cases, indistinguishable from an empty configuration.Environment
Logs / Evidence
crates/mcpls-core/src/bridge/translator.rs:get_client_for_file(~line 675) vshandle_workspace_symbol(~line 1247) resolution paths.crates/mcpls-core/src/config/routing.rs:ToolRouter::resolve_anyhas no equivalent ofresolve's explicit/catch-all distinction surfaced to the caller, and nohas_language-style helper for the language-less case.