Invalid Automatic-Module-Name in mcp-core
Opened this issue ยท 6 comments
Hey there,
Just upgraded to 0.13.0 and ran into an invalid module name.
Current value:
Automatic-Module-Name:io.modelcontextprotocol.sdk.mcp-core
Module names may not contain dashes, so this should be:
Automatic-Module-Name:io.modelcontextprotocol.sdk.mcp.core
Can anybody fix this issue please? It is blocking updates from 0.12.1 to 0.13.0+ whenever people are using java modules
Seeing this as well (while building my https://github.com/enola-dev/enola and the https://github.com/bazel-contrib/rules_jvm_external tool logging the following message; but it's not specific to that build tool, but to this library, as reported in this issue):
INFO: From Creating compile jar for @@rules_jvm_external++maven+maven//:io_modelcontextprotocol_sdk_mcp_core: Automatic module name 'io.modelcontextprotocol.sdk.mcp-core' contains a character ('-') that may not be used in a java identifier: processed_mcp-core-0.14.1.jar
It looks like that Automatic-Module-Name is generated here. That seems wrong, and perhaps a PR to change and simply hard-code io.modelcontextprotocol.sdk.mcp.core instead of ${project.groupId}.${project.artifactId} would do the trick?
What surprises me is that the other (new, recently introduced) Maven artifacts mcp-json etc. don't even use the bnd-maven-plugin. So I am not sure that this library (as-is in 1.4.1) would fully work with Java modules, anyways; this might need a bit more work.
But I'm not actually using Java modules myself (just saw that message), so leaving this to someone more incentivized.
Hire my services if would like me to take care of this! ๐
That seems wrong, and perhaps a PR to change and simply hard-code io.modelcontextprotocol.sdk.mcp.core instead of ${project.groupId}.${project.artifactId} would do the trick?
Yup, that's exactly what my pull request does (#609), now we just cross our fingers for it to be merged. ๐
What surprises me is that the other (new, recently introduced) Maven artifacts mcp-json etc. don't even use the bnd-maven-plugin
The "mcp-core" jar includes all the classes from "mcp-json". I was never sure if this was a bug or a feature but as of right now you simply do not need "mcp-json".
Concerning other jars not using bnd-maven-plugin, see #562
Would be good to prioritize fixing this issue, breaks any downstream that is using Java Modules (--module-path). We are currently blocked from taking any version newer than 0.12.1.
I would recommend that as a modern and popular library this SDK should embrace Java Modules and use module-info.java. The UX of consuming this SDK in applications using Java Modules is sub-optimal because downstream module declarations end up having to add requires clauses for the onward dependencies of the SDK. If the SDK used module-info.java which had requires clauses this would not be necessary. See below for example of the verbosity/fragility imposed on downstream Java Modules due to this SDK not having its own module-info.java
To protect against this issue recurring a testcase should be added to confirm that the produced artefacts can be consumed as Java Modules. This would be a build time test, incorporated into the Maven build. If something regresses then this testcase would fail the build.
Below is a sample minimal project that could form the basis of this test:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mcp-jpms</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>21</maven.compiler.release>
<compiler.version>3.14.1</compiler.version>
<exec.version>3.6.1</exec.version>
<mcp.version>0.12.1</mcp.version>
<slf4j.version>2.0.16</slf4j.version>
<module.name>org.example.mcp.jpms</module.name>
<module.main.class>${module.name}.McpInJavaModule</module.main.class>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
<version>${mcp.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler.version}</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>--module-path</argument>
<modulepath/>
<argument>--module</argument>
<argument>${module.name}/${module.main.class}</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>src/main/java/module-info.java
module org.example.mcp.jpms {
requires io.modelcontextprotocol.sdk.mcp;
// require modules that MCP depends on
requires org.slf4j;
requires org.slf4j.simple;
requires reactor.core;
requires com.networknt.schema;
requires com.fasterxml.jackson.databind;
}- Note how this module has to figure out and declare all the modules which
io.modelcontextprotocol.sdk.mcpdepends on and addrequiresclauses for them. This is the disadvantage of just usingAutomatic-Module-Name. Since this SDK has multiple dependencies, it would be better if it usedmodule-info.javato declare its module name and userequiresclauses to add its dependencies to the module graph.
src/main/java/org/example/mcp/jpms/McpInJavaModule.java
package org.example.mcp.jpms;
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
public class McpInJavaModule {
private static final Logger LOGGER = LoggerFactory.getLogger(McpInJavaModule.class);
public static void main(String... args) {
// If this compiles then Java Module config is good
final var params =
ServerParameters.builder("npx")
.args("-y", "@modelcontextprotocol/server-everything", "dir")
.build();
final var transport = new StdioClientTransport(params);
McpClient.sync(transport).requestTimeout(Duration.ofSeconds(10)).build();
LOGGER.info("Mcp SDK working with Java modules");
}
}Here's a workaround for Gradle based builds.
Using the Extra Java Module Info Gradle plugin.
plugins {
id("org.gradlex.extra-java-module-info")
}
dependencies {
implementation("io.modelcontextprotocol.sdk:mcp-core:0.15.0")
}
extraJavaModuleInfo {
module("io.modelcontextprotocol.sdk:mcp-core", "io.modelcontextprotocol.sdk.mcp.core") {
overrideModuleName()
}
automaticModule("io.modelcontextprotocol.sdk:mcp-json", "io.modelcontextprotocol.sdk.mcp.json")
}