Labsco
github logo

java-mcp-server-generator

✓ Official36,200

by github · part of github/awesome-copilot

Generate production-ready MCP servers in Java with the official SDK, Maven or Gradle, and reactive streams. Scaffolds complete project structure with tools, resources, and prompts organized into separate handler classes Includes Maven and Gradle templates with MCP SDK, SLF4J logging, Project Reactor, and JUnit 5 dependencies Provides ready-to-use handler templates for tools, resources, and prompts with error handling and async Mono-based responses Generates test suite examples and Claude...

🔥🔥🔥🔥✓ VerifiedFreeAdvanced setup
🧩 One of 7 skills in the github/awesome-copilot package — works on its own, and pairs well with its siblings.

Generate production-ready MCP servers in Java with the official SDK, Maven or Gradle, and reactive streams. Scaffolds complete project structure with tools, resources, and prompts organized into separate handler classes Includes Maven and Gradle templates with MCP SDK, SLF4J logging, Project Reactor, and JUnit 5 dependencies Provides ready-to-use handler templates for tools, resources, and prompts with error handling and async Mono-based responses Generates test suite examples and Claude...

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates — shown here so you can audit it before installing. You don't need to read it to use the skill.

by github

Generate production-ready MCP servers in Java with the official SDK, Maven or Gradle, and reactive streams. Scaffolds complete project structure with tools, resources, and prompts organized into separate handler classes Includes Maven and Gradle templates with MCP SDK, SLF4J logging, Project Reactor, and JUnit 5 dependencies Provides ready-to-use handler templates for tools, resources, and prompts with error handling and async Mono-based responses Generates test suite examples and Claude... npx skills add https://github.com/github/awesome-copilot --skill java-mcp-server-generator Download ZIPGitHub36.2k

Java MCP Server Generator

Generate a complete, production-ready MCP server in Java using the official Java SDK with Maven or Gradle.

Project Generation

When asked to create a Java MCP server, generate a complete project with this structure:

Copy & paste — that's it
my-mcp-server/
├── pom.xml (or build.gradle.kts)
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/mcp/
│ │ │ ├── McpServerApplication.java
│ │ │ ├── config/
│ │ │ │ └── ServerConfiguration.java
│ │ │ ├── tools/
│ │ │ │ ├── ToolDefinitions.java
│ │ │ │ └── ToolHandlers.java
│ │ │ ├── resources/
│ │ │ │ ├── ResourceDefinitions.java
│ │ │ │ └── ResourceHandlers.java
│ │ │ └── prompts/
│ │ │ ├── PromptDefinitions.java
│ │ │ └── PromptHandlers.java
│ │ └── resources/
│ │ └── application.properties (if using Spring)
│ └── test/
│ └── java/
│ └── com/example/mcp/
│ └── McpServerTest.java
└── README.md

Maven pom.xml Template

Copy & paste — that's it
 
 
 4.0.0 

 com.example 
 my-mcp-server 
 1.0.0 
 jar 

 My MCP Server 
 Model Context Protocol server implementation 

 
 17 
 17 
 17 
 UTF-8 
 0.14.1 
 2.0.9 
 1.4.11 
 5.10.0 
 

 
 
 
 io.modelcontextprotocol.sdk 
 mcp 
 ${mcp.version} 
 

 
 
 org.slf4j 
 slf4j-api 
 ${slf4j.version} 
 
 
 ch.qos.logback 
 logback-classic 
 ${logback.version} 
 

 
 
 org.junit.jupiter 
 junit-jupiter 
 ${junit.version} 
 test 
 
 
 io.projectreactor 
 reactor-test 
 test 
 
 

 
 
 
 org.apache.maven.plugins 
 maven-compiler-plugin 
 3.11.0 
 
 
 org.apache.maven.plugins 
 maven-surefire-plugin 
 3.1.2 
 
 
 org.apache.maven.plugins 
 maven-shade-plugin 
 3.5.0 
 
 
 package 
 
 shade 
 
 
 
 
 com.example.mcp.McpServerApplication 
 
 
 
 
 
 
 
 
 

Gradle build.gradle.kts Template

Copy & paste — that's it
plugins {
 id("java")
 id("application")
}

group = "com.example"
version = "1.0.0"

java {
 sourceCompatibility = JavaVersion.VERSION_17
 targetCompatibility = JavaVersion.VERSION_17
}

repositories {
 mavenCentral()
}

