diff --git a/mcp-examples/mcp-stateless-server/README.md b/mcp-examples/mcp-stateless-server/README.md
new file mode 100644
index 000000000..d22497ab6
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/README.md
@@ -0,0 +1,39 @@
+# Example Stateless MCP HTTP Server
+
+This an example of sync stateless MCP HTTP server. It shows how to set up
+some simple tools, prompts, and resources as well as accessing the HTTP request
+from handlers.
+
+The actual server implementation is Jetty but any servlet container could be used.
+
+- See [Tools](src/main/java/io/modelcontextprotocol/examples/stateless/server/Tools.java) for the test tools.
+The tool `requestHeader` shows how to access the HTTP request headers.
+- See [Prompts](src/main/java/io/modelcontextprotocol/examples/stateless/server/Prompts.java) for the test prompt.
+- See [Resources](src/main/java/io/modelcontextprotocol/examples/stateless/server/Resources.java) for the test resource.
+
+## How to run
+
+1. Build the project:
+
+```shell
+./mvnw clean install
+```
+
+2. Run this server example:
+
+```shell
+./mvnw -pl :mcp-stateless-server exec:java -Dexec.mainClass="io.modelcontextprotocol.examples.stateless.server.Main"
+```
+
+3. In a separate terminal, run the MCP inspector:
+
+```shell
+npx @modelcontextprotocol/inspector
+```
+
+A browser should open with the MCP Inspector tool:
+- Set the "Transport Type" to "Streamable HTTP"
+- Change the URL to `http://localhost:8080/mcp`
+- Click "Connect"
+
+Try out the tools, prompts, and resources in the MCP Inspector.
diff --git a/mcp-examples/mcp-stateless-server/pom.xml b/mcp-examples/mcp-stateless-server/pom.xml
new file mode 100644
index 000000000..4598531e3
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+ io.modelcontextprotocol.sdk
+ mcp-examples
+ 0.12.0-SNAPSHOT
+
+ mcp-stateless-server
+ jar
+ Examples for the Java MCP SDK
+ Provides some examples for the MCP Java SDK
+ https://github.com/modelcontextprotocol/java-sdk
+
+
+ https://github.com/modelcontextprotocol/java-sdk
+ git://github.com/modelcontextprotocol/java-sdk.git
+ git@github.com/modelcontextprotocol/java-sdk.git
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${jackson.version}
+
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ ${jakarta.servlet.version}
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ 11.0.20
+
+
+
+ org.eclipse.jetty
+ jetty-servlet
+ 11.0.20
+
+
+
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/JettyServer.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/JettyServer.java
new file mode 100644
index 000000000..feae09626
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/JettyServer.java
@@ -0,0 +1,34 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import jakarta.servlet.http.HttpServlet;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+public class JettyServer implements AutoCloseable {
+
+ private final Server server;
+
+ public JettyServer(HttpServlet servlet, int port) {
+ server = new Server(port);
+
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ context.addServlet(new ServletHolder(servlet), "/mcp");
+
+ try {
+ server.start();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ server.stop();
+ }
+
+}
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Main.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Main.java
new file mode 100644
index 000000000..9567bbfcc
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Main.java
@@ -0,0 +1,40 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import io.modelcontextprotocol.server.McpStatelessSyncServer;
+import io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
+import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
+import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities.PromptCapabilities;
+import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities.ResourceCapabilities;
+import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities.ToolCapabilities;
+
+public class Main {
+
+ @SuppressWarnings("CallToPrintStackTrace")
+ public static void main(String[] args) {
+ HttpServletStatelessServerTransport transport = McpServerBuilder.buildTransport();
+
+ PromptCapabilities promptCapabilities = new PromptCapabilities(false);
+ ResourceCapabilities resourceCapabilities = new ResourceCapabilities(false, false);
+ ToolCapabilities toolCapabilities = new ToolCapabilities(false);
+
+ McpStatelessSyncServer mcpServer = McpServerBuilder.buildServer(transport,
+ new ServerCapabilities(null, null, null, promptCapabilities, resourceCapabilities, toolCapabilities),
+ "test", "1.0", "For testing");
+
+ mcpServer.addTool(Tools.addTwoNumbers);
+ mcpServer.addTool(Tools.requestHeader);
+ mcpServer.addPrompt(Prompts.greetingPrompt);
+ mcpServer.addResource(Resources.testResources);
+
+ try (var ignore = new JettyServer(transport, 8080)) {
+ Thread.currentThread().join();
+ }
+ catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/McpServerBuilder.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/McpServerBuilder.java
new file mode 100644
index 000000000..4d75645d5
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/McpServerBuilder.java
@@ -0,0 +1,38 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.modelcontextprotocol.server.McpServer;
+import io.modelcontextprotocol.server.McpStatelessSyncServer;
+import io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpStatelessServerTransport;
+
+public interface McpServerBuilder {
+
+ String CONTEXT_REQUEST_KEY = McpServerBuilder.class.getName() + ".request";
+
+ ObjectMapper MAPPER = new ObjectMapper();
+
+ static HttpServletStatelessServerTransport buildTransport() {
+ return HttpServletStatelessServerTransport.builder()
+ .messageEndpoint("/mcp")
+ .objectMapper(MAPPER)
+ .contextExtractor((request, transportContext) -> {
+ transportContext.put(CONTEXT_REQUEST_KEY, request);
+ return transportContext;
+ })
+ .build();
+ }
+
+ static McpStatelessSyncServer buildServer(McpStatelessServerTransport transport,
+ McpSchema.ServerCapabilities serverCapabilities, String serverName, String serverVersion,
+ String instructions) {
+ return McpServer.sync(transport)
+ .objectMapper(MAPPER)
+ .capabilities(serverCapabilities)
+ .serverInfo(serverName, serverVersion)
+ .instructions(instructions)
+ .build();
+ }
+
+}
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Prompts.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Prompts.java
new file mode 100644
index 000000000..dae88fe88
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Prompts.java
@@ -0,0 +1,25 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncPromptSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
+import io.modelcontextprotocol.spec.McpSchema.Prompt;
+import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
+import io.modelcontextprotocol.spec.McpSchema.TextContent;
+
+import java.util.List;
+
+import static io.modelcontextprotocol.spec.McpSchema.Role.USER;
+
+public interface Prompts {
+
+ SyncPromptSpecification greetingPrompt = new SyncPromptSpecification(
+ new Prompt("greeting", "Greeting Prompt",
+ List.of(new McpSchema.PromptArgument("name", "Name of the person to greet", true))),
+ (transportContext, getPromptRequest) -> {
+ String name = String.valueOf(getPromptRequest.arguments().get("name"));
+ return new GetPromptResult("greeting",
+ List.of(new PromptMessage(USER, new TextContent("Hello " + name + "!"))));
+ });
+
+}
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Resources.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Resources.java
new file mode 100644
index 000000000..40be09cbe
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Resources.java
@@ -0,0 +1,24 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncResourceSpecification;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpSchema.ReadResourceResult;
+import io.modelcontextprotocol.spec.McpSchema.Resource;
+
+import java.util.List;
+
+public interface Resources {
+
+ SyncResourceSpecification testResources = new SyncResourceSpecification(
+ Resource.builder()
+ .name("test")
+ .uri("https://modelcontextprotocol.io")
+ .description("A test resource")
+ .mimeType("text/plain")
+ .size(10L)
+ .build(),
+ (transportContext, readResourceRequest) -> new ReadResourceResult(
+ List.of(new McpSchema.TextResourceContents("https://modelcontextprotocol.io", "text/plain",
+ "0123456789"))));
+
+}
diff --git a/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Tools.java b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Tools.java
new file mode 100644
index 000000000..df8bc5525
--- /dev/null
+++ b/mcp-examples/mcp-stateless-server/src/main/java/io/modelcontextprotocol/examples/stateless/server/Tools.java
@@ -0,0 +1,67 @@
+package io.modelcontextprotocol.examples.stateless.server;
+
+import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
+import io.modelcontextprotocol.spec.McpError;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
+import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse.JSONRPCError;
+import jakarta.servlet.http.HttpServletRequest;
+
+import static io.modelcontextprotocol.examples.stateless.server.McpServerBuilder.CONTEXT_REQUEST_KEY;
+import static io.modelcontextprotocol.spec.McpSchema.ErrorCodes.INVALID_REQUEST;
+
+public interface Tools {
+
+ String addTwoNumbersSchemaJson = """
+ {
+ "type": "object",
+ "properties": {
+ "a": {
+ "type": "integer"
+ },
+ "b": {
+ "type": "integer"
+ }
+ },
+ "required": ["a", "b"]
+ }
+ """;
+
+ String requestHeaderSchemaJson = """
+ {
+ "type": "object",
+ "properties": {
+ "headerName": {
+ "type": "string"
+ }
+ },
+ "required": ["headerName"]
+ }
+ """;
+
+ SyncToolSpecification addTwoNumbers = SyncToolSpecification.builder()
+ .tool(McpSchema.Tool.builder().name("add").inputSchema(addTwoNumbersSchemaJson).build())
+ .callHandler((transportContext, callToolRequest) -> {
+ int a = Integer.parseInt(String.valueOf(callToolRequest.arguments().get("a")));
+ int b = Integer.parseInt(String.valueOf(callToolRequest.arguments().get("b")));
+
+ return new CallToolResult(String.valueOf(a + b), null);
+ })
+ .build();
+
+ SyncToolSpecification requestHeader = SyncToolSpecification.builder()
+ .tool(McpSchema.Tool.builder().name("requestHeader").inputSchema(requestHeaderSchemaJson).build())
+ .callHandler((transportContext, callToolRequest) -> {
+ HttpServletRequest request = (HttpServletRequest) transportContext.get(CONTEXT_REQUEST_KEY);
+ String headerName = String.valueOf(callToolRequest.arguments().get("headerName"));
+
+ String value = request.getHeader(headerName);
+ if (value == null) {
+ throw new McpError(new JSONRPCError(INVALID_REQUEST, "Header '" + headerName + "' not found", null));
+ }
+
+ return new CallToolResult(value, null);
+ })
+ .build();
+
+}
diff --git a/mcp-examples/pom.xml b/mcp-examples/pom.xml
new file mode 100644
index 000000000..2cd67551a
--- /dev/null
+++ b/mcp-examples/pom.xml
@@ -0,0 +1,33 @@
+
+
+ 4.0.0
+
+ io.modelcontextprotocol.sdk
+ mcp-parent
+ 0.12.0-SNAPSHOT
+
+ mcp-examples
+ pom
+ Examples for the Java MCP SDK
+ Provides some examples for the MCP Java SDK
+ https://github.com/modelcontextprotocol/java-sdk
+
+ mcp-stateless-server
+
+
+
+ https://github.com/modelcontextprotocol/java-sdk
+ git://github.com/modelcontextprotocol/java-sdk.git
+ git@github.com/modelcontextprotocol/java-sdk.git
+
+
+
+
+ io.modelcontextprotocol.sdk
+ mcp
+ 0.12.0-SNAPSHOT
+
+
+
diff --git a/pom.xml b/pom.xml
index c0b1f7a44..28df75d8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,7 +106,8 @@
mcp-spring/mcp-spring-webflux
mcp-spring/mcp-spring-webmvc
mcp-test
-
+ mcp-examples
+