Skip to main content

Module 1: Environment Setup

Duration: ~20 minutes | Level: Beginner | Prerequisites: Java 17+ installed (Java 21 recommended), basic Maven or Gradle knowledge


What You'll Have After This Module

  • Java 17+ confirmed working (21 strongly recommended)
  • Maven or Gradle project with the MCP Java SDK dependency
  • Claude Desktop installed and configured to launch your server
  • The MCP SDK resolved and verified on your classpath (a real hello-world server and its Claude Desktop connection come in Module 2)

The Java MCP SDK requires Java 17 as a minimum. It uses modern Java features:

  • Records: for immutable data classes (tool results, resource content); available in 17
  • Pattern Matching for instanceof: concise, safe type checks when reading tool arguments and content (e.g. arg instanceof String text); available in 17
  • Text Blocks: for JSON schema definitions and tool descriptions; available in 17
  • Virtual Threads (Project Loom): efficient, non-blocking I/O without reactive frameworks; added in 21

You can use Java 17, but 21 is strongly recommended because virtual threads dramatically simplify stdio and HTTP transport implementations and Java 21 is a well-supported LTS release (Java 25, GA September 2025, is the current LTS). Pick 21 unless you have a specific reason to stay on 17 or to move to the newer Java 25 LTS.


Verify Your Java Installation

java -version
# Expected: openjdk version "21.0.x" (or 17.0.x at minimum)

javac -version
# Expected: javac 21.0.x (or 17.0.x at minimum)

If you see an older version, install a current JDK. Adoptium (Eclipse Temurin) provides free, production-quality LTS builds.


Create a Maven Project

The fastest way to start is with Maven's standard archetype:

mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=my-mcp-server \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=1.5 \
-DinteractiveMode=false

cd my-mcp-server

# Verify the archetype generated what you expect; older Maven versions
# default to a slightly different layout:
ls # should show: pom.xml src/
find src # should show: src/main/java/com/example/App.java
# src/test/java/com/example/AppTest.java

If your layout differs (e.g., no App.java), the rest of this module still works; just adjust the file paths in subsequent steps to match your archetype's output.

Add the MCP Java SDK dependency

Edit pom.xml and add the SDK:

<project>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<!-- MCP Java SDK 2.0.0 is GA (prior minor 1.1.x and 1.0.x are still patched). Follows SemVer; no formal LTS designation. -->
<!-- The 'mcp' artifact is the bundled distribution (it depends on mcp-core + mcp-json-jackson3, which uses Jackson 3's 'tools.jackson' packages). -->
<!-- For Jackson 2 (the familiar 'com.fasterxml.jackson' ObjectMapper), pull in mcp-core directly together with mcp-json-jackson2 as shown below. -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-json-jackson2</artifactId>
<version>2.0.0</version>
</dependency>

<!-- Logging (SLF4J + Logback) -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.34</version>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Build a runnable fat JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.HelloMcpServer</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Version check

The MCP Java SDK is actively developed. Check Maven Central for the latest version before starting a new project.


Gradle Alternative

For Gradle (Kotlin DSL):

// build.gradle.kts
plugins {
java
application
}

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

dependencies {
implementation("io.modelcontextprotocol.sdk:mcp-core:2.0.0")
implementation("io.modelcontextprotocol.sdk:mcp-json-jackson2:2.0.0")
implementation("ch.qos.logback:logback-classic:1.5.34")
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.0")
}

application {
mainClass.set("com.example.HelloMcpServer")
}

tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.example.HelloMcpServer"
}
from(configurations.runtimeClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

Install Claude Desktop

For development, Claude Desktop is the easiest MCP host to use. It supports both stdio and HTTP servers and provides visual feedback when tools are called.

  1. Download from claude.ai/download
  2. Log in with your Anthropic account (free accounts work)
  3. Open Settings → Developer → Enable MCP

Configure Claude Desktop to find your server

Claude Desktop reads its MCP server configuration from a JSON file:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

Create or edit this file:

{
"mcpServers": {
"my-first-server": {
"command": "java",
"args": ["-jar", "/absolute/path/to/my-mcp-server/target/my-mcp-server-1.0-SNAPSHOT.jar"],
"env": {}
}
}
}

Use the absolute path to your JAR file. The env object can pass environment variables (database URLs, API keys) to your server process.


Verify the SDK Is Available

Create a quick sanity-check class to confirm the SDK resolved:

package com.example;

import io.modelcontextprotocol.server.McpServer;

public class SdkCheck {
public static void main(String[] args) {
System.out.println("MCP SDK available: " + McpServer.class.getName());
}
}
mvn compile exec:java -Dexec.mainClass=com.example.SdkCheck
# Expected: MCP SDK available: io.modelcontextprotocol.server.McpServer

If this fails, check your pom.xml dependencies and ensure you're running mvn compile (not just mvn package).


Project Structure

Your project should look like this:

my-mcp-server/
├── pom.xml
└── src/
└── main/
├── java/
│ └── com/example/
│ └── HelloMcpServer.java ← we'll build this next
└── resources/
└── logback.xml ← logging config

Logging configuration

Create src/main/resources/logback.xml:

<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDERR" />
</root>
</configuration>
Log to stderr, not stdout

When using stdio transport, stdout is used exclusively for MCP protocol messages. Any log output to stdout will corrupt the protocol stream. Always configure your logger to write to stderr.


Project Setup: Get the Companion Code

Every module in this course has a runnable, compiling reference in the companion repository under projects/mcp-java-sdk/. It is a single multi-module Maven build: a parent pom plus five module directories, one per major topic.

projects/mcp-java-sdk/
├── pom.xml ← parent POM (packaging: pom)
├── hello-mcp-server/ ← Module 2
├── tools-server/ ← Module 3 (and the error-handling/testing examples)
├── resources-server/ ← Module 4
├── prompts-server/ ← Module 5
└── production-server/ ← Module 9 (Spring Boot + HTTP)

The parent POM pins every version once and the modules inherit them, so the snippets you copy from individual lessons (which show explicit versions for clarity) line up with a single source of truth. The parent declares Java 21, the MCP Java SDK BOM (io.modelcontextprotocol.sdk:mcp-bom:2.0.0, which version-aligns mcp-core, mcp-json-jackson2, and friends), the Spring Boot BOM (used only by production-server), and the JUnit, Jackson, Logback, and SLF4J versions. Module POMs therefore list dependencies without versions: the BOMs supply them.

Build everything from the repository's projects/mcp-java-sdk/ directory:

# Compile and test all modules
mvn -B verify

# Build (or work on) a single module plus its dependencies
mvn -B -pl tools-server -am verify

Run a stdio server module after building (each produces a runnable fat JAR via the shade plugin):

# Module 2 hello server
java -jar hello-mcp-server/target/hello-mcp-server-1.0.0-SNAPSHOT.jar

# Module 3 tools server
java -jar tools-server/target/tools-server-1.0.0-SNAPSHOT.jar

The Module 9 production-server is a Spring Boot app (HTTP, not stdio), so run it with the Spring Boot plugin instead of a bare java -jar:

# Starts on http://localhost:8080 with /sse, /mcp/message, and /actuator endpoints
mvn -B -pl production-server -am spring-boot:run
Point Claude Desktop at a stdio module

To wire any stdio module into Claude Desktop, use the absolute path to its built JAR in the config shown earlier in this module, for example tools-server/target/tools-server-1.0.0-SNAPSHOT.jar.


What's Next

Your environment is ready. In the next module, we'll write your first MCP server, a minimal server that advertises capabilities and responds to tool calls, and connect it to Claude Desktop.

→ Module 2: Your First MCP Server