dependencies {
 // MCP Java SDK
 implementation("io.modelcontextprotocol.sdk:mcp:0.14.1")
 
 // Logging
 implementation("org.slf4j:slf4j-api:2.0.9")
 implementation("ch.qos.logback:logback-classic:1.4.11")
 
 // Testing
 testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
 testImplementation("io.projectreactor:reactor-test:3.5.0")
}

application {
 mainClass.set("com.example.mcp.McpServerApplication")
}

tasks.test {
 useJUnitPlatform()
}

McpServerApplication.java Template

Copy & paste — that's it
package com.example.mcp;

import com.example.mcp.tools.ToolHandlers;
import com.example.mcp.resources.ResourceHandlers;
import com.example.mcp.prompts.PromptHandlers;
import io.mcp.server.McpServer;
import io.mcp.server.McpServerBuilder;
import io.mcp.server.transport.StdioServerTransport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.Disposable;

public class McpServerApplication {
 
 private static final Logger log = LoggerFactory.getLogger(McpServerApplication.class);
 
 public static void main(String[] args) {
 log.info("Starting MCP Server...");
 
 try {
 McpServer server = createServer();
 StdioServerTransport transport = new StdioServerTransport();
 
 // Start server
 Disposable serverDisposable = server.start(transport).subscribe();
 
 // Graceful shutdown
 Runtime.getRuntime().addShutdownHook(new Thread(() -> {
 log.info("Shutting down MCP server");
 serverDisposable.dispose();
 server.stop().block();
 }));
 
 log.info("MCP Server started successfully");
 
 // Keep running
 Thread.currentThread().join();
 
 } catch (Exception e) {
 log.error("Failed to start MCP server", e);
 System.exit(1);
 }
 }
 
 private static McpServer createServer() {
 McpServer server = McpServerBuilder.builder()
 .serverInfo("my-mcp-server", "1.0.0")
 .capabilities(capabilities -> capabilities
 .tools(true)
 .resources(true)
 .prompts(true))
 .build();
 
 // Register handlers
 ToolHandlers.register(server);
 ResourceHandlers.register(server);
 PromptHandlers.register(server);
 
 return server;
 }
}

ToolDefinitions.java Template

Copy & paste — that's it
package com.example.mcp.tools;

import io.mcp.json.JsonSchema;
import io.mcp.server.tool.Tool;

import java.util.List;

public class ToolDefinitions {
 
 public static List getTools() {
 return List.of(
 createGreetTool(),
 createCalculateTool()
 );
 }
 
 private static Tool createGreetTool() {
 return Tool.builder()
 .name("greet")
 .description("Generate a greeting message")
 .inputSchema(JsonSchema.object()
 .property("name", JsonSchema.string()
 .description("Name to greet")
 .required(true)))
 .build();
 }
 
 private static Tool createCalculateTool() {
 return Tool.builder()
 .name("calculate")
 .description("Perform mathematical calculations")
 .inputSchema(JsonSchema.object()
 .property("operation", JsonSchema.string()
 .description("Operation to perform")
 .enumValues(List.of("add", "subtract", "multiply", "divide"))
 .required(true))
 .property("a", JsonSchema.number()
 .description("First operand")
 .required(true))
 .property("b", JsonSchema.number()
 .description("Second operand")
 .required(true)))
 .build();
 }
}

ToolHandlers.java Template

Copy & paste — that's it
package com.example.mcp.tools;

import com.fasterxml.jackson.databind.JsonNode;
import io.mcp.server.McpServer;
import io.mcp.server.tool.ToolResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

public class ToolHandlers {
 
 private static final Logger log = LoggerFactory.getLogger(ToolHandlers.class);
 
 public static void register(McpServer server) {
 // Register tool list handler
 server.addToolListHandler(() -> {
 log.debug("Listing available tools");
 return Mono.just(ToolDefinitions.getTools());
 });
 
 // Register greet handler
 server.addToolHandler("greet", ToolHandlers::handleGreet);
 
 // Register calculate handler
 server.addToolHandler("calculate", ToolHandlers::handleCalculate);
 }
 
 private static Mono handleGreet(JsonNode arguments) {
 log.info("Greet tool called");
 
 if (!arguments.has("name")) {
 return Mono.just(ToolResponse.error()
 .message("Missing 'name' parameter")
 .build());
 }
 
 String name = arguments.get("name").asText();
 String greeting = "Hello, " + name + "! Welcome to MCP.";
 
 log.debug("Generated greeting for: {}", name);
 
 return Mono.just(ToolResponse.success()
 .addTextContent(greeting)
 .build());
 }
 
