Skip to content

Commit 0750cc8

Browse files
committed
Allow MCP to work without connected LSP
Signed-off-by: BoykoAlex <alex.boyko@broadcom.com>
1 parent 25e82cb commit 0750cc8

4 files changed

Lines changed: 87 additions & 13 deletions

File tree

claude-plugins/spring-boot/launcher.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const javaArgs = [
2727
"-Dspring.ai.mcp.server.stdio=true",
2828
"-Dlanguageserver.standalone=true",
2929
"-Dlanguageserver.standalone-port=5007",
30+
`-Dspring.boot.ls.project.dir=${process.env.CLAUDE_PROJECT_DIR || process.cwd()}`,
3031
"-jar",
3132
jarPath
3233
];

headless-services/commons/commons-gradle/src/main/java/org/springframework/ide/vscode/commons/gradle/GradleCore.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ public interface GradleCoreProject {
4444
BuildEnvironment getBuildEnvironment();
4545
}
4646

47-
static final String GRADLE_BUILD_FILE = "build.gradle";
47+
public static final String GRADLE_BUILD_FILE = "build.gradle";
48+
public static final String GRADLE_KTS_BUILD_FILE = "build.gradle.kts";
4849

4950
static final String GLOB_GRADLE_FILE = "**/*.gradle";
5051

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/LspProgressClient.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,16 @@ class LspProgressClient implements ProgressClient {
5858
this.clientSupplier = clientSupplier;
5959
}
6060

