diff --git a/mcp.servlet-server.log b/mcp.servlet-server.log new file mode 100644 index 0000000..b95440b --- /dev/null +++ b/mcp.servlet-server.log @@ -0,0 +1,58 @@ +2025-02-09T21:26:38.153+01:00 INFO 95924 --- [main] .s.a.m.s.s.s.McpServletServerApplication : Starting McpServletServerApplication using Java 17.0.12 with PID 95924 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-servlet-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:26:38.154+01:00 INFO 95924 --- [main] .s.a.m.s.s.s.McpServletServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:26:38.468+01:00 INFO 95924 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-02-09T21:26:38.473+01:00 INFO 95924 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-02-09T21:26:38.473+01:00 INFO 95924 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33] +2025-02-09T21:26:38.493+01:00 INFO 95924 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-02-09T21:26:38.493+01:00 INFO 95924 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 319 ms +2025-02-09T21:26:38.711+01:00 INFO 95924 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-02-09T21:26:38.715+01:00 INFO 95924 --- [main] .s.a.m.s.s.s.McpServletServerApplication : Started McpServletServerApplication in 0.731 seconds (process running for 0.85) +2025-02-09T21:26:43.707+01:00 INFO 95924 --- [http-nio-8080-exec-2] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=initialize, id=6c0682de-0, params={protocolVersion=2024-11-05, capabilities={}, clientInfo={name=Java SDK MCP Client, version=1.0.0}}] +2025-02-09T21:26:43.711+01:00 INFO 95924 --- [http-nio-8080-exec-2] i.m.server.McpAsyncServer : Client initialize request - Protocol: 2024-11-05, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null], Info: Implementation[name=Java SDK MCP Client, version=1.0.0] +2025-02-09T21:26:43.756+01:00 INFO 95924 --- [http-nio-8080-exec-3] i.m.spec.DefaultMcpSession : Received notification: JSONRPCNotification[jsonrpc=2.0, method=notifications/initialized, params=null] +2025-02-09T21:26:43.758+01:00 INFO 95924 --- [http-nio-8080-exec-4] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=ping, id=6c0682de-1, params=null] +2025-02-09T21:26:43.760+01:00 INFO 95924 --- [http-nio-8080-exec-5] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/list, id=6c0682de-2, params={}] +2025-02-09T21:26:43.770+01:00 INFO 95924 --- [http-nio-8080-exec-6] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=6c0682de-3, params={name=toUpperCase, arguments={input=accountName}}] +2025-02-09T21:26:43.794+01:00 INFO 95924 --- [http-nio-8080-exec-7] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=6c0682de-4, params={name=getBooks, arguments={title=Spring Framework}}] +2025-02-09T21:26:44.908+01:00 INFO 95924 --- [http-nio-8080-exec-8] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/list, id=6c0682de-5, params={}] +2025-02-09T21:26:44.917+01:00 INFO 95924 --- [http-nio-8080-exec-9] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/read, id=6c0682de-6, params={uri=system://info}] +2025-02-09T21:26:44.927+01:00 INFO 95924 --- [http-nio-8080-exec-10] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/list, id=6c0682de-7, params={}] +2025-02-09T21:26:44.934+01:00 INFO 95924 --- [http-nio-8080-exec-1] i.m.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/get, id=6c0682de-8, params={name=greeting, arguments={name=Spring}}] +2025-02-09T21:26:46.642+01:00 ERROR 95924 --- [SpringApplicationShutdownHook] reactor.core.publisher.Operators : Operator called default onErrorDropped + +reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing. +Caused by: java.lang.IllegalStateException: The request associated with the AsyncContext has already completed processing. + at org.apache.catalina.core.AsyncContextImpl.check(AsyncContextImpl.java:529) ~[tomcat-embed-core-10.1.33.jar:10.1.33] + at org.apache.catalina.core.AsyncContextImpl.complete(AsyncContextImpl.java:92) ~[tomcat-embed-core-10.1.33.jar:10.1.33] + at io.modelcontextprotocol.server.transport.HttpServletSseServerTransport.removeSession(HttpServletSseServerTransport.java:379) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at java.base/java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4780) ~[na:na] + at io.modelcontextprotocol.server.transport.HttpServletSseServerTransport.lambda$closeGracefully$4(HttpServletSseServerTransport.java:351) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61) ~[reactor-core-3.6.12.jar:3.6.12] + at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.6.12.jar:3.6.12] + at reactor.core.publisher.Mono.subscribeWith(Mono.java:4642) ~[reactor-core-3.6.12.jar:3.6.12] + at reactor.core.publisher.Mono.subscribe(Mono.java:4403) ~[reactor-core-3.6.12.jar:3.6.12] + at io.modelcontextprotocol.spec.McpTransport.close(McpTransport.java:61) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at io.modelcontextprotocol.server.transport.HttpServletSseServerTransport.close(HttpServletSseServerTransport.java:323) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at io.modelcontextprotocol.spec.DefaultMcpSession.close(DefaultMcpSession.java:283) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at io.modelcontextprotocol.server.McpAsyncServer.close(McpAsyncServer.java:255) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at io.modelcontextprotocol.server.McpSyncServer.close(McpSyncServer.java:205) ~[mcp-0.7.0-SNAPSHOT.jar:0.7.0-SNAPSHOT] + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] + at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] + at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:316) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:249) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:587) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:559) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1202) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:520) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1195) ~[spring-beans-6.1.15.jar:6.1.15] + at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1195) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1156) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.doClose(ServletWebServerApplicationContext.java:174) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:1102) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.boot.SpringApplicationShutdownHook.closeAndWait(SpringApplicationShutdownHook.java:145) ~[spring-boot-3.3.6.jar:3.3.6] + at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na] + at org.springframework.boot.SpringApplicationShutdownHook.run(SpringApplicationShutdownHook.java:114) ~[spring-boot-3.3.6.jar:3.3.6] + at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na] + diff --git a/mcp.webflux.log b/mcp.webflux.log new file mode 100644 index 0000000..7c4efe8 --- /dev/null +++ b/mcp.webflux.log @@ -0,0 +1,50 @@ +2025-02-09T21:25:36.624+01:00 INFO 95283 --- [main] o.s.a.m.s.server.McpServerApplication : Starting McpServerApplication using Java 17.0.12 with PID 95283 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-webflux-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:25:36.625+01:00 INFO 95283 --- [main] o.s.a.m.s.server.McpServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:25:38.595+01:00 WARN 95283 --- [main] o.s.c.support.DefaultLifecycleProcessor : Failed to stop bean 'reactorResourceFactory' + +reactor.core.Exceptions$ReactiveException: java.lang.InterruptedException + at reactor.core.Exceptions.propagate(Exceptions.java:410) ~[reactor-core-3.6.12.jar:3.6.12] + at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:96) ~[reactor-core-3.6.12.jar:3.6.12] + at reactor.core.publisher.Mono.block(Mono.java:1779) ~[reactor-core-3.6.12.jar:3.6.12] + at org.springframework.http.client.ReactorResourceFactory.stop(ReactorResourceFactory.java:298) ~[spring-web-6.1.15.jar:6.1.15] + at org.springframework.context.SmartLifecycle.stop(SmartLifecycle.java:117) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.DefaultLifecycleProcessor.doStop(DefaultLifecycleProcessor.java:346) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.stop(DefaultLifecycleProcessor.java:488) ~[spring-context-6.1.15.jar:6.1.15] + at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na] + at org.springframework.context.support.DefaultLifecycleProcessor.stopBeans(DefaultLifecycleProcessor.java:315) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:207) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:990) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:628) ~[spring-context-6.1.15.jar:6.1.15] + at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.6.jar:3.3.6] + at org.springframework.ai.mcp.sample.server.McpServerApplication.main(McpServerApplication.java:10) ~[classes/:na] +Caused by: java.lang.InterruptedException: null + at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1048) ~[na:na] + at java.base/java.util.concurrent.CountDownLatch.await(CountDownLatch.java:230) ~[na:na] + at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:91) ~[reactor-core-3.6.12.jar:3.6.12] + ... 17 common frames omitted + +2025-02-09T21:25:38.599+01:00 WARN 95283 --- [main] onfigReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop' +2025-02-09T21:25:38.609+01:00 INFO 95283 --- [main] o.s.a.m.s.t.WebFluxSseServerTransport : Graceful shutdown completed +2025-02-09T21:25:38.610+01:00 INFO 95283 --- [main] o.s.a.m.s.t.WebFluxSseServerTransport : Graceful shutdown completed +2025-02-09T21:25:44.586+01:00 INFO 95411 --- [main] o.s.a.m.s.server.McpServerApplication : Starting McpServerApplication using Java 17.0.12 with PID 95411 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-webflux-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:25:44.587+01:00 INFO 95411 --- [main] o.s.a.m.s.server.McpServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:25:45.244+01:00 INFO 95411 --- [main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080 (http) +2025-02-09T21:25:45.252+01:00 INFO 95411 --- [main] o.s.a.m.s.server.McpServerApplication : Started McpServerApplication in 0.833 seconds (process running for 0.968) +2025-02-09T21:25:49.434+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=initialize, id=12e95de7-0, params={protocolVersion=2024-11-05, capabilities={}, clientInfo={name=Spring AI MCP Client, version=1.0.0}}] +2025-02-09T21:25:49.438+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.server.McpAsyncServer : Client initialize request - Protocol: 2024-11-05, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null], Info: Implementation[name=Spring AI MCP Client, version=1.0.0] +2025-02-09T21:25:49.488+01:00 INFO 95411 --- [reactor-http-nio-4] o.s.ai.mcp.spec.DefaultMcpSession : Received notification: JSONRPCNotification[jsonrpc=2.0, method=notifications/initialized, params=null] +2025-02-09T21:25:49.492+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=ping, id=12e95de7-1, params=null] +2025-02-09T21:25:49.496+01:00 INFO 95411 --- [reactor-http-nio-4] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/list, id=12e95de7-2, params={}] +2025-02-09T21:25:49.508+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=12e95de7-3, params={name=toUpperCase, arguments={input=accountName}}] +2025-02-09T21:25:49.527+01:00 INFO 95411 --- [reactor-http-nio-4] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=12e95de7-4, params={name=getBooks, arguments={title=Spring Framework}}] +2025-02-09T21:25:50.384+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/list, id=12e95de7-5, params={}] +2025-02-09T21:25:50.396+01:00 INFO 95411 --- [reactor-http-nio-4] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/read, id=12e95de7-6, params={uri=system://info}] +2025-02-09T21:25:50.408+01:00 INFO 95411 --- [reactor-http-nio-3] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/list, id=12e95de7-7, params={}] +2025-02-09T21:25:50.417+01:00 INFO 95411 --- [reactor-http-nio-4] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/get, id=12e95de7-8, params={name=greeting, arguments={name=Spring}}] +2025-02-09T21:25:54.383+01:00 INFO 95411 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebFluxSseServerTransport : Graceful shutdown completed +2025-02-09T21:25:54.384+01:00 INFO 95411 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebFluxSseServerTransport : Graceful shutdown completed diff --git a/mcp.webmvc.log b/mcp.webmvc.log new file mode 100644 index 0000000..d56e239 --- /dev/null +++ b/mcp.webmvc.log @@ -0,0 +1,50 @@ +2025-02-09T21:21:11.760+01:00 INFO 93310 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Starting McpMvcServerApplication using Java 17.0.12 with PID 93310 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-webmvc-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:21:11.761+01:00 INFO 93310 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:21:12.089+01:00 INFO 93310 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-02-09T21:21:12.095+01:00 INFO 93310 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-02-09T21:21:12.095+01:00 INFO 93310 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33] +2025-02-09T21:21:12.125+01:00 INFO 93310 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-02-09T21:21:12.125+01:00 INFO 93310 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 344 ms +2025-02-09T21:21:12.481+01:00 INFO 93310 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-02-09T21:21:12.487+01:00 INFO 93310 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Started McpMvcServerApplication in 0.895 seconds (process running for 1.022) +2025-02-09T21:21:36.802+01:00 INFO 93310 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed +2025-02-09T21:21:36.803+01:00 INFO 93310 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed +2025-02-09T21:22:52.834+01:00 INFO 93938 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Starting McpMvcServerApplication using Java 17.0.12 with PID 93938 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-webmvc-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:22:52.835+01:00 INFO 93938 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:22:53.140+01:00 INFO 93938 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-02-09T21:22:53.145+01:00 INFO 93938 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-02-09T21:22:53.145+01:00 INFO 93938 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33] +2025-02-09T21:22:53.167+01:00 INFO 93938 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-02-09T21:22:53.167+01:00 INFO 93938 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 313 ms +2025-02-09T21:22:53.484+01:00 INFO 93938 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-02-09T21:22:53.490+01:00 INFO 93938 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Started McpMvcServerApplication in 0.82 seconds (process running for 0.943) +2025-02-09T21:23:04.979+01:00 INFO 93938 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed +2025-02-09T21:23:04.979+01:00 INFO 93938 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed +2025-02-09T21:24:24.073+01:00 INFO 94676 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Starting McpMvcServerApplication using Java 17.0.12 with PID 94676 (/Users/christiantzolov/Dev/projects/spring-ai-examples/model-context-protocol/book-library/manual-webmvc-server/target/classes started by christiantzolov in /Users/christiantzolov/Dev/projects/spring-ai-examples) +2025-02-09T21:24:24.074+01:00 INFO 94676 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : No active profile set, falling back to 1 default profile: "default" +2025-02-09T21:24:24.425+01:00 INFO 94676 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http) +2025-02-09T21:24:24.430+01:00 INFO 94676 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat] +2025-02-09T21:24:24.431+01:00 INFO 94676 --- [main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.33] +2025-02-09T21:24:24.455+01:00 INFO 94676 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext +2025-02-09T21:24:24.456+01:00 INFO 94676 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 362 ms +2025-02-09T21:24:24.789+01:00 INFO 94676 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/' +2025-02-09T21:24:24.795+01:00 INFO 94676 --- [main] o.s.a.m.s.w.s.McpMvcServerApplication : Started McpMvcServerApplication in 0.896 seconds (process running for 1.022) +2025-02-09T21:24:27.528+01:00 INFO 94676 --- [http-nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-02-09T21:24:27.529+01:00 INFO 94676 --- [http-nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' +2025-02-09T21:24:27.529+01:00 INFO 94676 --- [http-nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 0 ms +2025-02-09T21:24:27.578+01:00 INFO 94676 --- [http-nio-8080-exec-2] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=initialize, id=1f83bbd8-0, params={protocolVersion=2024-11-05, capabilities={}, clientInfo={name=Spring AI MCP Client, version=1.0.0}}] +2025-02-09T21:24:27.582+01:00 INFO 94676 --- [http-nio-8080-exec-2] o.s.ai.mcp.server.McpAsyncServer : Client initialize request - Protocol: 2024-11-05, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null], Info: Implementation[name=Spring AI MCP Client, version=1.0.0] +2025-02-09T21:24:27.630+01:00 INFO 94676 --- [http-nio-8080-exec-3] o.s.ai.mcp.spec.DefaultMcpSession : Received notification: JSONRPCNotification[jsonrpc=2.0, method=notifications/initialized, params=null] +2025-02-09T21:24:27.633+01:00 INFO 94676 --- [http-nio-8080-exec-4] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=ping, id=1f83bbd8-1, params=null] +2025-02-09T21:24:27.637+01:00 INFO 94676 --- [http-nio-8080-exec-5] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/list, id=1f83bbd8-2, params={}] +2025-02-09T21:24:27.649+01:00 INFO 94676 --- [http-nio-8080-exec-6] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=1f83bbd8-3, params={name=toUpperCase, arguments={input=accountName}}] +2025-02-09T21:24:27.672+01:00 INFO 94676 --- [http-nio-8080-exec-7] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=tools/call, id=1f83bbd8-4, params={name=getBooks, arguments={title=Spring Framework}}] +2025-02-09T21:24:28.635+01:00 INFO 94676 --- [http-nio-8080-exec-8] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/list, id=1f83bbd8-5, params={}] +2025-02-09T21:24:28.645+01:00 INFO 94676 --- [http-nio-8080-exec-9] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=resources/read, id=1f83bbd8-6, params={uri=system://info}] +2025-02-09T21:24:28.657+01:00 INFO 94676 --- [http-nio-8080-exec-10] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/list, id=1f83bbd8-7, params={}] +2025-02-09T21:24:28.665+01:00 INFO 94676 --- [http-nio-8080-exec-1] o.s.ai.mcp.spec.DefaultMcpSession : Received request: JSONRPCRequest[jsonrpc=2.0, method=prompts/get, id=1f83bbd8-8, params={name=greeting, arguments={name=Spring}}] +2025-02-09T21:24:57.797+01:00 WARN 94676 --- [http-nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Ignoring exception, response committed already: org.springframework.web.context.request.async.AsyncRequestTimeoutException +2025-02-09T21:24:57.798+01:00 WARN 94676 --- [http-nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.context.request.async.AsyncRequestTimeoutException] +2025-02-09T21:25:37.487+01:00 WARN 94676 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Failed to complete SSE emitter for session 76fdc444-38d2-4884-9e75-dc747611b756: The response object has been recycled and is no longer associated with this facade +2025-02-09T21:25:37.487+01:00 INFO 94676 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed +2025-02-09T21:25:37.487+01:00 INFO 94676 --- [SpringApplicationShutdownHook] o.s.a.m.s.t.WebMvcSseServerTransport : Graceful shutdown completed diff --git a/model-context-protocol/README.md b/model-context-protocol/README.md deleted file mode 100644 index d63c286..0000000 --- a/model-context-protocol/README.md +++ /dev/null @@ -1,147 +0,0 @@ -# Spring AI Model Context Protocol (MCP) Examples - -This directory contains various examples demonstrating the usage of Spring AI's Model Context Protocol (MCP). Each example showcases different aspects of MCP implementation, including various transport methods and client-server configurations. - - -## Transport Types - -The examples demonstrate two main types of transport: - -1. **STDIO Transport** - - Process-based communication - - Synchronous communication - - Used in all client examples - - Available in all server implementations - -2. **HTTP SSE (Server-Sent Events) Transport** - - HTTP-based streaming communication - - Asynchronous communication - - Available in server implementations - - Implemented in three variants: - - Servlet-based (Spring MVC) - - WebFlux-based (Reactive) - - WebMVC-based - -## API Types - -The examples demonstrate both synchronous and asynchronous API usage: - -- **Synchronous API**: Used in STDIO transport implementations -- **Asynchronous API**: Used in SSE transport implementations - -## Getting Started - -Each example project can be built using Maven: - -```bash -./mvnw clean install -``` - -For running the examples: -1. For STDIO transport: Run the client application directly -2. For SSE transport: Start the server first, then run the client - -## Note - -- All server implementations support both STDIO and SSE transport modes -- Transport mode can be configured using the `transport.mode` property -- Client examples primarily use STDIO transport for simplicity -- Server starters provide auto-configuration support for easier integration -## Example Projects Overview - -### Current Implementations -These projects use current Spring AI MCP dependencies: - -#### Spring Boot Starter Projects -These use the `spring-ai-mcp-spring-boot-starter` dependency: - -#### `brave-chatbot` -- **Type**: Client -- **Transport**: STDIO -- **Framework**: Spring Boot with MCP Starter -- **Description**: Enhanced version of the Brave client with chatbot capabilities. - -#### `brave-starter` -- **Type**: Client Starter -- **Transport**: STDIO -- **Framework**: Spring Boot with MCP Starter -- **Description**: Spring Boot starter version of the Brave client. - -#### `mcp-webflux-server-starter` -- **Type**: Server Starter -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring WebFlux with MCP Starter -- **Description**: Spring Boot starter for WebFlux server with auto-configuration support. - -#### `mcp-weather-server-quickstart` -- **Type**: Server Quickstart -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring Boot with MCP Starter -- **Description**: Simplified version of the weather server for quick start purposes. - -#### `mcp-weather-server-starter` -- **Type**: Server Starter -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring Boot with MCP Starter -- **Description**: Spring Boot starter version of the weather server, with auto-configuration support. - -#### Manual Configuration Examples -These demonstrate how to create MCP applications without Spring Boot auto-configuration: - -#### `mcp-weather-server` -- **Type**: Server -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring Boot with WebFlux -- **Dependencies**: Uses `spring-ai-bom` and `mcp-bom` for dependency management -- **Description**: Weather service implementation showing how to manually configure an MCP application without using spring-boot-starter. Demonstrates manual configuration patterns while maintaining clean dependency management through BOMs. - -### Legacy Projects (Using Experimental Dependency) -These projects use the experimental dependency `org.springframework.experimental:spring-ai-mcp:0.6.0` and need updating: - -#### Server Implementations - -#### `mcp-servlet-server` -- **Type**: Server -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring MVC -- **Status**: Uses experimental dependency -- **Description**: Demonstrates a server implementation using Spring MVC with servlet-based SSE transport. Includes OpenLibrary integration. - -#### `mcp-webflux-server` -- **Type**: Server -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring WebFlux -- **Status**: Uses experimental dependency -- **Description**: Shows a reactive server implementation using Spring WebFlux with SSE transport. Includes OpenLibrary integration. - -#### `mcp-webmvc-server` -- **Type**: Server -- **Transport**: Supports both HTTP SSE and STDIO -- **Framework**: Spring WebMVC -- **Status**: Uses experimental dependency -- **Description**: Another server implementation using Spring WebMVC, demonstrating SSE transport integration. - -#### Client Examples - -#### `brave` -- **Type**: Client -- **Transport**: STDIO -- **Framework**: Spring Boot -- **Status**: Uses experimental dependency -- **Description**: Client implementation for Brave Search integration. - -#### `filesystem` -- **Type**: Client -- **Transport**: STDIO -- **Framework**: Spring Boot -- **Status**: Uses experimental dependency -- **Description**: Example showing filesystem operations through MCP. - -#### `sqlite` -- **Type**: Client -- **Transport**: STDIO -- **Framework**: Spring Boot -- **Status**: Uses experimental dependency -- **Description**: Demonstrates SQLite database integration through MCP (includes both simple and chatbot variants). - - diff --git a/model-context-protocol/mcp-servlet-server/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/book-library/manual-servlet-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-servlet-server/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/book-library/manual-servlet-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/mcp-servlet-server/README.md b/model-context-protocol/book-library/manual-servlet-server/README.md similarity index 100% rename from model-context-protocol/mcp-servlet-server/README.md rename to model-context-protocol/book-library/manual-servlet-server/README.md diff --git a/model-context-protocol/mcp-servlet-server/mvnw b/model-context-protocol/book-library/manual-servlet-server/mvnw similarity index 100% rename from model-context-protocol/mcp-servlet-server/mvnw rename to model-context-protocol/book-library/manual-servlet-server/mvnw diff --git a/model-context-protocol/mcp-servlet-server/mvnw.cmd b/model-context-protocol/book-library/manual-servlet-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-servlet-server/mvnw.cmd rename to model-context-protocol/book-library/manual-servlet-server/mvnw.cmd diff --git a/model-context-protocol/mcp-servlet-server/pom.xml b/model-context-protocol/book-library/manual-servlet-server/pom.xml similarity index 62% rename from model-context-protocol/mcp-servlet-server/pom.xml rename to model-context-protocol/book-library/manual-servlet-server/pom.xml index 1eabf31..2394605 100644 --- a/model-context-protocol/mcp-servlet-server/pom.xml +++ b/model-context-protocol/book-library/manual-servlet-server/pom.xml @@ -18,15 +18,15 @@ Sample application demonstrating MCP Servlet server usage - 0.6.0 + 1.0.0-SNAPSHOT - org.springframework.experimental - mcp-bom - ${spring-ai-mcp.version} + org.springframework.ai + spring-ai-bom + ${sprign-ai.version} pom import @@ -35,7 +35,7 @@ - org.springframework.experimental + org.springframework.ai spring-ai-mcp @@ -43,12 +43,6 @@ org.springframework.boot spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-test - test - @@ -56,27 +50,6 @@ org.springframework.boot spring-boot-maven-plugin - - - - repackage - - - - - - io.spring.javaformat - spring-javaformat-maven-plugin - 0.0.43 - - - validate - true - - validate - - - diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java b/model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java similarity index 72% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java rename to model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java index e1b425e..67f6d37 100644 --- a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java +++ b/model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServerConfig.java @@ -5,29 +5,30 @@ import java.util.Map; import java.util.function.Function; import com.fasterxml.jackson.databind.ObjectMapper; +import io.modelcontextprotocol.server.McpServer; +import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptRegistration; +import io.modelcontextprotocol.server.McpServerFeatures.SyncResourceRegistration; +import io.modelcontextprotocol.server.McpServerFeatures.SyncToolRegistration; +import io.modelcontextprotocol.server.McpSyncServer; +import io.modelcontextprotocol.server.transport.HttpServletSseServerTransport; +import io.modelcontextprotocol.server.transport.StdioServerTransport; +import io.modelcontextprotocol.spec.McpSchema; +import io.modelcontextprotocol.spec.McpSchema.GetPromptResult; +import io.modelcontextprotocol.spec.McpSchema.PromptMessage; +import io.modelcontextprotocol.spec.McpSchema.Role; +import io.modelcontextprotocol.spec.McpSchema.TextContent; +import io.modelcontextprotocol.spec.ServerMcpTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.mcp.server.McpServer; -import org.springframework.ai.mcp.server.McpServerFeatures.SyncPromptRegistration; -import org.springframework.ai.mcp.server.McpServerFeatures.SyncResourceRegistration; -import org.springframework.ai.mcp.server.McpServerFeatures.SyncToolRegistration; -import org.springframework.ai.mcp.server.McpSyncServer; -import org.springframework.ai.mcp.server.transport.HttpServletSseServerTransport; -import org.springframework.ai.mcp.server.transport.StdioServerTransport; -import org.springframework.ai.mcp.spec.McpSchema; -import org.springframework.ai.mcp.spec.McpSchema.GetPromptResult; -import org.springframework.ai.mcp.spec.McpSchema.PromptMessage; -import org.springframework.ai.mcp.spec.McpSchema.Role; -import org.springframework.ai.mcp.spec.McpSchema.TextContent; -import org.springframework.ai.mcp.spec.ServerMcpTransport; -import org.springframework.ai.mcp.spring.ToolHelper; -import org.springframework.ai.model.function.FunctionCallback; +import org.springframework.ai.mcp.McpToolUtils; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.ToolCallbacks; +import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestClient; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -77,9 +78,8 @@ public class McpServerConfig implements WebMvcConfigurer { .resources(systemInfoResourceRegistration()) .prompts(greetingPromptRegistration()) .tools( - ToolHelper.toSyncToolRegistration( - FunctionCallback.builder() - .function("toUpperCase", (Function) s -> s.input().toUpperCase()) + McpToolUtils.toSyncToolRegistration( + FunctionToolCallback.builder("toUpperCase", (Function) s -> s.input().toUpperCase()) .description("To upper case") .inputType(ToUpperCaseInput.class) .build())) @@ -89,20 +89,8 @@ public class McpServerConfig implements WebMvcConfigurer { } // @formatter:on public static List openLibraryToolRegistrations(OpenLibrary openLibrary) { - - var books = FunctionCallback.builder() - .method("getBooks", String.class) - .description("Get list of Books by title") - .targetObject(openLibrary) - .build(); - - var bookTitlesByAuthor = FunctionCallback.builder() - .method("getBookTitlesByAuthor", String.class) - .description("Get book titles by author") - .targetObject(openLibrary) - .build(); - - return ToolHelper.toSyncToolRegistration(books, bookTitlesByAuthor); + ToolCallback[] tools = ToolCallbacks.from(openLibrary); + return McpToolUtils.toSyncToolRegistration(tools); } private static SyncResourceRegistration systemInfoResourceRegistration() { @@ -156,10 +144,4 @@ public class McpServerConfig implements WebMvcConfigurer { return new GetPromptResult("A personalized greeting message", List.of(userMessage)); }); } - - @Bean - public OpenLibrary openLibrary() { - return new OpenLibrary(RestClient.builder()); - } - } diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServletServerApplication.java b/model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServletServerApplication.java similarity index 100% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServletServerApplication.java rename to model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/McpServletServerApplication.java diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java b/model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java similarity index 91% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java rename to model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java index b67b192..47bb548 100644 --- a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java +++ b/model-context-protocol/book-library/manual-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/server/OpenLibrary.java @@ -18,12 +18,14 @@ package org.springframework.ai.mcp.sample.servlet.server; import java.util.List; import java.util.Map; +import org.springframework.ai.tool.annotation.Tool; +import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; /** * @author Christian Tzolov */ - +@Service public class OpenLibrary { private RestClient restClient; @@ -38,6 +40,7 @@ public class OpenLibrary { public record Book(List isbn, String title, List authorName) { } + @Tool(description = "Search for books by title") public List getBooks(String title) { Books books = restClient.get() .uri(uriBuilder -> uriBuilder.path("/search.json").queryParam("q", title).build()) @@ -52,6 +55,7 @@ public class OpenLibrary { .toList(); } + @Tool(description = "Search for books by author") public List getBookTitlesByAuthor(String authorName) { var books = restClient.get() .uri(uriBuilder -> uriBuilder.path("/search/authors.json").queryParam("q", authorName).build()) diff --git a/model-context-protocol/mcp-servlet-server/src/main/resources/application.properties b/model-context-protocol/book-library/manual-servlet-server/src/main/resources/application.properties similarity index 100% rename from model-context-protocol/mcp-servlet-server/src/main/resources/application.properties rename to model-context-protocol/book-library/manual-servlet-server/src/main/resources/application.properties diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java similarity index 89% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java rename to model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java index bb1a768..87de741 100644 --- a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java +++ b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/ClientStdio.java @@ -15,8 +15,8 @@ */ package org.springframework.ai.mcp.sample.servlet.client; -import org.springframework.ai.mcp.client.transport.ServerParameters; -import org.springframework.ai.mcp.client.transport.StdioClientTransport; +import io.modelcontextprotocol.client.transport.ServerParameters; +import io.modelcontextprotocol.client.transport.StdioClientTransport; /** * With stdio transport, the MCP server is automatically started by the client. But you diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java similarity index 91% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java rename to model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java index 5155f85..44e841d 100644 --- a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java +++ b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/HttpClientSse.java @@ -15,7 +15,7 @@ */ package org.springframework.ai.mcp.sample.servlet.client; -import org.springframework.ai.mcp.client.transport.HttpClientSseClientTransport; +import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport; /** * @author Christian Tzolov diff --git a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java similarity index 81% rename from model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java rename to model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java index 1ba03ca..9d37bd4 100644 --- a/model-context-protocol/mcp-servlet-server/src/main/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java +++ b/model-context-protocol/book-library/manual-servlet-server/src/test/java/org/springframework/ai/mcp/sample/servlet/client/SampleClient.java @@ -17,14 +17,15 @@ package org.springframework.ai.mcp.sample.servlet.client; import java.util.Map; -import org.springframework.ai.mcp.client.McpClient; -import org.springframework.ai.mcp.spec.ClientMcpTransport; -import org.springframework.ai.mcp.spec.McpSchema.CallToolRequest; -import org.springframework.ai.mcp.spec.McpSchema.CallToolResult; -import org.springframework.ai.mcp.spec.McpSchema.GetPromptRequest; -import org.springframework.ai.mcp.spec.McpSchema.ListPromptsResult; -import org.springframework.ai.mcp.spec.McpSchema.ListToolsResult; -import org.springframework.ai.mcp.spec.McpSchema.ReadResourceRequest; +import io.modelcontextprotocol.client.McpClient; +import io.modelcontextprotocol.spec.ClientMcpTransport; +import io.modelcontextprotocol.spec.McpSchema.CallToolResult; +import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult; +import io.modelcontextprotocol.spec.McpSchema.ListToolsResult; +import io.modelcontextprotocol.spec.McpSchema.CallToolRequest; +import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest; +import io.modelcontextprotocol.spec.McpSchema.ReadResourceRequest; + /** * @author Christian Tzolov diff --git a/model-context-protocol/mcp-webflux-server/.flattened-pom.xml b/model-context-protocol/book-library/manual-webflux-server/.flattened-pom.xml similarity index 100% rename from model-context-protocol/mcp-webflux-server/.flattened-pom.xml rename to model-context-protocol/book-library/manual-webflux-server/.flattened-pom.xml diff --git a/model-context-protocol/mcp-weather-server-quickstart/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/book-library/manual-webflux-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-weather-server-quickstart/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/book-library/manual-webflux-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/mcp-webflux-server/README.md b/model-context-protocol/book-library/manual-webflux-server/README.md similarity index 100% rename from model-context-protocol/mcp-webflux-server/README.md rename to model-context-protocol/book-library/manual-webflux-server/README.md diff --git a/model-context-protocol/mcp-weather-server-quickstart/mvnw b/model-context-protocol/book-library/manual-webflux-server/mvnw similarity index 100% rename from model-context-protocol/mcp-weather-server-quickstart/mvnw rename to model-context-protocol/book-library/manual-webflux-server/mvnw diff --git a/model-context-protocol/mcp-weather-server-quickstart/mvnw.cmd b/model-context-protocol/book-library/manual-webflux-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-weather-server-quickstart/mvnw.cmd rename to model-context-protocol/book-library/manual-webflux-server/mvnw.cmd diff --git a/model-context-protocol/mcp-webflux-server/pom.xml b/model-context-protocol/book-library/manual-webflux-server/pom.xml similarity index 100% rename from model-context-protocol/mcp-webflux-server/pom.xml rename to model-context-protocol/book-library/manual-webflux-server/pom.xml diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java b/model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java similarity index 100% rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java rename to model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java b/model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java rename to model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java b/model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java rename to model-context-protocol/book-library/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/resources/application.properties b/model-context-protocol/book-library/manual-webflux-server/src/main/resources/application.properties similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/resources/application.properties rename to model-context-protocol/book-library/manual-webflux-server/src/main/resources/application.properties diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java b/model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java rename to model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java b/model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java rename to model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java b/model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java rename to model-context-protocol/book-library/manual-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java diff --git a/model-context-protocol/mcp-webmvc-server/.flattened-pom.xml b/model-context-protocol/book-library/manual-webmvc-server/.flattened-pom.xml similarity index 100% rename from model-context-protocol/mcp-webmvc-server/.flattened-pom.xml rename to model-context-protocol/book-library/manual-webmvc-server/.flattened-pom.xml diff --git a/model-context-protocol/mcp-weather-server-starter/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/book-library/manual-webmvc-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/book-library/manual-webmvc-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/mcp-webmvc-server/README.md b/model-context-protocol/book-library/manual-webmvc-server/README.md similarity index 100% rename from model-context-protocol/mcp-webmvc-server/README.md rename to model-context-protocol/book-library/manual-webmvc-server/README.md diff --git a/model-context-protocol/mcp-weather-server-starter/mvnw b/model-context-protocol/book-library/manual-webmvc-server/mvnw similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/mvnw rename to model-context-protocol/book-library/manual-webmvc-server/mvnw diff --git a/model-context-protocol/mcp-weather-server-starter/mvnw.cmd b/model-context-protocol/book-library/manual-webmvc-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/mvnw.cmd rename to model-context-protocol/book-library/manual-webmvc-server/mvnw.cmd diff --git a/model-context-protocol/mcp-webmvc-server/pom.xml b/model-context-protocol/book-library/manual-webmvc-server/pom.xml similarity index 100% rename from model-context-protocol/mcp-webmvc-server/pom.xml rename to model-context-protocol/book-library/manual-webmvc-server/pom.xml diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpMvcServerApplication.java b/model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpMvcServerApplication.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpMvcServerApplication.java rename to model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpMvcServerApplication.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpServerConfig.java b/model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpServerConfig.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpServerConfig.java rename to model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/McpServerConfig.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/OpenLibrary.java b/model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/OpenLibrary.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/OpenLibrary.java rename to model-context-protocol/book-library/manual-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/server/OpenLibrary.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/resources/application.properties b/model-context-protocol/book-library/manual-webmvc-server/src/main/resources/application.properties similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/resources/application.properties rename to model-context-protocol/book-library/manual-webmvc-server/src/main/resources/application.properties diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/ClientStdio.java b/model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/ClientStdio.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/ClientStdio.java rename to model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/ClientStdio.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/ClientWebFluxSse.java b/model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/ClientWebFluxSse.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/ClientWebFluxSse.java rename to model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/ClientWebFluxSse.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/HttpClientSse.java b/model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/HttpClientSse.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/HttpClientSse.java rename to model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/HttpClientSse.java diff --git a/model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/SampleClient.java b/model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/SampleClient.java similarity index 100% rename from model-context-protocol/mcp-webmvc-server/src/main/java/org/springframework/ai/mcp/sample/webmvc/client/SampleClient.java rename to model-context-protocol/book-library/manual-webmvc-server/src/test/java/org/springframework/ai/mcp/sample/webmvc/client/SampleClient.java diff --git a/model-context-protocol/mcp-weather-server/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/book-library/starter-webflux-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-weather-server/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/book-library/starter-webflux-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/mcp-webflux-server-starter/README.md b/model-context-protocol/book-library/starter-webflux-server/README.md similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/README.md rename to model-context-protocol/book-library/starter-webflux-server/README.md diff --git a/model-context-protocol/mcp-weather-server/mvnw b/model-context-protocol/book-library/starter-webflux-server/mvnw similarity index 100% rename from model-context-protocol/mcp-weather-server/mvnw rename to model-context-protocol/book-library/starter-webflux-server/mvnw diff --git a/model-context-protocol/mcp-weather-server/mvnw.cmd b/model-context-protocol/book-library/starter-webflux-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-weather-server/mvnw.cmd rename to model-context-protocol/book-library/starter-webflux-server/mvnw.cmd diff --git a/model-context-protocol/mcp-webflux-server-starter/pom.xml b/model-context-protocol/book-library/starter-webflux-server/pom.xml similarity index 63% rename from model-context-protocol/mcp-webflux-server-starter/pom.xml rename to model-context-protocol/book-library/starter-webflux-server/pom.xml index e055579..0dbad54 100644 --- a/model-context-protocol/mcp-webflux-server-starter/pom.xml +++ b/model-context-protocol/book-library/starter-webflux-server/pom.xml @@ -19,7 +19,6 @@ Sample Spring Boot application demonstrating MCP server usage - 0.7.0-SNAPSHOT 1.0.0-SNAPSHOT @@ -32,33 +31,14 @@ pom import - - io.modelcontextprotocol.sdk - mcp-bom - ${mcp.version} - pom - import - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - - org.springframework.ai - spring-ai-mcp-spring-boot-starter + spring-ai-mcp-server-webflux-spring-boot-starter - - - org.springframework.boot - spring-boot-starter-webflux - - @@ -66,27 +46,6 @@ org.springframework.boot spring-boot-maven-plugin - - - - repackage - - - - - - io.spring.javaformat - spring-javaformat-maven-plugin - 0.0.43 - - - validate - true - - validate - - - diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java b/model-context-protocol/book-library/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java rename to model-context-protocol/book-library/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java b/model-context-protocol/book-library/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java rename to model-context-protocol/book-library/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/OpenLibrary.java diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/resources/application.properties b/model-context-protocol/book-library/starter-webflux-server/src/main/resources/application.properties similarity index 76% rename from model-context-protocol/mcp-webflux-server-starter/src/main/resources/application.properties rename to model-context-protocol/book-library/starter-webflux-server/src/main/resources/application.properties index 751f64d..96c96b1 100644 --- a/model-context-protocol/mcp-webflux-server-starter/src/main/resources/application.properties +++ b/model-context-protocol/book-library/starter-webflux-server/src/main/resources/application.properties @@ -1,10 +1,9 @@ # NOTE: You must disable the banner and the console logging # to allow the STDIO transport to work !!! spring.main.banner-mode=off -logging.pattern.console= +# logging.pattern.console= logging.file.name=./model-context-protocol/mcp-webflux-server-starter/target/mcp.webflux-server-starter.log -spring.ai.mcp.server.enabled=true spring.ai.mcp.server.name=my-webflux-server-starter spring.ai.mcp.server.version=0.0.1 -spring.ai.mcp.server.transport=WEBFLUX + diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java b/model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java similarity index 93% rename from model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java rename to model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java index 43c1846..caacea6 100644 --- a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java +++ b/model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java @@ -31,7 +31,7 @@ public class ClientStdio { public static void main(String[] args) { var stdioParams = ServerParameters.builder("java") - .args("-Dspring.ai.mcp.server.transport=STDIO", "-Dspring.main.web-application-type=none", + .args("-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none", "-Dlogging.pattern.console=", "-jar", "model-context-protocol/mcp-webflux-server-starter/target/mcp-webflux-server-starter-0.0.1-SNAPSHOT.jar") .build(); diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java b/model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java rename to model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientWebFluxSse.java diff --git a/model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java b/model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java rename to model-context-protocol/book-library/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java diff --git a/model-context-protocol/brave-chatbot/pom.xml b/model-context-protocol/brave-chatbot/pom.xml index 5b31838..6adddc9 100644 --- a/model-context-protocol/brave-chatbot/pom.xml +++ b/model-context-protocol/brave-chatbot/pom.xml @@ -14,6 +14,7 @@ 0.0.1-SNAPSHOT Spring AI - Model Context Protocol - Brave Simple AI Application using MCP client to use Brave for Internet search + 17 @@ -31,14 +32,10 @@ - - org.springframework.boot - spring-boot-starter - org.springframework.ai - spring-ai-mcp-spring-boot-starter + spring-ai-mcp-client-spring-boot-starter diff --git a/model-context-protocol/brave-chatbot/src/main/resources/application.properties b/model-context-protocol/brave-chatbot/src/main/resources/application.properties index 903f1d7..5904948 100644 --- a/model-context-protocol/brave-chatbot/src/main/resources/application.properties +++ b/model-context-protocol/brave-chatbot/src/main/resources/application.properties @@ -3,5 +3,4 @@ spring.main.web-application-type=none spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} -spring.ai.mcp.client.stdio.enabled=true spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json \ No newline at end of file diff --git a/model-context-protocol/brave-starter/pom.xml b/model-context-protocol/brave-starter/pom.xml index efd980b..b14bbb1 100644 --- a/model-context-protocol/brave-starter/pom.xml +++ b/model-context-protocol/brave-starter/pom.xml @@ -31,14 +31,10 @@ - - org.springframework.boot - spring-boot-starter - - + org.springframework.ai - spring-ai-mcp-spring-boot-starter + spring-ai-mcp-client-spring-boot-starter @@ -46,11 +42,6 @@ spring-ai-openai-spring-boot-starter - - org.springframework.ai - spring-ai-mcp - - diff --git a/model-context-protocol/brave-starter/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java b/model-context-protocol/brave-starter/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java index 302cf19..cff3dbc 100644 --- a/model-context-protocol/brave-starter/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java +++ b/model-context-protocol/brave-starter/src/main/java/org/springframework/ai/mcp/samples/brave/Application.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.ai.mcp.samples.brave; import java.util.List; diff --git a/model-context-protocol/brave-starter/src/main/resources/application.properties b/model-context-protocol/brave-starter/src/main/resources/application.properties index ecb878b..294f176 100644 --- a/model-context-protocol/brave-starter/src/main/resources/application.properties +++ b/model-context-protocol/brave-starter/src/main/resources/application.properties @@ -4,5 +4,8 @@ spring.main.web-application-type=none spring.ai.openai.api-key=${OPENAI_API_KEY} spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} -spring.ai.mcp.client.stdio.enabled=true -spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json \ No newline at end of file +# spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json + +spring.ai.mcp.client.stdio.connections.brave-search.command=npx +spring.ai.mcp.client.stdio.connections.brave-search.args=-y,@modelcontextprotocol/server-brave-search +spring.ai.mcp.client.stdio.connections.brave-search.env.FOO=BAAR diff --git a/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.jar b/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..c1dd12f Binary files /dev/null and b/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.jar differ diff --git a/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..b7cb93e --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/model-context-protocol/client-starter/starter-default-client/mvnw b/model-context-protocol/client-starter/starter-default-client/mvnw new file mode 100755 index 0000000..eb65ff2 --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/mvnw @@ -0,0 +1,305 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ "$MVNW_REPOURL" = true]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/model-context-protocol/client-starter/starter-default-client/mvnw.cmd b/model-context-protocol/client-starter/starter-default-client/mvnw.cmd new file mode 100755 index 0000000..4f5150a --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/mvnw.cmd @@ -0,0 +1,172 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + ) + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/model-context-protocol/client-starter/starter-default-client/pom.xml b/model-context-protocol/client-starter/starter-default-client/pom.xml new file mode 100644 index 0000000..4735fb9 --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.6 + + + com.example + mcp-starter-default-client + 0.0.1-SNAPSHOT + Spring AI - MCP Starter Default Client + Spring AI - MCP Starter Default Client + + + 17 + 1.0.0-SNAPSHOT + + + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + + + + + org.springframework.ai + spring-ai-mcp-client-spring-boot-starter + + + + + + org.springframework.ai + spring-ai-anthropic-spring-boot-starter + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-default-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java b/model-context-protocol/client-starter/starter-default-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java new file mode 100644 index 0000000..c94e5fc --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java @@ -0,0 +1,55 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.mcp.samples.client; + +import java.util.List; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Value("${spring.ai.mcp.client.demo.user.input}") + private String userInput; + + @Bean + public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, List tools, + ConfigurableApplicationContext context) { + + return args -> { + + var chatClient = chatClientBuilder + .defaultTools(tools) + .build(); + + System.out.println("\n>>> QUESTION: " + userInput); + System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content()); + + context.close(); + }; + } +} \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties b/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties new file mode 100644 index 0000000..720d3d3 --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/src/main/resources/application.properties @@ -0,0 +1,14 @@ +spring.application.name=mcp +spring.main.web-application-type=none + +spring.ai.openai.api-key=${OPENAI_API_KEY} +spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} + +# spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json + +spring.ai.mcp.client.stdio.connections.brave-search.command=npx +spring.ai.mcp.client.stdio.connections.brave-search.args=-y,@modelcontextprotocol/server-brave-search +# spring.ai.mcp.client.stdio.connections.brave-search.env.FOO=BAAR + + +spring.ai.mcp.client.demo.user.input=What tools are available? \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-default-client/src/main/resources/mcp-servers-config.json b/model-context-protocol/client-starter/starter-default-client/src/main/resources/mcp-servers-config.json new file mode 100644 index 0000000..df98809 --- /dev/null +++ b/model-context-protocol/client-starter/starter-default-client/src/main/resources/mcp-servers-config.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "brave-search": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-brave-search" + ], + "env": { + } + } + } +} \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.jar b/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..c1dd12f Binary files /dev/null and b/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.jar differ diff --git a/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..b7cb93e --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/model-context-protocol/client-starter/starter-webflux-client/mvnw b/model-context-protocol/client-starter/starter-webflux-client/mvnw new file mode 100755 index 0000000..eb65ff2 --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/mvnw @@ -0,0 +1,305 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ "$MVNW_REPOURL" = true]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/model-context-protocol/client-starter/starter-webflux-client/mvnw.cmd b/model-context-protocol/client-starter/starter-webflux-client/mvnw.cmd new file mode 100755 index 0000000..4f5150a --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/mvnw.cmd @@ -0,0 +1,172 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + echo Found %WRAPPER_JAR% +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.2/maven-wrapper-0.5.2.jar" + ) + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/model-context-protocol/client-starter/starter-webflux-client/pom.xml b/model-context-protocol/client-starter/starter-webflux-client/pom.xml new file mode 100644 index 0000000..dede02b --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.3.6 + + + com.example + mcp-starter-webflux-client + 0.0.1-SNAPSHOT + Spring AI - MCP Starter WebFlux Client + Spring AI - MCP Starter WebFlux Client + + + 17 + 1.0.0-SNAPSHOT + + + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + + + + + org.springframework.ai + spring-ai-mcp-server-webmvc-spring-boot-starter + + + + + + org.springframework.ai + spring-ai-anthropic-spring-boot-starter + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + + + + \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-webflux-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java b/model-context-protocol/client-starter/starter-webflux-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java new file mode 100644 index 0000000..269ad98 --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/src/main/java/org/springframework/ai/mcp/samples/client/Application.java @@ -0,0 +1,55 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.mcp.samples.client; + +import java.util.List; + +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Value("${spring.ai.mcp.client.demo.user.input}") + private String userInput; + + @Bean + public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, List tools, + ConfigurableApplicationContext context) { + + return args -> { + + var chatClient = chatClientBuilder + .defaultTools(tools) + .build(); + + System.out.println("\n>>> QUESTION: " + userInput); + System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content()); + + context.close(); + }; + } +} \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties new file mode 100644 index 0000000..720d3d3 --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/application.properties @@ -0,0 +1,14 @@ +spring.application.name=mcp +spring.main.web-application-type=none + +spring.ai.openai.api-key=${OPENAI_API_KEY} +spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY} + +# spring.ai.mcp.client.stdio.servers-configuration=classpath:/mcp-servers-config.json + +spring.ai.mcp.client.stdio.connections.brave-search.command=npx +spring.ai.mcp.client.stdio.connections.brave-search.args=-y,@modelcontextprotocol/server-brave-search +# spring.ai.mcp.client.stdio.connections.brave-search.env.FOO=BAAR + + +spring.ai.mcp.client.demo.user.input=What tools are available? \ No newline at end of file diff --git a/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/mcp-servers-config.json b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/mcp-servers-config.json new file mode 100644 index 0000000..df98809 --- /dev/null +++ b/model-context-protocol/client-starter/starter-webflux-client/src/main/resources/mcp-servers-config.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "brave-search": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-brave-search" + ], + "env": { + } + } + } +} \ No newline at end of file diff --git a/model-context-protocol/mcp-weather-server-quickstart/README.md b/model-context-protocol/mcp-weather-server-quickstart/README.md deleted file mode 100644 index 1691961..0000000 --- a/model-context-protocol/mcp-weather-server-quickstart/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# Spring AI MCP Quick Weather Server Sample - -This sample project demonstrates a simplified implementation of the Spring AI Model Context Protocol (MCP). It shows how to create an MCP server that exposes weather-related tools using the National Weather Service API. - -## Overview - -The sample provides: -- A Spring Boot application implementing an MCP server -- Two transport mode implementations: Stdio and SSE (Server-Sent Events) -- Two weather-related tools: - - Get weather forecast by location (latitude/longitude) - - Get weather alerts by US state - -## Building the Project - -```bash -./mvnw clean package -``` - -## Running the Server - -The server can be started in two transport modes, controlled by the `transport.mode` property: - -### Stdio Mode (Default) - -```bash -java -Dspring.ai.mcp.server.transport=STDIO -Dspring.main.web-application-type=none -Dlogging.pattern.console= -jar target/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar -``` - -The Stdio mode server is automatically started by the client - no explicit server startup is needed. -But you have to build the server jar first: `./mvnw clean install -DskipTests`. - -In Stdio mode the server must not emit any messages/logs to the console (e.g. standard out) but the JSON messages produced by the server. - -### SSE Mode -```bash -java -Dspring.ai.mcp.server.transport=WEBFLUX -jar target/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar -``` - -## Sample Clients - -The project includes example clients for both transport modes: - -### Stdio Client (ClientStdio.java) -```java -var stdioParams = ServerParameters.builder("java") - .args("-Dspring.ai.mcp.server.transport=STDIO", "-Dspring.main.web-application-type=none", - "-Dlogging.pattern.console=", "-jar", - "model-context-protocol/mcp-weather-server-quick/target/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar") - .build(); - -var transport = new StdioClientTransport(stdioParams); -var client = McpClient.sync(transport).build(); -``` - -### SSE Client (ClientSse.java) -```java -var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080")); -var client = McpClient.using(transport).sync(); -``` - -### Claud Destop - -```json -{ - "mcpServers": { - "spring-ai-mcp-weather": { - "command": "java", - "args": [ - "-Dspring.ai.mcp.server.transport=STDIO", - "-Dspring.main.web-application-type=none", - "-Dlogging.pattern.console=", - "-jar", - "/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar" - ] - } - } -} -``` - -## Available Tools - -### Weather Forecast Tool -- Name: `getWeatherForecastByLocation` -- Description: Get weather forecast for a specific latitude/longitude -- Parameters: - - `latitude`: double - Latitude coordinate - - `longitude`: double - Longitude coordinate -- Example: -```java -CallToolResult forecastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", - Map.of("latitude", 47.6062, "longitude", -122.3321))); -``` - -### Weather Alerts Tool -- Name: `getAlerts` -- Description: Get weather alerts for a US state -- Parameters: - - `state`: String - Two-letter US state code (e.g. CA, NY) -- Example: -```java -CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", - Map.of("state", "NY"))); -``` - -## Client Usage Example - -```java -// Initialize client -client.initialize(); - -// Test connection -client.ping(); - -// List available tools -ListToolsResult tools = client.listTools(); -System.out.println("Available tools: " + tools); - -// Get weather forecast for Seattle -CallToolResult weatherForcastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", - Map.of("latitude", "47.6062", "longitude", "-122.3321"))); -System.out.println("Weather Forcast: " + weatherForcastResult); - -// Get weather alerts for New York -CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", Map.of("state", "NY"))); -System.out.println("Alert Response = " + alertResult); - -// Close client -client.closeGracefully(); -``` - -## Server Implementation - -The server is implemented using Spring Boot and Spring AI's tool annotations: - -```java -@SpringBootApplication -public class McpServerApplication { - - public static void main(String[] args) { - SpringApplication.run(McpServerApplication.class, args); - } - - @Bean - public List weatherTools(WeatherService weatherService) { - return List.of(ToolCallbacks.from(weatherService)); - } -} -``` - -The `WeatherService` class provides the tool implementations using the `@Tool` annotation: - -```java -@Service -public class WeatherService { - @Tool(description = "Get weather forecast for a specific latitude/longitude") - public String getWeatherForecastByLocation(double latitude, double longitude) { - // Implementation using weather.gov API - } - - @Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)") - public String getAlerts(String state) { - // Implementation using weather.gov API - } -} -``` - -## Configuration - -The application can be configured through `application.properties`: - -- `spring.ai.mcp.server.transport`: Transport mode to use (STDIO/WEBFLUX) -- `server.port`: Server port for WEBFLUX mode (default: 8080) -- `spring.main.banner-mode`: Set to 'off' for STDIO mode -- `logging.pattern.console`: Clear this property for STDIO mode -- `logging.file.name`: Path to log file (useful when console logging is disabled) diff --git a/model-context-protocol/mcp-weather-server-starter/README.md b/model-context-protocol/mcp-weather-server-starter/README.md deleted file mode 100644 index 9b91a92..0000000 --- a/model-context-protocol/mcp-weather-server-starter/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# Spring AI MCP Quick Weather Server Sample - -This sample project demonstrates a simplified implementation of the Spring AI Model Context Protocol (MCP). It shows how to create an MCP server that exposes weather-related tools using the National Weather Service API. - -## Overview - -The sample provides: -- A Spring Boot application implementing an MCP server -- Two transport mode implementations: Stdio and SSE (Server-Sent Events) -- Two weather-related tools: - - Get weather forecast by location (latitude/longitude) - - Get weather alerts by US state - -## Building the Project - -```bash -./mvnw clean install -DskipTests -``` - -## Running the Server - -The server can be started in two transport modes, controlled by the `transport.mode` property: - -### Stdio Mode (Default) - -The Stdio mode server is automatically started by the client - no explicit server startup is needed. -But you have to build the server jar first: `./mvnw clean install -DskipTests`. - -In Stdio mode the server must not emit any messages/logs to the console (e.g. standard out) but the JSON messages produced by the server. - -### SSE Mode -```bash -java -Dspring.ai.mcp.server.transport=WEBFLUX -jar target/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar -``` - -## Sample Clients - -The project includes example clients for both transport modes: - -### Stdio Client (ClientStdio.java) - -**Note:** When running via command line, you may need to specify the full path to your Java executable since the shell environment (including `.bashrc`) might not be loaded. For example, instead of `"java"`, you might need to use the full path like `"/home/user/.sdkman/candidates/java/current/bin/java"`. You can find your Java path by running `which java` in your terminal. - -```java -var stdioParams = ServerParameters.builder("java") // You may need to use full path to Java executable - .args("-Dspring.ai.mcp.server.transport=STDIO", "-Dspring.main.web-application-type=none", - "-Dlogging.pattern.console=", "-jar", - "model-context-protocol/mcp-weather-server-quick/target/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar") - .build(); - -var transport = new StdioClientTransport(stdioParams); -var client = McpClient.sync(transport).build(); -``` - -### SSE Client (ClientSse.java) -```java -var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080")); -var client = McpClient.using(transport).sync(); -``` - -### Claude Desktop - -```json -{ - "mcpServers": { - "spring-ai-mcp-weather": { - "command": "java", - "args": [ - "-Dspring.ai.mcp.server.transport=STDIO", - "-Dspring.main.web-application-type=none", - "-Dlogging.pattern.console=", - "-jar", - "/mcp-weather-server-quick-0.0.1-SNAPSHOT.jar" - ] - } - } -} -``` - -## Available Tools - -### Weather Forecast Tool -- Name: `getWeatherForecastByLocation` -- Description: Get weather forecast for a specific latitude/longitude -- Parameters: - - `latitude`: double - Latitude coordinate - - `longitude`: double - Longitude coordinate -- Example: -```java -CallToolResult forecastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", - Map.of("latitude", 47.6062, "longitude", -122.3321))); -``` - -### Weather Alerts Tool -- Name: `getAlerts` -- Description: Get weather alerts for a US state -- Parameters: - - `state`: String - Two-letter US state code (e.g. CA, NY) -- Example: -```java -CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", - Map.of("state", "NY"))); -``` - -## Client Usage Example (SampleClient.java) - -```java -// Initialize client -client.initialize(); - -// Test connection -client.ping(); - -// List available tools -ListToolsResult tools = client.listTools(); -System.out.println("Available tools: " + tools); - -// Get weather forecast for Seattle -CallToolResult weatherForcastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", - Map.of("latitude", "47.6062", "longitude", "-122.3321"))); -System.out.println("Weather Forcast: " + weatherForcastResult); - -// Get weather alerts for New York -CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", Map.of("state", "NY"))); -System.out.println("Alert Response = " + alertResult); - -// Close client -client.closeGracefully(); -``` - -## Server Implementation - -The server is implemented using Spring Boot and Spring AI's tool annotations: - -```java -@SpringBootApplication -public class McpServerApplication { - - public static void main(String[] args) { - SpringApplication.run(McpServerApplication.class, args); - } - - @Bean - public List weatherTools(WeatherService weatherService) { - return List.of(ToolCallbacks.from(weatherService)); - } -} -``` - -The `WeatherService` class provides the tool implementations using the `@Tool` annotation: - -```java -@Service -public class WeatherService { - @Tool(description = "Get weather forecast for a specific latitude/longitude") - public String getWeatherForecastByLocation(double latitude, double longitude) { - // Implementation using weather.gov API - } - - @Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)") - public String getAlerts(String state) { - // Implementation using weather.gov API - } -} -``` - -## Configuration - -The application can be configured through `application.properties`: - -- `spring.ai.mcp.server.transport`: Transport mode to use (STDIO/WEBFLUX) -- `server.port`: Server port for WEBFLUX mode (default: 8080) -- `spring.main.banner-mode`: Set to 'off' for STDIO mode -- `logging.pattern.console`: Clear this property for STDIO mode -- `logging.file.name`: Path to log file (useful when console logging is disabled) diff --git a/model-context-protocol/mcp-webflux-server-starter/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/weather/manual-webflux-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/weather/manual-webflux-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/mcp-weather-server/README.md b/model-context-protocol/weather/manual-webflux-server/README.md similarity index 100% rename from model-context-protocol/mcp-weather-server/README.md rename to model-context-protocol/weather/manual-webflux-server/README.md diff --git a/model-context-protocol/mcp-webflux-server-starter/mvnw b/model-context-protocol/weather/manual-webflux-server/mvnw similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/mvnw rename to model-context-protocol/weather/manual-webflux-server/mvnw diff --git a/model-context-protocol/mcp-webflux-server-starter/mvnw.cmd b/model-context-protocol/weather/manual-webflux-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-webflux-server-starter/mvnw.cmd rename to model-context-protocol/weather/manual-webflux-server/mvnw.cmd diff --git a/model-context-protocol/mcp-weather-server/pom.xml b/model-context-protocol/weather/manual-webflux-server/pom.xml similarity index 100% rename from model-context-protocol/mcp-weather-server/pom.xml rename to model-context-protocol/weather/manual-webflux-server/pom.xml diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java similarity index 100% rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java diff --git a/model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java similarity index 100% rename from model-context-protocol/mcp-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java similarity index 100% rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerConfig.java diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherApiClient.java b/model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherApiClient.java similarity index 100% rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherApiClient.java rename to model-context-protocol/weather/manual-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherApiClient.java diff --git a/model-context-protocol/mcp-weather-server/src/main/resources/application.properties b/model-context-protocol/weather/manual-webflux-server/src/main/resources/application.properties similarity index 100% rename from model-context-protocol/mcp-weather-server/src/main/resources/application.properties rename to model-context-protocol/weather/manual-webflux-server/src/main/resources/application.properties diff --git a/model-context-protocol/mcp-webflux-server/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/weather/starter-stdio-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-webflux-server/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/weather/starter-stdio-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/weather/starter-stdio-server/README.md b/model-context-protocol/weather/starter-stdio-server/README.md new file mode 100644 index 0000000..7d3d63b --- /dev/null +++ b/model-context-protocol/weather/starter-stdio-server/README.md @@ -0,0 +1,214 @@ +# Spring AI MCP Weather STDIO Server + +A Spring Boot starter project demonstrating how to build a Model Context Protocol (MCP) server that provides weather-related tools using the National Weather Service (weather.gov) API. This project showcases the Spring AI MCP Server Boot Starter capabilities with STDIO transport implementation. + +## Prerequisites + +- Java 17 or later +- Maven 3.6+ +- Basic understanding of Spring Boot and Spring AI +- (Optional) Claude Desktop for AI assistant integration + +## About Spring AI MCP Server Boot Starter + +This project uses `spring-ai-mcp-server-spring-boot-starter`, which provides: +- Automatic configuration of MCP server components +- Support for both synchronous and asynchronous operation modes +- STDIO transport layer implementation +- Flexible tool registration through Spring beans +- Change notification capabilities + +## Project Structure + +``` +src/ +├── main/ +│ ├── java/ +│ │ └── org/springframework/ai/mcp/sample/server/ +│ │ ├── McpServerApplication.java # Main application class with tool registration +│ │ └── WeatherService.java # Weather service implementation with MCP tools +│ └── resources/ +│ └── application.properties # Server and transport configuration +└── test/ + └── java/ + └── org/springframework/ai/mcp/sample/client/ + └── ClientStdio.java # Test client implementation +``` + +## Building and Running + +The server uses STDIO transport mode and is typically started automatically by the client. You only need to build the server jar: + +```bash +./mvnw clean install -DskipTests +``` + +## Tool Implementation + +The project demonstrates how to implement and register MCP tools using Spring's dependency injection and auto-configuration: + +```java +@Service +public class WeatherService { + + @Tool(description = "Get weather forecast for a specific latitude/longitude") + public String getWeatherForecastByLocation( + double latitude, // Latitude coordinate + double longitude // Longitude coordinate + ) { + // Implementation + } + + @Tool(description = "Get weather alerts for a US state") + public String getAlerts( + String state // Two-letter US state code (e.g. CA, NY) + ) { + // Implementation + } +} + +@SpringBootApplication +public class McpServerApplication { + @Bean + public List weatherTools(WeatherService weatherService) { + return ToolCallbacks.from(weatherService); + } +} +``` + +The auto-configuration will automatically register these tools with the MCP server. You can have multiple beans producing lists of ToolCallbacks, and the auto-configuration will merge them. + +## Available Tools + +### 1. Weather Forecast Tool +```java +@Tool(description = "Get weather forecast for a specific latitude/longitude") +public String getWeatherForecastByLocation( + double latitude, // Latitude coordinate + double longitude // Longitude coordinate +) { + // Returns detailed forecast including: + // - Temperature and unit + // - Wind speed and direction + // - Detailed forecast description +} + +// Example usage: +CallToolResult forecast = client.callTool( + new CallToolRequest("getWeatherForecastByLocation", + Map.of( + "latitude", 47.6062, // Seattle coordinates + "longitude", -122.3321 + ) + ) +); +``` + +### 2. Weather Alerts Tool +```java +@Tool(description = "Get weather alerts for a US state") +public String getAlerts( + String state // Two-letter US state code (e.g. CA, NY) +) { + // Returns active alerts including: + // - Event type + // - Affected area + // - Severity + // - Description + // - Safety instructions +} + +// Example usage: +CallToolResult alerts = client.callTool( + new CallToolRequest("getAlerts", + Map.of("state", "NY") + ) +); +``` + +## Client Integration + +### Java Client Example + +```java +// Create server parameters +ServerParameters stdioParams = ServerParameters.builder("java") + .args("-Dspring.ai.mcp.server.transport=STDIO", + "-Dspring.main.web-application-type=none", + "-Dlogging.pattern.console=", + "-jar", + "target/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar") + .build(); + +// Initialize transport and client +var transport = new StdioClientTransport(stdioParams); +var client = McpClient.sync(transport).build(); +``` + +### Claude Desktop Integration + +To integrate with Claude Desktop, add the following configuration to your Claude Desktop settings: + +```json +{ + "mcpServers": { + "spring-ai-mcp-weather": { + "command": "java", + "args": [ + "-Dspring.ai.mcp.server.transport=STDIO", + "-Dspring.main.web-application-type=none", + "-Dlogging.pattern.console=", + "-jar", + "/absolute/path/to/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar" + ] + } + } +} +``` + +Replace `/absolute/path/to/` with the actual path to your built jar file. + +## Configuration + +### Application Properties + +All properties are prefixed with `spring.ai.mcp.server` + + +```properties +# Required STDIO Configuration +spring.main.web-application-type=none +spring.main.banner-mode=off +logging.pattern.console= + +# Server Configuration +spring.ai.mcp.server.enabled=true +spring.ai.mcp.server.name=my-weather-server +spring.ai.mcp.server.version=0.0.1 +# SYNC or ASYNC +spring.ai.mcp.server.type=SYNC +spring.ai.mcp.server.resource-change-notification=true +spring.ai.mcp.server.tool-change-notification=true +spring.ai.mcp.server.prompt-change-notification=true + +# Optional file logging +logging.file.name=mcp-weather-stdio-server.log +``` + +### Key Configuration Notes + +1. **STDIO Mode Requirements**: + - Disable web application type (`spring.main.web-application-type=none`) + - Disable Spring banner (`spring.main.banner-mode=off`) + - Clear console logging pattern (`logging.pattern.console=`) + +2. **Server Type**: + - `SYNC` (default): Uses `McpSyncServer` for straightforward request-response patterns + - `ASYNC`: Uses `McpAsyncServer` for non-blocking operations with Project Reactor support + +## Additional Resources + +- [Spring AI Documentation](https://docs.spring.io/spring-ai/reference/) +- [Model Context Protocol Specification](https://modelcontextprotocol.github.io/specification/) +- [Spring Boot Auto-configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration) + diff --git a/model-context-protocol/mcp-webflux-server/mvnw b/model-context-protocol/weather/starter-stdio-server/mvnw similarity index 100% rename from model-context-protocol/mcp-webflux-server/mvnw rename to model-context-protocol/weather/starter-stdio-server/mvnw diff --git a/model-context-protocol/mcp-webflux-server/mvnw.cmd b/model-context-protocol/weather/starter-stdio-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-webflux-server/mvnw.cmd rename to model-context-protocol/weather/starter-stdio-server/mvnw.cmd diff --git a/model-context-protocol/mcp-weather-server-quickstart/pom.xml b/model-context-protocol/weather/starter-stdio-server/pom.xml similarity index 62% rename from model-context-protocol/mcp-weather-server-quickstart/pom.xml rename to model-context-protocol/weather/starter-stdio-server/pom.xml index 8637347..18ec531 100644 --- a/model-context-protocol/mcp-weather-server-quickstart/pom.xml +++ b/model-context-protocol/weather/starter-stdio-server/pom.xml @@ -12,15 +12,12 @@ com.example - mcp-weather-server-quickstart + mcp-weather-stdio-server 0.0.1-SNAPSHOT - Spring AI MCP Weather Sample - Sample Spring Boot application demonstrating MCP client and server usage + Spring AI MCP Weather STDIO server + Sample Spring Boot application demonstrating MCP stdio server usage - - 0.7.0-SNAPSHOT - @@ -31,34 +28,19 @@ pom import - - - io.modelcontextprotocol.sdk - mcp-bom - ${mcp.version} - pom - import - - org.springframework.ai - spring-ai-mcp-spring-boot-starter + spring-ai-mcp-server-spring-boot-starter - + org.springframework spring-web - - - org.springframework.boot - spring-boot-starter - - @@ -66,27 +48,6 @@ org.springframework.boot spring-boot-maven-plugin - - - - repackage - - - - - - io.spring.javaformat - spring-javaformat-maven-plugin - 0.0.43 - - - validate - true - - validate - - - diff --git a/model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java b/model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java similarity index 100% rename from model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java rename to model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java diff --git a/model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java b/model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java similarity index 100% rename from model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java rename to model-context-protocol/weather/starter-stdio-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java diff --git a/model-context-protocol/mcp-weather-server-quickstart/src/main/resources/application.properties b/model-context-protocol/weather/starter-stdio-server/src/main/resources/application.properties similarity index 68% rename from model-context-protocol/mcp-weather-server-quickstart/src/main/resources/application.properties rename to model-context-protocol/weather/starter-stdio-server/src/main/resources/application.properties index 9a78228..eb07a22 100644 --- a/model-context-protocol/mcp-weather-server-quickstart/src/main/resources/application.properties +++ b/model-context-protocol/weather/starter-stdio-server/src/main/resources/application.properties @@ -10,5 +10,5 @@ spring.ai.mcp.server.enabled=true spring.ai.mcp.server.name=my-weather-server spring.ai.mcp.server.version=0.0.1 -logging.file.name=./model-context-protocol/mcp-weather-server-quickstart/target/mcp.weather-quickstart.log +logging.file.name=./model-context-protocol/weather/mcp-weather-stdio-server/mcp-weather-server-quickstart/target/mcp-weather-stdio-server.log diff --git a/model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java b/model-context-protocol/weather/starter-stdio-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java similarity index 93% rename from model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java rename to model-context-protocol/weather/starter-stdio-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java index cbb92d6..fce3a1a 100644 --- a/model-context-protocol/mcp-weather-server-quickstart/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java +++ b/model-context-protocol/weather/starter-stdio-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java @@ -15,7 +15,6 @@ */ package org.springframework.ai.mcp.sample.client; -import java.io.File; import java.util.Map; import io.modelcontextprotocol.client.McpClient; @@ -39,7 +38,7 @@ public class ClientStdio { var stdioParams = ServerParameters.builder("java") .args("-jar", - "model-context-protocol/mcp-weather-server-quickstart/target/mcp-weather-server-quickstart-0.0.1-SNAPSHOT.jar") + "model-context-protocol/weather/starter-stdio-server/target/mcp-weather-stdio-server-0.0.1-SNAPSHOT.jar") .build(); var transport = new StdioClientTransport(stdioParams); diff --git a/model-context-protocol/mcp-webmvc-server/.mvn/wrapper/maven-wrapper.properties b/model-context-protocol/weather/starter-webflux-server/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from model-context-protocol/mcp-webmvc-server/.mvn/wrapper/maven-wrapper.properties rename to model-context-protocol/weather/starter-webflux-server/.mvn/wrapper/maven-wrapper.properties diff --git a/model-context-protocol/weather/starter-webflux-server/README.md b/model-context-protocol/weather/starter-webflux-server/README.md new file mode 100644 index 0000000..1c52dea --- /dev/null +++ b/model-context-protocol/weather/starter-webflux-server/README.md @@ -0,0 +1,213 @@ +# Spring AI MCP Weather Server Sample with WebFlux Starter + +This sample project demonstrates how to create an MCP server using the Spring AI MCP Server Boot Starter with WebFlux transport. It implements a weather service that exposes tools for retrieving weather information using the National Weather Service API. + +## Overview + +The sample showcases: +- Integration with `spring-ai-mcp-server-webflux-spring-boot-starter` +- Support for both SSE (Server-Sent Events) and STDIO transports +- Automatic tool registration using Spring AI's `@Tool` annotation +- Two weather-related tools: + - Get weather forecast by location (latitude/longitude) + - Get weather alerts by US state + +## Dependencies + +The project uses the Spring AI MCP Server WebFlux Boot Starter: + +```xml + + org.springframework.ai + spring-ai-mcp-server-webflux-spring-boot-starter + +``` + +This starter provides: +- Reactive transport using Spring WebFlux (`WebFluxSseServerTransport`) +- Automatically configured reactive SSE endpoints +- Optional STDIO transport +- Included `spring-boot-starter-webflux` and `mcp-spring-webflux` dependencies + +## Building the Project + +```bash +./mvnw clean install -DskipTests +``` + +## Running the Server + +The server supports two transport modes: + +### WebFlux SSE Mode (Default) +```bash +java -jar target/mcp-weather-starter-webflux-server-0.0.1-SNAPSHOT.jar +``` + +### STDIO Mode +Enable STDIO transport by setting the appropriate properties: +```bash +java -Dspring.ai.mcp.server.stdio=true -Dspring.main.web-application-type=none -jar target/mcp-weather-starter-webflux-server-0.0.1-SNAPSHOT.jar +``` + +## Configuration + +The server can be configured through `application.properties`: + +```properties +# Server identification +spring.ai.mcp.server.name=my-weather-server +spring.ai.mcp.server.version=0.0.1 + +# Server type (SYNC/ASYNC) +spring.ai.mcp.server.type=SYNC + +# Transport configuration +spring.ai.mcp.server.stdio=false +spring.ai.mcp.server.sse-message-endpoint=/mcp/message + +# Change notifications +spring.ai.mcp.server.resource-change-notification=true +spring.ai.mcp.server.tool-change-notification=true +spring.ai.mcp.server.prompt-change-notification=true + +# Logging (required for STDIO transport) +spring.main.banner-mode=off +logging.file.name=./target/starter-webflux-server.log +``` + +## Sample Clients + +### WebFlux SSE Client +```java +var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080")); +var client = McpClient.sync(transport).build(); +``` + +### STDIO Client +```java +var stdioParams = ServerParameters.builder("java") + .args("-Dspring.ai.mcp.server.stdio=true", + "-Dspring.main.web-application-type=none", + "-Dspring.main.banner-mode=off", + "-Dlogging.pattern.console=", + "-jar", + "target/mcp-weather-starter-webflux-server-0.0.1-SNAPSHOT.jar") + .build(); + +var transport = new StdioClientTransport(stdioParams); +var client = McpClient.sync(transport).build(); +``` + +### Claude Desktop Configuration + +```json +{ + "mcpServers": { + "spring-ai-mcp-weather": { + "command": "java", + "args": [ + "-Dspring.ai.mcp.server.stdio=true", + "-Dspring.main.web-application-type=none", + "-Dspring.main.banner-mode=off", + "-Dlogging.pattern.console=", + "-jar", + "/mcp-weather-starter-webflux-server-0.0.1-SNAPSHOT.jar" + ] + } + } +} +``` + +## Available Tools + +### Weather Forecast Tool +- Name: `getWeatherForecastByLocation` +- Description: Get weather forecast for a specific latitude/longitude +- Parameters: + - `latitude`: double - Latitude coordinate + - `longitude`: double - Longitude coordinate +- Example: +```java +CallToolResult forecastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", + Map.of("latitude", 47.6062, "longitude", -122.3321))); +``` + +### Weather Alerts Tool +- Name: `getAlerts` +- Description: Get weather alerts for a US state +- Parameters: + - `state`: String - Two-letter US state code (e.g. CA, NY) +- Example: +```java +CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", + Map.of("state", "NY"))); +``` + +## Server Implementation + +The server uses Spring Boot and Spring AI's tool annotations for automatic tool registration: + +```java +@SpringBootApplication +public class McpServerApplication { + + public static void main(String[] args) { + SpringApplication.run(McpServerApplication.class, args); + } + + @Bean + public List weatherTools(WeatherService weatherService) { + return List.of(ToolCallbacks.from(weatherService)); + } +} +``` + +The `WeatherService` implements the weather tools using the `@Tool` annotation: + +```java +@Service +public class WeatherService { + @Tool(description = "Get weather forecast for a specific latitude/longitude") + public String getWeatherForecastByLocation(double latitude, double longitude) { + // Implementation using weather.gov API + } + + @Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)") + public String getAlerts(String state) { + // Implementation using weather.gov API + } +} +``` + +## Client Usage Example + +```java +// Initialize client +client.initialize(); + +// Test connection +client.ping(); + +// List available tools +ListToolsResult tools = client.listTools(); +System.out.println("Available tools: " + tools); + +// Get weather forecast for Seattle +CallToolResult weatherForcastResult = client.callTool(new CallToolRequest("getWeatherForecastByLocation", + Map.of("latitude", 47.6062, "longitude", -122.3321))); +System.out.println("Weather Forecast: " + weatherForcastResult); + +// Get weather alerts for New York +CallToolResult alertResult = client.callTool(new CallToolRequest("getAlerts", Map.of("state", "NY"))); +System.out.println("Alert Response = " + alertResult); + +// Close client +client.closeGracefully(); +``` + +## Additional Resources + +* [Spring AI Documentation](https://docs.spring.io/spring-ai/reference/) +* [Model Context Protocol Specification](https://modelcontextprotocol.github.io/specification/) +* [Spring Boot Auto-configuration](https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-auto-configuration) diff --git a/model-context-protocol/mcp-webmvc-server/mvnw b/model-context-protocol/weather/starter-webflux-server/mvnw similarity index 100% rename from model-context-protocol/mcp-webmvc-server/mvnw rename to model-context-protocol/weather/starter-webflux-server/mvnw diff --git a/model-context-protocol/mcp-webmvc-server/mvnw.cmd b/model-context-protocol/weather/starter-webflux-server/mvnw.cmd similarity index 100% rename from model-context-protocol/mcp-webmvc-server/mvnw.cmd rename to model-context-protocol/weather/starter-webflux-server/mvnw.cmd diff --git a/model-context-protocol/mcp-weather-server-starter/pom.xml b/model-context-protocol/weather/starter-webflux-server/pom.xml similarity index 56% rename from model-context-protocol/mcp-weather-server-starter/pom.xml rename to model-context-protocol/weather/starter-webflux-server/pom.xml index d37b3cf..93bae11 100644 --- a/model-context-protocol/mcp-weather-server-starter/pom.xml +++ b/model-context-protocol/weather/starter-webflux-server/pom.xml @@ -12,16 +12,12 @@ com.example - mcp-weather-server-starter + mcp-weather-starter-webflux-server 0.0.1-SNAPSHOT Spring AI MCP Weather Sample Sample Spring Boot application demonstrating MCP client and server usage - - 0.7.0-SNAPSHOT - - @@ -31,42 +27,13 @@ pom import - - - io.modelcontextprotocol.sdk - mcp-bom - ${mcp.version} - pom - import - org.springframework.ai - spring-ai-core - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - - - - org.springframework.ai - spring-ai-mcp-spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-webflux - - - - org.springframework.boot - spring-boot-starter-test - test + spring-ai-mcp-server-webflux-spring-boot-starter @@ -75,27 +42,6 @@ org.springframework.boot spring-boot-maven-plugin - - - - repackage - - - - - - io.spring.javaformat - spring-javaformat-maven-plugin - 0.0.43 - - - validate - true - - validate - - - diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java b/model-context-protocol/weather/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java similarity index 62% rename from model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java rename to model-context-protocol/weather/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java index 774a2ac..60af7e7 100644 --- a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java +++ b/model-context-protocol/weather/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/McpServerApplication.java @@ -4,6 +4,7 @@ import java.util.List; import org.springframework.ai.tool.ToolCallback; import org.springframework.ai.tool.ToolCallbacks; +import org.springframework.ai.tool.function.FunctionToolCallback; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -20,4 +21,16 @@ public class McpServerApplication { return List.of(ToolCallbacks.from(weatherService)); } + public record TextInput(String input) { + } + + @Bean + public List toUpperCase() { + var tool = FunctionToolCallback.builder("toUpperCase", (TextInput input) -> input.input().toUpperCase()) + .inputType(TextInput.class) + .description("Put the text to upper case") + .build(); + return List.of(tool); + } + } diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java b/model-context-protocol/weather/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java similarity index 100% rename from model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java rename to model-context-protocol/weather/starter-webflux-server/src/main/java/org/springframework/ai/mcp/sample/server/WeatherService.java diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/resources/application.properties b/model-context-protocol/weather/starter-webflux-server/src/main/resources/application.properties similarity index 61% rename from model-context-protocol/mcp-weather-server-starter/src/main/resources/application.properties rename to model-context-protocol/weather/starter-webflux-server/src/main/resources/application.properties index f740026..7d7756a 100644 --- a/model-context-protocol/mcp-weather-server-starter/src/main/resources/application.properties +++ b/model-context-protocol/weather/starter-webflux-server/src/main/resources/application.properties @@ -5,12 +5,7 @@ spring.main.banner-mode=off # logging.pattern.console= -spring.ai.mcp.server.enabled=true - spring.ai.mcp.server.name=my-weather-server spring.ai.mcp.server.version=0.0.1 -spring.ai.mcp.server.transport=WEBFLUX - -logging.file.name=./model-context-protocol/mcp-weather-server-starter/target/mcp.weather-starter.log - +logging.file.name=./model-context-protocol/weather/starter-webflux-server/target/starter-webflux-server.log diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java b/model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientSse.java similarity index 99% rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java rename to model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientSse.java index 836dc41..1becf0a 100644 --- a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/ClientSse.java +++ b/model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientSse.java @@ -26,7 +26,6 @@ public class ClientSse { public static void main(String[] args) { var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080")); - new SampleClient(transport).run(); } diff --git a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java b/model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java similarity index 80% rename from model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java rename to model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java index 6374cab..573fdd6 100644 --- a/model-context-protocol/mcp-weather-server-starter/src/main/java/org/springframework/ai/mcp/sample/client/ClientStdio.java +++ b/model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/ClientStdio.java @@ -21,7 +21,8 @@ import io.modelcontextprotocol.client.transport.ServerParameters; import io.modelcontextprotocol.client.transport.StdioClientTransport; /** - * With stdio transport, the MCP server is automatically started by the client. But you + * With stdio transport, the MCP server is automatically started by the client. + * But you * have to build the server jar first: * *
@@ -35,10 +36,10 @@ public class ClientStdio {
 		System.out.println(new File(".").getAbsolutePath());
 
 		var stdioParams = ServerParameters.builder("java")
-			.args("-Dspring.ai.mcp.server.transport=STDIO", "-Dspring.main.web-application-type=none",
-					"-Dlogging.pattern.console=", "-jar",
-					"model-context-protocol/mcp-weather-server-starter/target/mcp-weather-server-starter-0.0.1-SNAPSHOT.jar")
-			.build();
+				.args("-Dspring.ai.mcp.server.stdio=true", "-Dspring.main.web-application-type=none",
+						"-Dlogging.pattern.console=", "-jar",
+						"model-context-protocol/weather/starter-webflux-server/target/mcp-weather-starter-webflux-server-0.0.1-SNAPSHOT.jar")
+				.build();
 
 		var transport = new StdioClientTransport(stdioParams);
 
diff --git a/model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java b/model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java
similarity index 100%
rename from model-context-protocol/mcp-weather-server/src/main/java/org/springframework/ai/mcp/sample/client/SampleClient.java
rename to model-context-protocol/weather/starter-webflux-server/src/test/java/org/springframework/ai/mcp/sample/client/SampleClient.java
diff --git a/pom.xml b/pom.xml
index de36e88..9b30a73 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,17 +23,28 @@
 		misc/openai-streaming-response
 		model-context-protocol/sqlite/simple
 		model-context-protocol/sqlite/chatbot
+		
 		model-context-protocol/filesystem
+		
 		model-context-protocol/brave
 		model-context-protocol/brave-starter
 		model-context-protocol/brave-chatbot
-		model-context-protocol/mcp-webmvc-server
-		model-context-protocol/mcp-webflux-server
-		model-context-protocol/mcp-webflux-server-starter
-		model-context-protocol/mcp-servlet-server
-		model-context-protocol/mcp-weather-server
-		model-context-protocol/mcp-weather-server-starter
-		model-context-protocol/mcp-weather-server-quickstart
+
+		model-context-protocol/book-library/manual-webmvc-server
+		model-context-protocol/book-library/manual-webflux-server
+		model-context-protocol/book-library/starter-webflux-server
+		model-context-protocol/book-library/manual-servlet-server
+		
+		model-context-protocol/weather/java-client
+		model-context-protocol/weather/starter-webflux-server
+		model-context-protocol/weather/starter-stdio-server
+		model-context-protocol/weather/manual-webflux-server
+		
+		
+		model-context-protocol/client-starter/starter-default-client
+		model-context-protocol/client-starter/starter-webflux-client
+
+
 		agentic-patterns