 private static Mono handleCalculate(JsonNode arguments) {
 log.info("Calculate tool called");
 
 if (!arguments.has("operation") || !arguments.has("a") || !arguments.has("b")) {
 return Mono.just(ToolResponse.error()
 .message("Missing required parameters")
 .build());
 }
 
 String operation = arguments.get("operation").asText();
 double a = arguments.get("a").asDouble();
 double b = arguments.get("b").asDouble();
 
 double result;
 switch (operation) {
 case "add":
 result = a + b;
 break;
 case "subtract":
 result = a - b;
 break;
 case "multiply":
 result = a * b;
 break;
 case "divide":
 if (b == 0) {
 return Mono.just(ToolResponse.error()
 .message("Division by zero")
 .build());
 }
 result = a / b;
 break;
 default:
 return Mono.just(ToolResponse.error()
 .message("Unknown operation: " + operation)
 .build());
 }
 
 log.debug("Calculation: {} {} {} = {}", a, operation, b, result);
 
 return Mono.just(ToolResponse.success()
 .addTextContent("Result: " + result)
 .build());
 }
}

ResourceDefinitions.java Template

Copy & paste — that's it
package com.example.mcp.resources;

import io.mcp.server.resource.Resource;

import java.util.List;

public class ResourceDefinitions {
 
 public static List getResources() {
 return List.of(
 Resource.builder()
 .name("Example Data")
 .uri("resource://data/example")
 .description("Example resource data")
 .mimeType("application/json")
 .build(),
 Resource.builder()
 .name("Configuration")
 .uri("resource://config")
 .description("Server configuration")
 .mimeType("application/json")
 .build()
 );
 }
}

ResourceHandlers.java Template

Copy & paste — that's it
package com.example.mcp.resources;

import io.mcp.server.McpServer;
import io.mcp.server.resource.ResourceContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ResourceHandlers {
 
 private static final Logger log = LoggerFactory.getLogger(ResourceHandlers.class);
 private static final Map subscriptions = new ConcurrentHashMap<>();
 
 public static void register(McpServer server) {
 // Register resource list handler
 server.addResourceListHandler(() -> {
 log.debug("Listing available resources");
 return Mono.just(ResourceDefinitions.getResources());
 });
 
 // Register resource read handler
 server.addResourceReadHandler(ResourceHandlers::handleRead);
 
 // Register resource subscribe handler
 server.addResourceSubscribeHandler(ResourceHandlers::handleSubscribe);
 
 // Register resource unsubscribe handler
 server.addResourceUnsubscribeHandler(ResourceHandlers::handleUnsubscribe);
 }
 
 private static Mono handleRead(String uri) {
 log.info("Reading resource: {}", uri);
 
 switch (uri) {
 case "resource://data/example":
 String jsonData = String.format(
 "{\"message\":\"Example resource data\",\"timestamp\":\"%s\"}",
 Instant.now()
 );
 return Mono.just(ResourceContent.text(jsonData, uri, "application/json"));
 
 case "resource://config":
 String config = "{\"serverName\":\"my-mcp-server\",\"version\":\"1.0.0\"}";
 return Mono.just(ResourceContent.text(config, uri, "application/json"));
 
 default:
 log.warn("Unknown resource requested: {}", uri);
 return Mono.error(new IllegalArgumentException("Unknown resource URI: " + uri));
 }
 }
 
 private static Mono handleSubscribe(String uri) {
 log.info("Client subscribed to resource: {}", uri);
 subscriptions.put(uri, true);
 return Mono.empty();
 }
 
 private static Mono handleUnsubscribe(String uri) {
 log.info("Client unsubscribed from resource: {}", uri);
 subscriptions.remove(uri);
 return Mono.empty();
 }
}

PromptDefinitions.java Template

Copy & paste — that's it
package com.example.mcp.prompts;

import io.mcp.server.prompt.Prompt;
import io.mcp.server.prompt.PromptArgument;

import java.util.List;

public class PromptDefinitions {
 
 public static List getPrompts() {
 return List.of(
 Prompt.builder()
 .name("code-review")
 .description("Generate a code review prompt")
 .argument(PromptArgument.builder()
 .name("language")
 .description("Programming language")
 .required(true)
 .build())
 .argument(PromptArgument.builder()
 .name("focus")
 .description("Review focus area")
 .required(false)
 .build())
 .build()
 );
 }
}

PromptHandlers.java Template

Copy & paste — that's it
package com.example.mcp.prompts;

import io.mcp.server.McpServer;
import io.mcp.server.prompt.PromptMessage;
import io.mcp.server.prompt.PromptResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

public class PromptHandlers {
 
 private static final Logger log = LoggerFactory.getLogger(PromptHandlers.class);
 
