feat(mcp): proactive roots/list bootstrap + расширенный type_info + новый global_member_info#4131
Conversation
…obal_member_info Roots - McpRootsBootstrapper: при первом tool-вызове сервер сам шлёт roots/list если клиент объявил roots-capability — без него Claude Code на Windows и подобные клиенты, которые не отправляют roots/list_changed, оставляли bsl-ls без зарегистрированного workspace и валили все workspace-зависимые инструменты с «No registered workspace». - McpToolSpecificationsBootstrapWrapper: BeanPostProcessor оборачивает каждый SyncToolSpecification из bean'а `toolSpecs` Spring AI, прозрачно дёргая bootstrap перед делегированием в исходный callHandler. Сами @McpTool-методы не знают о bootstrap-логике. - McpRootsChangeConsumer.normalizeWindowsFileUri: чинит роуты вида `file://D:\path` (буква диска как host + backslash) → `file:///D:/path`, которые шлёт Claude Code 2.1.178 на Windows и которые Absolute.uri не парсит. type_info - Параметр `language` (RU/EN, default RU) на сам tool: имена, описания и билингв-поля платформенной метаинформации возвращаются на выбранной локали. - Новые поля Result: `constructors`, `events`, `definedAt`. - TypeMemberDto: добавлены `async` и `metadata` (TypeMemberMetadataDto со sinceVersion / deprecatedSinceVersion / recommendedReplacements / availabilities / accessMode / returnValueDescription / notes / examples / seeAlso). - TypeParameterDto: добавлены `variadic` и `description`. - TypeService.definingUri(TypeRef): публичный URI исходного файла-объявления для USER и CONFIGURATION без необходимости в активном DocumentContext'е. global_member_info - Новый MCP-tool: резолв глобальной функции / свойства / системного перечисления (GlobalScopeProvider.findFunction → findGlobalProperty → findGlobalEnum) с возвратом полного TypeMemberDto для функций и упрощённого дескриптора с типом значения для свойств/перечислений. Tests - TypeMemberMetadataDtoTest, TypeMemberDtoTest, TypeParameterDtoTest: DTO-маппинг. - McpRootsBootstrapperTest, McpToolSpecificationsBootstrapWrapperTest: цикл bootstrap, идемпотентность, обработка отсутствия capability, обёртка callHandler'а. - McpRootsChangeConsumerTest: windows-URI normalization, end-to-end приведение битого URI к работоспособному. - McpToolsTest: расширен новыми сценариями type_info (constructors / events / language / definedAt) и кейсами global_member_info (function / EN alias / unknown / OS file type). - TypeServiceTest: определение definingUri для PLATFORM / UNKNOWN / ANY.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughWalkthroughAdds ChangesMCP Tool Enrichment and Roots Bootstrapping
Sequence Diagram(s)sequenceDiagram
participant Client as MCP Client
rect rgba(70, 130, 180, 0.5)
note over Client: First tool invocation with roots capability declared
Client->>McpToolSpecificationsBootstrapWrapper: CallToolRequest (with McpSyncServerExchange)
McpToolSpecificationsBootstrapWrapper->>McpRootsBootstrapper: bootstrapIfNeeded(exchange)
McpRootsBootstrapper->>Client: exchange.listRoots()
Client-->>McpRootsBootstrapper: ListRootsResult(roots)
McpRootsBootstrapper->>McpRootsChangeConsumer: accept(roots)
McpRootsChangeConsumer->>McpRootsChangeConsumer: normalizeWindowsFileUri(uri)
end
McpToolSpecificationsBootstrapWrapper->>OriginalToolHandler: callHandler(exchange, request)
OriginalToolHandler-->>Client: CallToolResult
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeServiceTest.java (1)
130-140: ⚡ Quick winAssert the resolved fixture type before the empty-URI expectation.
This test assumes the fixture symbol resolves to a platform type. Add an explicit kind assertion first so failures stay diagnostic if test data changes.
Suggested test hardening
var typeRef = typeService.typesAt(reference).refs().iterator().next(); + assertThat(typeRef.kind()).isEqualTo(com.github._1c_syntax.bsl.languageserver.types.model.TypeKind.PLATFORM); var uri = typeService.definingUri(typeRef);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeServiceTest.java` around lines 130 - 140, In the definingUriEmptyForPlatformType test method, add an explicit assertion to verify that typeRef resolves to the expected platform type kind before the assertThat(uri).isEmpty() assertion. This ensures that if the test fixture data changes, the test will fail at the kind check with a clear diagnostic message rather than silently failing at the URI assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpRootsChangeConsumerTest.java`:
- Around line 78-91: The test `normalizesWindowsStyleFileUriBeforeRegistration`
extracts path components from the actual filesystem (using
`path.getRoot().toString().substring(0, 2)` for the drive letter and path
manipulation), which will fail on Unix systems where `getRoot()` returns "/"
instead of a drive letter. Replace the filesystem-dependent path extraction
logic with hardcoded Windows path values (e.g., hardcode "D:" for driveLetter
and use a hardcoded path string like "D:\\path\\with\\backslashes" for
constructing brokenUri) to make the test platform-independent and focused on
testing the URI normalization logic rather than filesystem specifics.
---
Nitpick comments:
In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeServiceTest.java`:
- Around line 130-140: In the definingUriEmptyForPlatformType test method, add
an explicit assertion to verify that typeRef resolves to the expected platform
type kind before the assertThat(uri).isEmpty() assertion. This ensures that if
the test fixture data changes, the test will fail at the kind check with a clear
diagnostic message rather than silently failing at the URI assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: feae3a91-d5ba-4ff7-96c2-fcc6779651ba
📒 Files selected for processing (21)
src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpRootsBootstrapper.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpRootsChangeConsumer.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolSpecificationsBootstrapWrapper.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeMemberDto.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeMemberMetadataDto.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeParameterDto.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/GlobalMemberInfoTool.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/McpToolParams.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/TypeInfoTool.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/types/TypeService.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpHttpServerTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpRootsBootstrapperTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpRootsChangeConsumerTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpSseServerTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpStreamableServerTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolSpecificationsBootstrapWrapperTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolsTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeMemberDtoTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeMemberMetadataDtoTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/dto/TypeParameterDtoTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/types/TypeServiceTest.java
Если у клиента открыто несколько MCP-roots, прежний выбор первого попавшегося workspace в type_info/global_member_info был детерминированно неверным для проектов, где ответ зависит от scope'а: смешанные конфигурация + OneScript, разные конфигурации с разным составом метаданных и т.п. Добавлен опциональный параметр `root`: клиент адресует конкретный workspace по URI из объявленных им roots. Если параметр не задан — старое поведение (любой зарегистрированный workspace), это нормально для платформенных имён. McpWorkspaceResolver — единая точка резолва, который нормализует URI через Absolute.uri (терпим к разным написаниям, включая trailing slash и file://D:\) и кидает осмысленное «No registered workspace matches root: …», если клиент указал URI, под которым ни один workspace не зарегистрирован. Покрыто 6 unit-тестами на сам резолвер и 4 интеграционными в McpToolsTest для type_info и global_member_info (явный root, неизвестный root).
… платформой Windows Тест вытаскивает букву диска из реального filesystem-роута тестовой директории (`path.getRoot().toString().substring(0, 2)` = `D:`), что работоспособно только на Windows: на Unix getRoot() возвращает `/`, выражение даёт нерабочий URI и ассерт валится на ubuntu-latest и macOS-latest. Само правило нормализации `file://D:\path` → `file:///D:/path` остаётся под кросс-платформенным покрытием через три string-теста normalizeWindowsFileUri* рядом с этим тестом — они проверяют логику без зависимости от FS.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/GlobalMemberInfoTool.java (1)
110-113:⚠️ Potential issue | 🟠 Major | ⚡ Quick winFix enum payload kind mismatch in
global_member_inforesponses.For enum lookups,
Result.kindis"ENUM"butmember.kindis hardcoded to"PROPERTY". That creates contradictory API payloads for the same entity. Use thekindargument when constructingTypeMemberDto.Proposed fix
private Result globalValueResult(String requestedName, FileType fileType, TypeRef valueType, String kind, Language language) { @@ var member = new TypeMemberDto( canonicalName, - "PROPERTY", + kind, List.of(valueType.qualifiedName()), description, List.of(), false, null );Also applies to: 127-142
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/GlobalMemberInfoTool.java` around lines 110 - 113, Fix the enum payload kind mismatch where Result.kind is set to "ENUM" but member.kind is hardcoded to "PROPERTY" in the GlobalMemberInfoTool class. In the globalValueResult method call at lines 110-113 (anchor location where "ENUM" is passed as the kind argument), ensure that the kind parameter is properly passed through to the TypeMemberDto constructor instead of being hardcoded to "PROPERTY". Apply the same fix at the sibling locations at lines 127-142 where other member type lookups occur, ensuring that the kind argument provided to the method is consistently used when constructing TypeMemberDto objects rather than hardcoding a value.
🧹 Nitpick comments (1)
src/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolsTest.java (1)
219-283: ⚡ Quick winAdd explicit tests for property/enum branches of
global_member_info.Current tests validate only function resolution. Please add assertions for property and enum responses (including
result.kindandmember.kind) to lock the contract and prevent regressions.As per coding guidelines, “Always run tests before submitting changes and maintain or improve test coverage using appropriate test frameworks (JUnit, AssertJ, Mockito)”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolsTest.java` around lines 219 - 283, Add two new test methods to McpToolsTest to cover property and enum member resolution in the globalMemberInfoTool. Create a test method for property member resolution (following the pattern of globalMemberInfoResolvesPlatformFunction) that calls globalMemberInfoTool.globalMemberInfo with a known property name and asserts that result.kind() matches the expected value and result.member().kind() is correct for properties. Create another test method for enum member resolution using the same pattern with a known enum name. Both tests should include assertions for result.kind() and result.member().kind() to establish and maintain the contract for these member types, ensuring comprehensive coverage beyond the existing function-only tests.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In
`@src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/GlobalMemberInfoTool.java`:
- Around line 110-113: Fix the enum payload kind mismatch where Result.kind is
set to "ENUM" but member.kind is hardcoded to "PROPERTY" in the
GlobalMemberInfoTool class. In the globalValueResult method call at lines
110-113 (anchor location where "ENUM" is passed as the kind argument), ensure
that the kind parameter is properly passed through to the TypeMemberDto
constructor instead of being hardcoded to "PROPERTY". Apply the same fix at the
sibling locations at lines 127-142 where other member type lookups occur,
ensuring that the kind argument provided to the method is consistently used when
constructing TypeMemberDto objects rather than hardcoding a value.
---
Nitpick comments:
In
`@src/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolsTest.java`:
- Around line 219-283: Add two new test methods to McpToolsTest to cover
property and enum member resolution in the globalMemberInfoTool. Create a test
method for property member resolution (following the pattern of
globalMemberInfoResolvesPlatformFunction) that calls
globalMemberInfoTool.globalMemberInfo with a known property name and asserts
that result.kind() matches the expected value and result.member().kind() is
correct for properties. Create another test method for enum member resolution
using the same pattern with a known enum name. Both tests should include
assertions for result.kind() and result.member().kind() to establish and
maintain the contract for these member types, ensuring comprehensive coverage
beyond the existing function-only tests.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 21da46ec-3c30-43b8-8749-672e0e52fdd8
📒 Files selected for processing (6)
src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpWorkspaceResolver.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/GlobalMemberInfoTool.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/McpToolParams.javasrc/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/TypeInfoTool.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpToolsTest.javasrc/test/java/com/github/_1c_syntax/bsl/languageserver/mcp/McpWorkspaceResolverTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/McpToolParams.java
- src/main/java/com/github/_1c_syntax/bsl/languageserver/mcp/tools/TypeInfoTool.java
…info Прежний выбор «любого» workspace при отсутствии root оставлял место для тихо неверных ответов: при нескольких roots (конфигурация + OneScript, разные конфигурации) клиент получал результат из произвольного scope'а без сигнала, что он промахнулся. Параметр `root` теперь required, порядок параметров переставлен так, чтобы все обязательные шли перед опциональными: type_info(typeName, fileType, root, language?) global_member_info(name, fileType, root, language?) McpWorkspaceResolver: убрана мёртвая ветка «root не задан → взять любой» — теперь null/blank сразу даёт IllegalArgumentException «Workspace root is required», ошибка указывает что именно пропущено. Тесты обновлены: WORKSPACE_ROOT-константа подставлена во все вызовы; добавлены кейсы на отсутствующий root и на blank-root.
- McpRootsChangeConsumer.normalizeWindowsFileUri: пометить return как @nullable (S2637, BUG — return null в @NullMarked пакете) и вытащить «file://» в константу FILE_SCHEME_PREFIX (S1192). - McpToolSpecificationsBootstrapWrapper: явный тип параметров лямбды wrapHandler (S2211). - TypeMemberMetadataDto.isEmpty: разбить 8-конъюнктное выражение на три helper'а по группам полей (S1067). - TypeParameterDto.from: убрать `defaultValue == null` / `description == null` — ParameterDescriptor гарантирует non-null оба поля, проверки always-false (S2589). - GlobalMemberInfoTool: functionResult статический (S2325), убран неиспользуемый параметр language у globalValueResult (S1172), `symbol -> symbol.getName()` → `Symbol::getName` (S1612). - Тесты: убран неиспользуемый импорт McpSchema; ListRootsResult, Tool.builder, TextContent, CallToolRequest заменены на не-deprecated формы (S1128, S1874).
|



Summary
Три темы вокруг MCP-режима bsl-language-server.
1. Roots bootstrap
McpRootsBootstrapper— при первом tool-вызове сервер сам шлёт клиентуroots/list, если тот объявилroots-capability вinitialize. По MCP-спеке клиент должен ответить на этот запрос. Без проактивного запроса bsl-ls регистрирует workspace только по уведомлениюnotifications/roots/list_changed, а клиенты (Claude Code 2.1.178 в частности) шлют его только при последующих изменениях roots, а не на инициализацию. Симптом: все workspace-зависимые tools падали с «No registered workspace» сразу после подключения.McpToolSpecificationsBootstrapWrapper—BeanPostProcessorоборачивает каждыйSyncToolSpecificationиз bean'аtoolSpecs, прозрачно вызывая bootstrap перед делегированием в исходныйcallHandler. Существующие@McpTool-методы про bootstrap не знают (diff в них — нулевой).McpRootsChangeConsumer.normalizeWindowsFileUri— фикс под windows-патологию: Claude Code 2.1.178 на Windows шлёт roots видаfile://D:\path\with\backslashes(буква диска как «host» + backslash в path).Absolute.uriтакое не разбирает → root отбрасывается с warn'ом, workspace не регистрируется. Нормализуем до RFC 8089file:///D:/path/with/forward-slashesдо передачи вAbsolute.2. Расширенный
type_infolanguage(RU/EN, default RU): имена, описания, билингв-поля платформенной метаинформации возвращаются на выбранной локали.Result:constructors,events,definedAt(URI исходного файла-объявления для USER/CONFIGURATION).TypeMemberDto: добавленыasyncиmetadata(TypeMemberMetadataDtoсоsinceVersion/deprecatedSinceVersion/recommendedReplacements/availabilities/accessMode/returnValueDescription/notes/examples/seeAlso).TypeParameterDto: добавленыvariadicиdescription.Чтобы получить URI определения без активного
DocumentContext'а (MCP-tool вызывается «снаружи» документа), добавлен публичныйTypeService.definingUri(TypeRef)— лёгкий вариант существующегоdefiningSymbol(TypeRef, DocumentContext).3. Новый MCP-tool
global_member_infoРезолв глобальной функции / свойства / системного перечисления через
GlobalScopeProvider. Для функций возвращает полныйTypeMemberDtoс сигнатурами и метаинформацией; для глобальных свойств/перечислений — упрощённый дескриптор с типом значения и описанием. Покрывает кейсы вроде «расскажи проСообщить/Message», «какой тип уМетаданные», без необходимости открывать конкретный файл.Test plan
TypeMemberMetadataDtoTest,TypeMemberDtoTest,TypeParameterDtoTest— DTO-маппинг (билингв-локаль, blank → null, сортировка, generic-семантика).McpRootsBootstrapperTest— proactivelistRoots, идемпотентность (только раз), отсутствие capability,nullexchange, ошибкаlistRootsswallow, пустой набор.McpToolSpecificationsBootstrapWrapperTest— обёртка другие bean'ы не трогает, не-List не трогает, при обёртке tool-метадата сохраняется, bootstrap вызывается до handler'а, при ошибке bootstrap'а original всё равно выполняется.McpRootsChangeConsumerTest— windows-URI нормализация (изолированный helper + end-to-end сRoot).McpToolsTest— расширен сценариямиtype_info(constructors/events/language/definedAt) и кейсамиglobal_member_info(function / EN alias / unknown / OS file type).TypeServiceTest—definingUriдляPLATFORM/UNKNOWN/ANY(вездеOptional.empty()).McpRootsBootstrapperTest,McpRootsChangeConsumerTest,McpToolsTest,McpHttpServerTest,McpSseServerTest,McpStreamableServerTest,McpToolSpecificationsBootstrapWrapperTest, DTO-тесты,TypeServiceTest).Summary by CodeRabbit
Release Notes
New Features
type_infoto be root/workspace aware and locale aware, including events, constructors, anddefinedAt.Bug Fixes
file://URI normalization for correct path conversion.Tests
Chores