Skip to content

Commit f5de79a

Browse files
committed
feat: add java init framework
Signed-off-by: ankittk <ankit.kumar@getweave.com>
1 parent 41071d1 commit f5de79a

25 files changed

Lines changed: 1734 additions & 14 deletions

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cli/internal/build/build.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ func (b *Builder) Build(opts Options) error {
5252
return b.buildDockerImage(opts, "node")
5353
case "go":
5454
return b.buildDockerImage(opts, "go")
55+
case "java":
56+
return b.buildDockerImage(opts, "java")
5557
default:
5658
return fmt.Errorf("unsupported project type: %s", projectType)
5759
}
@@ -77,6 +79,11 @@ func (b *Builder) detectProjectType(dir string) (string, error) {
7779
return "go", nil
7880
}
7981

82+
// Check for Java project
83+
if b.fileExists(filepath.Join(dir, "pom.xml")) {
84+
return "java", nil
85+
}
86+
8087
return "", fmt.Errorf("unknown project type")
8188
}
8289

pkg/cli/internal/commands/deploy.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import (
88
"strings"
99
"time"
1010

11-
"github.com/kagent-dev/kmcp/api/v1alpha1"
12-
"github.com/kagent-dev/kmcp/pkg/cli/internal/manifest"
1311
"github.com/spf13/cobra"
1412
corev1 "k8s.io/api/core/v1"
1513
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1614
"sigs.k8s.io/yaml"
15+
16+
"github.com/kagent-dev/kmcp/api/v1alpha1"
17+
"github.com/kagent-dev/kmcp/pkg/cli/internal/manifest"
1718
)
1819