 public static void register(McpServer server) {
 // Register prompt list handler
 server.addPromptListHandler(() -> {
 log.debug("Listing available prompts");
 return Mono.just(PromptDefinitions.getPrompts());
 });
 
 // Register prompt get handler
 server.addPromptGetHandler(PromptHandlers::handleCodeReview);
 }
 
 private static Mono handleCodeReview(String name, Map arguments) {
 log.info("Getting prompt: {}", name);
 
 if (!name.equals("code-review")) {
 return Mono.error(new IllegalArgumentException("Unknown prompt: " + name));
 }
 
 String language = arguments.getOrDefault("language", "Java");
 String focus = arguments.getOrDefault("focus", "general quality");
 
 String description = "Code review for " + language + " with focus on " + focus;
 
 List messages = List.of(
 PromptMessage.user("Please review this " + language + " code with focus on " + focus + "."),
 PromptMessage.assistant("I'll review the code focusing on " + focus + ". Please share the code."),
 PromptMessage.user("Here's the code to review: [paste code here]")
 );
 
 log.debug("Generated code review prompt for {} ({})", language, focus);
 
 return Mono.just(PromptResult.builder()
 .description(description)
 .messages(messages)
 .build());
 }
}

McpServerTest.java Template

Copy & paste — that's it
package com.example.mcp;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.mcp.server.McpServer;
import io.mcp.server.McpSyncServer;
import io.mcp.server.tool.ToolResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class McpServerTest {
 
 private McpSyncServer syncServer;
 private ObjectMapper objectMapper;
 
 @BeforeEach
 void setUp() {
 McpServer server = createTestServer();
 syncServer = server.toSyncServer();
 objectMapper = new ObjectMapper();
 }
 
 private McpServer createTestServer() {
 // Same setup as main application
 McpServer server = McpServerBuilder.builder()
 .serverInfo("test-server", "1.0.0")
 .capabilities(cap -> cap.tools(true))
 .build();
 
 // Register handlers
 ToolHandlers.register(server);
 
 return server;
 }
 
 @Test
 void testGreetTool() {
 ObjectNode args = objectMapper.createObjectNode();
 args.put("name", "Java");
 
 ToolResponse response = syncServer.callTool("greet", args);
 
 assertFalse(response.isError());
 assertEquals(1, response.getContent().size());
 assertTrue(response.getContent().get(0).getText().contains("Java"));
 }
 
 @Test
 void testCalculateTool() {
 ObjectNode args = objectMapper.createObjectNode();
 args.put("operation", "add");
 args.put("a", 5);
 args.put("b", 3);
 
 ToolResponse response = syncServer.callTool("calculate", args);
 
 assertFalse(response.isError());
 assertTrue(response.getContent().get(0).getText().contains("8"));
 }
 
 @Test
 void testDivideByZero() {
 ObjectNode args = objectMapper.createObjectNode();
 args.put("operation", "divide");
 args.put("a", 10);
 args.put("b", 0);
 
 ToolResponse response = syncServer.callTool("calculate", args);
 
 assertTrue(response.isError());
 }
}

README.md Template

Copy & paste — that's it
# My MCP Server

A Model Context Protocol server built with Java and the official MCP Java SDK.

## Features

- ✅ Tools: greet, calculate
- ✅ Resources: example data, configuration
- ✅ Prompts: code-review
- ✅ Reactive Streams with Project Reactor
- ✅ Structured logging with SLF4J
- ✅ Full test coverage

## Build

### Maven
```bash
mvn clean package

Gradle

Copy & paste — that's it
./gradlew build

Run

Maven

Copy & paste — that's it
java -jar target/my-mcp-server-1.0.0.jar

Gradle

Copy & paste — that's it
./gradlew run

Testing

Maven

Copy & paste — that's it
mvn test

Gradle

Copy & paste — that's it
./gradlew test

Integration with Claude Desktop

Add to claude_desktop_config.json:

Copy & paste — that's it
{
 "mcpServers": {
 "my-mcp-server": {
 "command": "java",
 "args": ["-jar", "/path/to/my-mcp-server-1.0.0.jar"]
 }
 }
}

License

MIT

Copy & paste — that's it

## Generation Instructions

1. **Ask for project name and package**
2. **Choose build tool** (Maven or Gradle)
3. **Generate all files** with proper package structure
4. **Use Reactive Streams** for async handlers
5. **Include comprehensive logging** with SLF4J
6. **Add tests** for all handlers
7. **Follow Java conventions** (camelCase, PascalCase)
8. **Include error handling** with proper responses
9. **Document public APIs** with Javadoc
10. **Provide both sync and async** examples