This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 40eb6c9ab677ca0eb185b9155b75cca101697be7
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sat May 23 13:25:44 2026 -0400

    Packaging MCP server as CayenneMCPServer.jar for symmetry with 
CayenneModeler
---
 ai-plugin/README.md                                |  2 +-
 ai-plugin/references/mcp-tools.md                  |  2 +-
 cayenne-mcp-server/README.md                       | 20 +++++++++---------
 cayenne-mcp-server/pom.xml                         |  1 +
 .../org/apache/cayenne/mcp/CayenneMcpMain.java     |  2 +-
 .../mcp/tools/openproject/McpJarLocator.java       | 19 +++++++++++++----
 .../mcp/tools/openproject/ModelerDiscovery.java    | 24 ++++++++++++++++------
 .../mcp/tools/openproject/OpenProjectTool.java     |  9 ++++----
 8 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/ai-plugin/README.md b/ai-plugin/README.md
index 50914756a..a6868a480 100644
--- a/ai-plugin/README.md
+++ b/ai-plugin/README.md
@@ -43,7 +43,7 @@ The plugin is distributed from the Apache Cayenne GitHub 
repository: **https://g
 /plugin install apache-cayenne@apache-cayenne
 
 # Install the MCP server (requires a local CayenneModeler install)
-claude mcp add cayenne --scope user -- java -jar 
/path/to/cayenne-mcp-server-<VERSION>.jar
+claude mcp add cayenne --scope user -- java -jar /path/to/CayenneMCPServer.jar
 ```
 
 Full MCP setup instructions: 
https://cayenne.apache.org/docs/5.0/cayenne-guide/installing-the-cayenne-mcp-server/
diff --git a/ai-plugin/references/mcp-tools.md 
b/ai-plugin/references/mcp-tools.md
index c8ab872bc..f0a61506e 100644
--- a/ai-plugin/references/mcp-tools.md
+++ b/ai-plugin/references/mcp-tools.md
@@ -25,7 +25,7 @@ The Cayenne MCP server (`cayenne-mcp-server` module) exposes 
Cayenne operations
 Setup is documented in `cayenne-mcp-server/README.md` at the repo root. Quick 
form for Claude Code:
 
 ```bash
-claude mcp add cayenne --scope user -- java -jar 
/path/to/cayenne-mcp-server-<VERSION>.jar
+claude mcp add cayenne --scope user -- java -jar /path/to/CayenneMCPServer.jar
 ```
 
 Verify the server is registered with `claude mcp list` — you should see an 
entry named `cayenne` (the MCP server alias from the `claude mcp add cayenne` 
command above) showing as connected. This is unrelated to the plugin name 
`apache-cayenne`.
diff --git a/cayenne-mcp-server/README.md b/cayenne-mcp-server/README.md
index 1464fda16..f776bc550 100644
--- a/cayenne-mcp-server/README.md
+++ b/cayenne-mcp-server/README.md
@@ -14,21 +14,21 @@ Downloads are available at 
https://cayenne.apache.org/download/.
 
 ### macOS (DMG)
 ```
-<install-dir>/CayenneModeler.app/Contents/Resources/mcp/cayenne-mcp-server-<VERSION>.jar
+<install-dir>/CayenneModeler.app/Contents/Resources/mcp/CayenneMCPServer.jar
 
 # But typically, in:
-/Applications/CayenneModeler.app/Contents/Resources/mcp/cayenne-mcp-server-<VERSION>.jar
+/Applications/CayenneModeler.app/Contents/Resources/mcp/CayenneMCPServer.jar
 ```
 
 ### Windows (ZIP)
 ```
-<install-dir>\bin\cayenne-mcp-server-<VERSION>.jar
+<install-dir>\bin\CayenneMCPServer.jar
 ```
 
 ### Linux / cross-platform (tar.gz)
 
 ```
-<install-dir>/bin/cayenne-mcp-server-<VERSION>.jar
+<install-dir>/bin/CayenneMCPServer.jar
 ```
 
 ### Development build (own Cayenne source)
@@ -42,13 +42,13 @@ mvn clean package -pl cayenne-mcp-server -am -DskipTests
 The JAR is then at:
 
 ```