1920
const (
@@ -511,6 +512,8 @@ func getDefaultCommand(framework string) string {
511512
return "./server"
512513
case manifest.FrameworkTypeScript:
513514
return "node"
515+
case manifest.FrameworkJava:
516+
return "java"
514517
default:
515518
return "python"
516519
}
@@ -527,6 +530,11 @@ func getDefaultArgs(framework string, targetPort int) []string {
527530
return []string{}
528531
case manifest.FrameworkTypeScript:
529532
return []string{"dist/index.js"}
533+
case manifest.FrameworkJava:
534+
if deployTransport == transportHTTP {
535+
return []string{"-jar", "app.jar", "--transport", "http", "--host", "0.0.0.0", "--port", fmt.Sprintf("%d", targetPort)}
536+
}
537+
return []string{"-jar", "app.jar"}
530538
default:
531539
return []string{"src/main.py"}
532540
}

pkg/cli/internal/commands/init.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ import (
88
"regexp"
99
"strings"
1010

11+
"github.com/spf13/cobra"
12+
1113
"github.com/kagent-dev/kmcp/pkg/cli/internal/frameworks"
1214
"github.com/kagent-dev/kmcp/pkg/cli/internal/manifest"
1315
"github.com/kagent-dev/kmcp/pkg/cli/internal/templates"
14-
15-
"github.com/spf13/cobra"
1616
)
1717

1818
const (
1919
frameworkFastMCPPython = "fastmcp-python"
2020
frameworkMCPGo = "mcp-go"
2121
frameworkTypeScript = "typescript"
22+
frameworkJava = "java"
2223
)
2324

2425
var initCmd = &cobra.Command{
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package commands
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var initJavaCmd = &cobra.Command{
10+
Use: "java [project-name]",
11+
Short: "Initialize a new Java MCP server project",
12+
Long: `Initialize a new MCP server project using the Java framework.
13+
14+
This command will create a new directory with a basic Java MCP project structure,
15+
including a pom.xml file, Maven project structure, and an example tool.`,
16+
Args: cobra.ExactArgs(1),
17+
RunE: runInitJava,
18+
}
19+
20+
func init() {
21+
initCmd.AddCommand(initJavaCmd)
22+
}
23+
24+
func runInitJava(_ *cobra.Command, args []string) error {
25+
projectName := args[0]
26+
framework := frameworkJava
27+
28+
if err := runInitFramework(projectName, framework, nil); err != nil {
29+
return err
30+
}
31+
32+
fmt.Printf("✓ Successfully created Java MCP server project: %s\n", projectName)
33+
fmt.Printf("\nNext steps:\n")
34+
fmt.Printf("1. cd %s\n", projectName)
35+
fmt.Printf("2. mvn clean install\n")
36+
fmt.Printf("3. mvn exec:java -Dexec.mainClass=\"com.example.Main\"\n")
37+
fmt.Printf("4. Add tools with: kmcp add-tool my-tool\n")
38+
return nil
39+
}

pkg/cli/internal/commands/run.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import (
66
"os/exec"
77
"path/filepath"
88

9-
"github.com/kagent-dev/kmcp/pkg/cli/internal/manifest"
109
"github.com/spf13/cobra"
10+
11+
"github.com/kagent-dev/kmcp/pkg/cli/internal/manifest"
1112
)
1213

1314
var runCmd = &cobra.Command{
@@ -82,6 +83,8 @@ func executeRun(_ *cobra.Command, _ []string) error {
8283
return runMCPGo(projectDir, manifest)
8384
case "typescript":
8485
return runTypeScript(projectDir, manifest)
86+
case "java":
87+
return runJava(projectDir, manifest)
8588
default:
8689
return fmt.Errorf("unsupported framework: %s", manifest.Framework)
8790
}
@@ -279,3 +282,52 @@ func runTypeScript(projectDir string, manifest *manifest.ProjectManifest) error
279282
// Run the inspector
280283
return runMCPInspector(configPath, manifest.Name, projectDir)
281284
}
285+
286+
func runJava(projectDir string, manifest *manifest.ProjectManifest) error {
287+
// Check if mvn is available
288+
if _, err := exec.LookPath("mvn"); err != nil {
289+
mvnInstallURL := "https://maven.apache.org/install.html"
290+
return fmt.Errorf("mvn is required to run Java projects locally. Please install Maven: %s", mvnInstallURL)
291+
}
292+
293+
// Run mvn clean install first to ensure dependencies are up to date
294+
if Verbose {
295+
fmt.Printf("Running mvn clean install in: %s\n", projectDir)
296+
}
297+
installCmd := exec.Command("mvn", "clean", "install", "-DskipTests")
298+
installCmd.Dir = projectDir
299+
installCmd.Stdout = os.Stdout
300+
installCmd.Stderr = os.Stderr
301+
if err := installCmd.Run(); err != nil {
302+
return fmt.Errorf("failed to run mvn clean install: %w", err)
303+
}
304+
305+
if noInspector {
306+
// Run the server directly
307+
fmt.Printf("Running server directly: mvn exec:java -Dexec.mainClass=\"com.example.Main\"\n")
308+
fmt.Printf("Server is running and waiting for MCP protocol input on stdin...\n")
309+
fmt.Printf("Press Ctrl+C to stop the server\n")
310+
311+
serverCmd := exec.Command("mvn", "exec:java", "-Dexec.mainClass=com.example.Main")
312+
serverCmd.Dir = projectDir
313+
serverCmd.Stdout = os.Stdout
314+
serverCmd.Stderr = os.Stderr
315+
serverCmd.Stdin = os.Stdin
316+
return serverCmd.Run()
317+
}
318+
319+
// Create server configuration for inspector
320+
serverConfig := map[string]interface{}{
321+
"command": "mvn",
322+
"args": []string{"exec:java", "-Dexec.mainClass=com.example.Main"},
323+
}
324+
325+
// Create MCP inspector config
326+
configPath := filepath.Join(projectDir, "mcp-server-config.json")
327+
if err := createMCPInspectorConfig(manifest.Name, serverConfig, configPath); err != nil {
328+
return err
329+
}
330+
331+
// Run the inspector
332+
return runMCPInspector(configPath, manifest.Name, projectDir)
333+
}

pkg/cli/internal/frameworks/common/base_generator.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import (
1010
"text/template"
1111

1212
"github.com/stoewer/go-strcase"
13-
14-
"github.com/kagent-dev/kmcp/pkg/cli/internal/templates"
1513
"golang.org/x/text/cases"
1614
"golang.org/x/text/language"
15+
16+
"github.com/kagent-dev/kmcp/pkg/cli/internal/templates"
1717
)
1818

1919
// Base Generator for MCP projects
@@ -128,13 +128,15 @@ func (g *BaseGenerator) GenerateTool(projectRoot string, config templates.ToolCo
128128
func (g *BaseGenerator) GenerateToolFile(filePath string, config templates.ToolConfig) error {
129129
// Prepare template data
130130
toolName := config.ToolName
131+
toolNamePascalCase := cases.Title(language.English).String(toolName)
131132
data := map[string]interface{}{
132-
"ToolName": toolName,
133-
"ToolNameTitle": cases.Title(language.English).String(toolName),
134-
"ToolNameUpper": strings.ToUpper(toolName),
135-
"ToolNameLower": strings.ToLower(toolName),
136-
"ClassName": cases.Title(language.English).String(toolName) + "Tool",
137-
"Description": config.Description,
133+
"ToolName": toolName,
134+
"ToolNameTitle": cases.Title(language.English).String(toolName),
135+
"ToolNameUpper": strings.ToUpper(toolName),
136+
"ToolNameLower": strings.ToLower(toolName),
137+
"ToolNamePascalCase": toolNamePascalCase,
138+
"ClassName": cases.Title(language.English).String(toolName) + "Tool",
139+
"Description": config.Description,
138140
}
139141

140142
// Create the directory if it doesn't exist

pkg/cli/internal/frameworks/frameworks.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55

66
"github.com/kagent-dev/kmcp/pkg/cli/internal/frameworks/golang"
7+
"github.com/kagent-dev/kmcp/pkg/cli/internal/frameworks/java"
78
"github.com/kagent-dev/kmcp/pkg/cli/internal/frameworks/python"
89
"github.com/kagent-dev/kmcp/pkg/cli/internal/frameworks/typescript"
910
"github.com/kagent-dev/kmcp/pkg/cli/internal/templates"
@@ -25,6 +26,8 @@ func GetGenerator(framework string) (Generator, error) {
2526
return golang.NewGenerator(), nil
2627
case "typescript":
2728
return typescript.NewGenerator(), nil
29+
case "java":
30+
return java.NewGenerator(), nil
2831
default:
2932
return nil, fmt.Errorf("unsupported framework: %s", framework)
3033
}

0 commit comments

Comments
 (0)