61-
private STS4LanguageClient requireClient() {
62-
STS4LanguageClient client = clientSupplier.get();
63-
if (client == null) {
64-
throw new IllegalStateException("Language client is not connected. Progress notifications require an active client connection.");
65-
}
66-
return client;
61+
private STS4LanguageClient getClient() {
62+
return clientSupplier.get();
6763
}
6864

6965
@Override
7066
public void begin(String taskId, WorkDoneProgressBegin report) {
71-
STS4LanguageClient client = requireClient();
67+
STS4LanguageClient client = getClient();
68+
if (client == null) {
69+
return;
70+
}
7271

7372
boolean isNew = activeTaskIDs.put(taskId, true) == null;
7473
if (!isNew) {
@@ -89,7 +88,10 @@ public void begin(String taskId, WorkDoneProgressBegin report) {
8988

9089
@Override
9190
public void report(String taskId, WorkDoneProgressReport report) {
92-
STS4LanguageClient client = requireClient();
91+
STS4LanguageClient client = getClient();
92+
if (client == null) {
93+
return;
94+
}
9395

9496
if (!activeTaskIDs.containsKey(taskId)) {
9597
log.error("Progress for task id '{}' does NOT exist!", taskId);
@@ -104,7 +106,10 @@ public void report(String taskId, WorkDoneProgressReport report) {
104106

105107
@Override
106108
public void end(String taskId, WorkDoneProgressEnd report) {
107-
STS4LanguageClient client = requireClient();
109+
STS4LanguageClient client = getClient();
110+
if (client == null) {
111+
return;
112+
}
108113
if (activeTaskIDs.remove(taskId) == null) {
109114
return;
110115
}

headless-services/spring-boot-language-server-standalone/src/main/java/org/springframework/ide/vscode/boot/app/LegacyJavaProjectsService.java

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import java.util.Optional;
1717

1818
import org.eclipse.lsp4j.TextDocumentIdentifier;
19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
21+
import org.springframework.beans.factory.InitializingBean;
1922
import org.springframework.ide.vscode.boot.jdt.ls.JavaProjectsService;
2023
import org.springframework.ide.vscode.commons.gradle.GradleCore;
2124
import org.springframework.ide.vscode.commons.gradle.GradleProjectCache;
@@ -41,17 +44,25 @@
4144
* Its presence on the classpath causes {@link BootLanguageServerBootApp} to skip creating
4245
* the JDT-LS-backed {@code JavaProjectsService} bean.
4346
*/
44-
public class LegacyJavaProjectsService implements JavaProjectsService {
47+
public class LegacyJavaProjectsService implements JavaProjectsService, InitializingBean {
48+
49+
private static final Logger log = LoggerFactory.getLogger(LegacyJavaProjectsService.class);
50+
51+
private static final java.util.Set<String> IGNORED_DIRECTORIES = java.util.Set.of(
52+
"target", "node_modules", "build", ".git", "bin"
53+
);
4554

4655
private final CompositeJavaProjectFinder projectFinder;
4756
private final CompositeProjectOvserver projectObserver;
57+
private final MavenProjectCache mavenProjectCache;
58+
private final GradleProjectCache gradleProjectCache;
4859

4960
public LegacyJavaProjectsService(SimpleLanguageServer server) {
50-
MavenProjectCache mavenProjectCache = new MavenProjectCache(server, MavenCore.getDefault(), false, null,
61+
this.mavenProjectCache = new MavenProjectCache(server, MavenCore.getDefault(), false, null,
5162
(uri, cpe) -> JavaDocProviders.createFor(cpe));
5263
mavenProjectCache.setAlwaysFireEventOnFileChanged(true);
5364

54-
GradleProjectCache gradleProjectCache = new GradleProjectCache(server, GradleCore.getDefault(), false, null,
65+
this.gradleProjectCache = new GradleProjectCache(server, GradleCore.getDefault(), false, null,
5566
(uri, cpe) -> JavaDocProviders.createFor(cpe));
5667
gradleProjectCache.setAlwaysFireEventOnFileChanged(true);
5768

@@ -62,6 +73,14 @@ public LegacyJavaProjectsService(SimpleLanguageServer server) {
6273
this.projectObserver = new CompositeProjectOvserver(Arrays.asList(mavenProjectCache, gradleProjectCache));
6374
}
6475

76+
@Override
77+
public void afterPropertiesSet() throws Exception {
78+
String projectDir = System.getProperty("spring.boot.ls.project.dir");
79+
if (projectDir != null && !projectDir.isEmpty()) {
80+
initializeProject(new java.io.File(projectDir));
81+
}
82+
}
83+
6584
@Override
6685
public Optional<IJavaProject> find(TextDocumentIdentifier doc) {
6786
return projectFinder.find(doc);
@@ -87,6 +106,54 @@ public boolean isSupported() {
87106
return projectObserver.isSupported();
88107
}
89108

109+
public void initializeProject(java.io.File projectRoot) {
110+
if (projectRoot == null || !projectRoot.exists() || !projectRoot.isDirectory()) {
111+
return;
112+
}
113+
log.info("Initializing workspace project directory: {}", projectRoot.getAbsolutePath());
114+
try {
115+
java.nio.file.Files.walkFileTree(projectRoot.toPath(), java.util.EnumSet.noneOf(java.nio.file.FileVisitOption.class), 10, new java.nio.file.SimpleFileVisitor<java.nio.file.Path>() {
116+
@Override
117+
public java.nio.file.FileVisitResult preVisitDirectory(java.nio.file.Path dir, java.nio.file.attribute.BasicFileAttributes attrs) {
118+
String name = dir.getFileName().toString();
119+
if (IGNORED_DIRECTORIES.contains(name)) {
120+
return java.nio.file.FileVisitResult.SKIP_SUBTREE;
121+
}
122+
123+
java.io.File dirFile = dir.toFile();
124+
java.io.File pomFile = new java.io.File(dirFile, MavenCore.POM_XML);
125+
if (pomFile.exists() && pomFile.isFile()) {
126+
log.info("Found Maven project: {}", pomFile.getAbsolutePath());
127+
mavenProjectCache.project(pomFile);
128+
return java.nio.file.FileVisitResult.SKIP_SUBTREE;
129+
}
130+
131+
java.io.File gradleFile = new java.io.File(dirFile, GradleCore.GRADLE_BUILD_FILE);
132+
if (gradleFile.exists() && gradleFile.isFile()) {
133+
log.info("Found Gradle project: {}", gradleFile.getAbsolutePath());
134+
gradleProjectCache.project(gradleFile);
135+
return java.nio.file.FileVisitResult.SKIP_SUBTREE;
136+
}
137+
138+
java.io.File gradleKtsFile = new java.io.File(dirFile, GradleCore.GRADLE_KTS_BUILD_FILE);
139+
if (gradleKtsFile.exists() && gradleKtsFile.isFile()) {
140+
log.info("Found Gradle Kotlin project: {}", gradleKtsFile.getAbsolutePath());
141+
gradleProjectCache.project(gradleKtsFile);
142+
return java.nio.file.FileVisitResult.SKIP_SUBTREE;
143+
}
144+
145+
return java.nio.file.FileVisitResult.CONTINUE;
146+
}
147+
@Override
148+
public java.nio.file.FileVisitResult visitFileFailed(java.nio.file.Path file, java.io.IOException exc) {
149+
return java.nio.file.FileVisitResult.CONTINUE;
150+
}
151+
});
152+
} catch (Exception e) {
153+
// ignore
154+
}
155+
}
156+
90157
@Override
91158
public IJavadocProvider javadocProvider(URI projectUri, CPE classpathEntry) {
92159
return JavaDocProviders.createFor(classpathEntry);

0 commit comments

Comments
 (0)