-cayenne-mcp-server/target/cayenne-mcp-server-<VERSION>.jar
+cayenne-mcp-server/target/classes/CayenneMCPServer.jar
 ```
 
 ## Configuring AI clients
 
 The server communicates over **stdio** and is launched on demand by the client.
-Replace `/path/to/cayenne-mcp-server.jar` with the actual path from the 
section above.
+Replace `/path/to/CayenneMCPServer.jar` with the actual path from the section 
above.
 
 ### Claude Code
 
@@ -56,10 +56,10 @@ By default `claude mcp add` registers the server for the 
current project only. U
 
 ```bash
 # Current project only (default)
-claude mcp add cayenne -- java -jar /path/to/cayenne-mcp-server-<VERSION>.jar
+claude mcp add cayenne -- java -jar /path/to/CayenneMCPServer.jar
 
 # All projects for the current user
-claude mcp add cayenne --scope user -- java -jar 
/path/to/cayenne-mcp-server-<VERSION>.jar
+claude mcp add cayenne --scope user -- java -jar /path/to/CayenneMCPServer.jar
 ```
 
 ### Cursor
@@ -71,7 +71,7 @@ Edit `~/.cursor/mcp.json` (global, all projects) or 
`.cursor/mcp.json` in your p
   "mcpServers": {
     "cayenne": {
       "command": "java",
-      "args": ["-jar", "/path/to/cayenne-mcp-server-<VERSION>.jar"]
+      "args": ["-jar", "/path/to/CayenneMCPServer.jar"]
     }
   }
 }
@@ -87,7 +87,7 @@ Add to `.vscode/mcp.json` in your project (per-project), or 
to your user `mcp.js
     "cayenne": {
       "type": "stdio",
       "command": "java",
-      "args": ["-jar", "/path/to/cayenne-mcp-server-<VERSION>.jar"]
+      "args": ["-jar", "/path/to/CayenneMCPServer.jar"]
     }
   }
 }
diff --git a/cayenne-mcp-server/pom.xml b/cayenne-mcp-server/pom.xml
index 7eca6077f..7df0f20c0 100644
--- a/cayenne-mcp-server/pom.xml
+++ b/cayenne-mcp-server/pom.xml
@@ -76,6 +76,7 @@
     </dependencies>
 
     <build>
+        <finalName>CayenneMCPServer</finalName>
         <plugins>
 
             <plugin>
diff --git 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpMain.java 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpMain.java
index cb6fcfa0e..045a2e98d 100644
--- 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpMain.java
+++ 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/CayenneMcpMain.java
@@ -33,7 +33,7 @@ public class CayenneMcpMain {
         String version = version();
 
         if (opts.isHelp()) {
-            System.err.println("Usage: java -jar cayenne-mcp-server.jar 
[options]");
+            System.err.println("Usage: java -jar CayenneMCPServer.jar 
[options]");
             System.err.println();
             System.err.println("Options:");
             System.err.println("  -h, --help     Print this help and exit.");
diff --git 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/McpJarLocator.java
 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/McpJarLocator.java
index 4b6085a07..3d0902eac 100644
--- 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/McpJarLocator.java
+++ 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/McpJarLocator.java
@@ -20,6 +20,7 @@ package org.apache.cayenne.mcp.tools.openproject;
 
 import java.net.URL;
 import java.net.URISyntaxException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.CodeSource;
@@ -34,15 +35,21 @@ import java.util.Optional;
  */
 final class McpJarLocator {
 
+    /** Canonical name of the MCP server jar in a distribution (outside of dev 
builds). */
+    static final String MCP_JAR_NAME = "CayenneMCPServer.jar";
+
+    record Located(Path dir, boolean isDistribution) {}
+
     private McpJarLocator() {
     }
 
     /**
      * Locates the directory containing the jar (or class output dir) the 
given class
-     * was loaded from. Returns {@code Optional.empty()} in exotic launch 
configurations
-     * where the protection domain has no resolvable location.
+     * was loaded from, and whether that jar is the canonical distribution jar
+     * ({@value #MCP_JAR_NAME}). Returns {@code Optional.empty()} in exotic 
launch
+     * configurations where the protection domain has no resolvable location.
      */
-    static Optional<Path> locate(Class<?> anchor) {
+    static Optional<Located> locate(Class<?> anchor) {
         try {
             ProtectionDomain pd = anchor.getProtectionDomain();
             if (pd == null) {
@@ -61,7 +68,11 @@ final class McpJarLocator {
             // For a class-file directory (IDE / surefire fork): location is 
the dir;
             // its parent is also a reasonable starting point (target/), but 
here we
             // want the dir that "would have been the jar's parent" — so use 
it directly.
-            return Optional.of(location.getParent() != null ? 
location.getParent() : location);
+            boolean isDistribution = Files.isRegularFile(location)
+                    && MCP_JAR_NAME.equals(location.getFileName() != null
+                            ? location.getFileName().toString() : "");
+            Path dir = location.getParent() != null ? location.getParent() : 
location;
+            return Optional.of(new Located(dir, isDistribution));
         } catch (URISyntaxException | RuntimeException e) {
             return Optional.empty();
         }
diff --git 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/ModelerDiscovery.java
 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/ModelerDiscovery.java
index d7cf007b0..56a3b8590 100644
--- 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/ModelerDiscovery.java
+++ 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/ModelerDiscovery.java
@@ -54,6 +54,16 @@ final class ModelerDiscovery {
     }
 
     static DiscoveryResult discover(Path mcpDir, OsKind osKind) {
+        return discover(mcpDir, osKind, false);
+    }
+
+    /**
+     * @param isDistributionJar {@code true} when the MCP server is running 
from
+     *   {@value McpJarLocator#MCP_JAR_NAME} — a distribution build. When 
{@code true},
+     *   the source-tree fallback is skipped: a production jar should not 
accidentally
+     *   pick up a developer Modeler build.
+     */
+    static DiscoveryResult discover(Path mcpDir, OsKind osKind, boolean 
isDistributionJar) {
         List<String> notes = new ArrayList<>();
 
         if (osKind == OsKind.MAC) {
@@ -78,13 +88,15 @@ final class ModelerDiscovery {
         }
         notes.add("generic: no " + GENERIC_JAR_NAME + " sibling of the MCP 
jar");
 
-        Optional<Found> sourceTree = probeSourceTree(mcpDir, osKind);
-        if (sourceTree.isPresent()) {
-            return sourceTree.get();
+        if (!isDistributionJar) {
+            Optional<Found> sourceTree = probeSourceTree(mcpDir, osKind);
+            if (sourceTree.isPresent()) {
+                return sourceTree.get();
+            }
+            notes.add("""
+                      source_tree: no built CayenneModeler under 
<gitRoot>/modeler/cayenne-modeler-{mac,win,generic}/target/classes/ \
+                      (run `mvn -pl modeler/cayenne-modeler-<kind> -am package 
-P<kind>`)""");
         }
-        notes.add("""
-                  source_tree: no built CayenneModeler under 
<gitRoot>/modeler/cayenne-modeler-{mac,win,generic}/target/classes/ \
-                  (run `mvn -pl modeler/cayenne-modeler-<kind> -am package 
-P<kind>`)""");
 
         return new NotFound(List.copyOf(notes));
     }
diff --git 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java
 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java
index 6ab3e75d7..ced9e3a21 100644
--- 
a/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java
+++ 
b/cayenne-mcp-server/src/main/java/org/apache/cayenne/mcp/tools/openproject/OpenProjectTool.java
@@ -123,21 +123,22 @@ public class OpenProjectTool {
         }
 
         // Step 2 — locate the MCP jar's directory.
-        Optional<Path> mcpDir = McpJarLocator.locate(OpenProjectTool.class);
-        if (mcpDir.isEmpty()) {
+        Optional<McpJarLocator.Located> mcpLocated = 
McpJarLocator.locate(OpenProjectTool.class);
+        if (mcpLocated.isEmpty()) {
             return 
validationFailed(OpenProjectErrorCode.mcp_jar_location_unresolved,
                     "Could not resolve the running MCP server jar's location",
                     new OpenProjectValidation(true, false, null));
         }
+        McpJarLocator.Located mcp = mcpLocated.get();
 
         // Step 3 — discover a Modeler installation.
         OsKind osKind = OsKind.detect();
-        DiscoveryResult discovery = ModelerDiscovery.discover(mcpDir.get(), 
osKind);
+        DiscoveryResult discovery = ModelerDiscovery.discover(mcp.dir(), 
osKind, mcp.isDistribution());
         return switch (discovery) {
             case Found f -> launchAndAwait(f, projectFile);
             case NotFound nf -> 
validationFailed(OpenProjectErrorCode.modeler_not_found,
                     "No CayenneModeler installation found relative to MCP jar 
at %s. Probes: %s"
-                            .formatted(mcpDir.get(), String.join("; ", 
nf.probeNotes())),
+                            .formatted(mcp.dir(), String.join("; ", 
nf.probeNotes())),
                     new OpenProjectValidation(true, true, false));
         };
     }

Reply via email to