<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arvind Menon</title>
    <description>The latest articles on DEV Community by Arvind Menon (@arvindand).</description>
    <link>https://dev.to/arvindand</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3377808%2Fd672552e-2160-48c8-a5bb-b8d338d33c28.jpg</url>
      <title>DEV Community: Arvind Menon</title>
      <link>https://dev.to/arvindand</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arvindand"/>
    <language>en</language>
    <item>
      <title>Guided Delegation: Adding Context7 Documentation to My Maven Tools MCP Server</title>
      <dc:creator>Arvind Menon</dc:creator>
      <pubDate>Wed, 06 Aug 2025 17:50:44 +0000</pubDate>
      <link>https://dev.to/arvindand/guided-delegation-adding-context7-documentation-to-my-maven-tools-mcp-server-572l</link>
      <guid>https://dev.to/arvindand/guided-delegation-adding-context7-documentation-to-my-maven-tools-mcp-server-572l</guid>
      <description>&lt;p&gt;How guided delegation bridges dependency analysis with up-to-date docs.&lt;/p&gt;




&lt;p&gt;A while back I wrote about &lt;a href="https://dev.to/arvindand/how-i-connected-claude-to-maven-central-and-why-you-should-too-2clo"&gt;building a Maven Central MCP server&lt;/a&gt; so Claude / Copilot can answer the boring dependency questions straight from Maven Central.&lt;/p&gt;

&lt;p&gt;It worked well for “what version should I be on?”&lt;/p&gt;

&lt;p&gt;On major upgrades, updating the POM was only part of the work. Breaking changes could still leave me searching through documentation and fixing the resulting build failures. I wanted the assistant to have that documentation available while working through the upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gap: From “What to Upgrade” to “How to Upgrade”
&lt;/h2&gt;

&lt;p&gt;My Maven tools can tell you things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the latest stable version is&lt;/li&gt;
&lt;li&gt;Whether an update is major/minor/patch&lt;/li&gt;
&lt;li&gt;Which dependencies are aging or stale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That gets you to a decision. It doesn’t get you through the upgrade.&lt;/p&gt;

&lt;p&gt;For anything non-trivial you still end up hunting for the right migration guide or “breaking changes” doc. And if the assistant falls back to generic web search, you quickly get stale or out-of-context advice.&lt;/p&gt;

&lt;p&gt;That's where &lt;a href="https://github.com/upstash/context7" rel="noopener noreferrer"&gt;Context7&lt;/a&gt; fits in. It retrieves indexed library documentation, including version-specific documentation where it's available. The assistant still needs to check that the result covers the version being targeted. If it doesn't, it can look for the project's migration guide or release notes using its own web-search tools, if available.&lt;/p&gt;

&lt;p&gt;So the real problem became: how do I combine “Maven intelligence” with “current docs” without jamming everything into one big server?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Approach: Guided Delegation
&lt;/h2&gt;

&lt;p&gt;I didn’t want to re-implement Context7 inside my project. I just wanted a clean workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Maven Tools does the analysis (versions, stability, update type)&lt;/li&gt;
&lt;li&gt;If it looks like a potentially painful upgrade, it returns an extra field with explicit orchestration instructions&lt;/li&gt;
&lt;li&gt;The assistant uses those instructions to call Context7 tools (or fall back to normal web search)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Maven analysis returns hints for the next documentation lookup. The assistant decides whether to follow them. With Context7 enabled, Maven Tools also exposes its documentation tools through the same server, forwarding those calls to Context7. The analysis doesn't automatically run the documentation lookup. That's what I mean by guided delegation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation: Dual MCP Architecture with Spring AI
&lt;/h2&gt;

&lt;p&gt;This ended up being mostly configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) Wire Context7 as an MCP client
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://github.com/arvindand/maven-tools-mcp/blob/main/src/main/resources/application.yaml" rel="noopener noreferrer"&gt;src/main/resources/application.yaml&lt;/a&gt; I enable the MCP client and tool callback, and point it at Context7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ASYNC&lt;/span&gt;
        &lt;span class="na"&gt;request-timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
        &lt;span class="na"&gt;toolcallback&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;streamable-http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;context7&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://mcp.context7.com/&lt;/span&gt;

&lt;span class="na"&gt;context7&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that, Spring AI connects to Context7 and exposes its tools alongside my Maven tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Add “guidance hints” to the response models
&lt;/h3&gt;

&lt;p&gt;On the Maven side, I don’t call Context7 directly. I just include a &lt;code&gt;context7_guidance&lt;/code&gt; field when Context7 is enabled.&lt;/p&gt;

&lt;p&gt;Here’s the rough shape of the tool method (trimmed down, but with the real parameters):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bulk upgrade check (versions REQUIRED in input)."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ToolResponse&lt;/span&gt; &lt;span class="nf"&gt;compare_dependency_versions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;currentDependencies&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;StabilityFilter&lt;/span&gt; &lt;span class="n"&gt;stabilityFilter&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;includeSecurityScan&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;executeToolOperation&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... compare versions, optionally scan with OSV&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;VersionComparison&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;securitySummary&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the per-dependency comparison result can include a guidance block like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"comparison_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-06T12:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework.boot:spring-boot-starter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"current_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.7.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"latest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"major"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update_available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"context7_guidance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"orchestration_instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Use resolve-library-id tool with query='spring-boot-starter migration guide breaking changes' and libraryName='spring-boot-starter' to find the library ID. Then use query-docs tool with the returned libraryId and query='spring-boot-starter migration guide breaking changes' to get upgrade instructions. If Context7 doesn't provide sufficient information, perform a web search for 'spring-boot-starter major version upgrade guide'."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"update_summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"major_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minor_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"patch_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"no_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That string looks a bit verbose on purpose: it’s meant to be copy-pasteable instructions for the model, not a nice message for humans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Notes
&lt;/h2&gt;

&lt;p&gt;If you’re running the Docker image, you don’t need a separate Context7 server. The container will call out to &lt;code&gt;https://mcp.context7.com/&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If your network blocks it, the README documents a Context7-free image: &lt;code&gt;arvindand/maven-tools-mcp:latest-noc7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;There’s also a profile that disables the MCP client entirely (see &lt;a href="https://github.com/arvindand/maven-tools-mcp/blob/main/src/main/resources/application-no-context7.yaml" rel="noopener noreferrer"&gt;src/main/resources/application-no-context7.yaml&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Changed for Me
&lt;/h2&gt;

&lt;p&gt;The practical difference is that a major upgrade conversation doesn’t stall out after “this is a major update”. The assistant can immediately pull the right docs and keep going.&lt;/p&gt;

&lt;p&gt;Also: keeping this as “compose tools + add orchestration hints” felt a lot cleaner than turning Maven Tools into a documentation scraper.&lt;/p&gt;

&lt;p&gt;If you try it, I’m curious about two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are the &lt;code&gt;context7_guidance&lt;/code&gt; instructions actually helpful in your upgrade scenarios?&lt;/li&gt;
&lt;li&gt;Where do they fall short (too generic, too verbose, wrong query phrasing, etc.)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the repo if you haven't yet - &lt;a href="https://github.com/arvindand/maven-tools-mcp" rel="noopener noreferrer"&gt;github.com/arvindand/maven-tools-mcp&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;: I'm a software architect at Rockwell Automation. I write about architecture, developer tooling, and the use of AI in software engineering. You can find me on &lt;a href="https://github.com/arvindand" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or &lt;a href="https://linkedin.com/in/arvindsmenon/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated September 2026 to clarify tool behaviour and limitations.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>springboot</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How I Connected Claude to Maven Central (And Why You Should Too)</title>
      <dc:creator>Arvind Menon</dc:creator>
      <pubDate>Sat, 26 Jul 2025 22:53:22 +0000</pubDate>
      <link>https://dev.to/arvindand/how-i-connected-claude-to-maven-central-and-why-you-should-too-2clo</link>
      <guid>https://dev.to/arvindand/how-i-connected-claude-to-maven-central-and-why-you-should-too-2clo</guid>
      <description>&lt;p&gt;&lt;em&gt;A Spring developer's journey into the Model Context Protocol&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I've spent almost a decade building and maintaining Spring/JVM systems in enterprise environments. As I've started learning more about AI—and integrating it into my daily workflows—I had a simple idea: use what I already know (Spring) to shave off the small, annoying bits of daily dev work.&lt;/p&gt;

&lt;p&gt;Lately I've been trying to use AI for the parts of development that are mostly "mechanical". One of the first places I felt it: dependency lookups in bigger projects.&lt;/p&gt;

&lt;p&gt;In a bigger codebase it's rarely one lookup. It's the same loop repeated across a long list of libraries: search the artifact, find the latest stable version, check whether it's still actively maintained, maybe skim for CVEs… and move on to the next one.&lt;/p&gt;

&lt;p&gt;None of that is complicated. It's just time.&lt;/p&gt;

&lt;p&gt;When I came across the Model Context Protocol (MCP)—a standard for giving AI assistants access to tools—I realized I could turn that loop into something Claude (or GitHub Copilot) could do directly. Same answers, fewer tabs, and I stay in the editor.&lt;/p&gt;

&lt;p&gt;That's how &lt;strong&gt;Maven Tools MCP Server&lt;/strong&gt; happened. It's not meant to replace Dependabot, Renovate, or the kind of CI/CD setup you need for compliance and automated updates. This is for the "I just need to know what's going on with my dependencies right now" moments—through the AI assistant you're already using.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Looks Like
&lt;/h2&gt;

&lt;p&gt;Before the technical bits, here's what this looks like in real life. Instead of opening a pile of browser tabs, I paste my build file and ask:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Check all these dependencies for updates, but only show me stable versions since this is going to production"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The assistant checks the dependencies, tells me what needs attention, and groups available updates as major, minor, or patch. Those categories help me decide what to investigate; they don't guarantee compatibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Challenge (And Why Spring Made It Easy)
&lt;/h2&gt;

&lt;p&gt;Building an MCP server sounds like one of those "cool idea, lots of plumbing" projects. Spring Boot made it much less painful than I expected. The main job was building a bridge between AI assistants and Maven Central's API that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work across JVM build tools because everything ultimately maps to Maven coordinates (Maven/Gradle/SBT/Mill)&lt;/li&gt;
&lt;li&gt;Process bulk requests efficiently&lt;/li&gt;
&lt;li&gt;Classify versions intelligently (stable/RC/beta/alpha/milestone)&lt;/li&gt;
&lt;li&gt;Cache aggressively since dependency data doesn't change that often&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what the foundation looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Spring AI's MCP support --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-starter-mcp-server&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Optional MCP client integration (e.g., exposing Context7 tools) --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-starter-mcp-client-webflux&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Spring cache abstraction --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-cache&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Caffeine for caching --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.github.ben-manes.caffeine&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;caffeine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Maven's own version comparison logic --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-artifact&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Spring AI's MCP support, you expose methods as tools and let the starter handle the protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MavenDependencyTools&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Tool&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Single dependency. Returns newest versions by type (stable/rc/beta/alpha/milestone)."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ToolResponse&lt;/span&gt; &lt;span class="nf"&gt;get_latest_version&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Maven coordinate like 'org.springframework:spring-core'"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@ToolParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Stability filter (ALL, STABLE_ONLY, PREFER_STABLE)"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@Nullable&lt;/span&gt; &lt;span class="nc"&gt;StabilityFilter&lt;/span&gt; &lt;span class="n"&gt;stabilityFilter&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;executeToolOperation&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;MavenCoordinate&lt;/span&gt; &lt;span class="n"&gt;coordinate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MavenCoordinateParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;allVersions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mavenCentralService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllVersions&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allVersions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;notFoundResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;

            &lt;span class="nc"&gt;StabilityFilter&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stabilityFilter&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;stabilityFilter&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;StabilityFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PREFER_STABLE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;buildVersionsByType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coordinate&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allVersions&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;spring-ai-starter-mcp-server&lt;/code&gt; handles JSON serialization, parameter validation, stdio transport, and the MCP protocol bits. Without it, this would have been a much longer project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes This Different From Just Googling
&lt;/h2&gt;

&lt;p&gt;Fair question. You can absolutely Google it or check Maven Central manually. The difference is what you get when you put it behind a tool designed for bulk + context:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed&lt;/strong&gt;: 20+ dependencies in a single interaction, not 20 separate lookups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accuracy&lt;/strong&gt;: Pulling directly from Maven Central, not from a blog post that happened to mention a version number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signal, not just numbers&lt;/strong&gt;: Classifies versions (stable/RC/beta/etc.), compares properly, and uses historical data to infer release patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt;: Ask follow-ups like "should I move from Spring Boot 2.7 to 3.x—what breaks?" and get an answer that uses both dependency data and ecosystem knowledge.&lt;/p&gt;

&lt;p&gt;Example response from a bulk upgrade check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"comparison_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-01-06T12:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dependency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.springframework:spring-core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"current_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6.1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"latest_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6.2.7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"latest_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"minor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"update_available"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"update_summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"major_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minor_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"patch_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"no_updates"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Beyond Version Lookup
&lt;/h2&gt;

&lt;p&gt;Once the basic "latest version" flow worked, it was obvious there was more useful stuff to return.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Age Analysis&lt;/strong&gt;: Is a library "fresh" (≤30 days), "current" (≤6 months), "aging" (6 months–2 years), or "stale" (&amp;gt;2 years)?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release patterns&lt;/strong&gt;: How often has this library released, and how consistent has that timing been? The server also estimates the next release window from those intervals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Health Scoring&lt;/strong&gt;: Aggregate health score across dependencies. Which ones need attention?&lt;/p&gt;

&lt;p&gt;I treat these as signals to investigate. A quiet release history doesn't by itself mean a library is abandoned, and a stable version label doesn't establish that an upgrade is compatible with my application.&lt;/p&gt;

&lt;p&gt;This has already caught a few "we haven't looked at this in forever" dependencies—things that weren't on fire today, but were quietly becoming a maintenance risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;It runs in Docker. For Claude Desktop, add this to your config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maven-tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"arvindand/maven-tools-mcp:latest"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For VS Code + GitHub Copilot, create &lt;code&gt;.vscode/mcp.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maven-tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stdio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arvindand/maven-tools-mcp:latest"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"What's the latest stable Spring Boot version?"&lt;/li&gt;
&lt;li&gt;"Check my build.gradle for outdated dependencies"&lt;/li&gt;
&lt;li&gt;"Show me the health status of my project dependencies"&lt;/li&gt;
&lt;li&gt;"Should I upgrade from Hibernate 5.6 to 6.x?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a Gradle build, the assistant needs to extract the dependency coordinates before calling the tools. The server's whole-file analysis supports Maven POMs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;I spent time on this because if it's slow, you'll stop using it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: Maven Central results cached with 24-hour TTL (vulnerability lookups cached separately)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulk Operations&lt;/strong&gt;: One request handles 20+ dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Images&lt;/strong&gt;: GraalVM compilation for fast startup&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backpressure&lt;/strong&gt;: Bounded concurrency so you don't melt your machine or Maven Central&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once cache is warm, most queries feel instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;MCP let me make dependency checks available inside the assistant, and Spring AI handled much of the integration work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching matters.&lt;/strong&gt; Dependency data doesn't change often. Aggressive caching makes everything feel instant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bulk operations change the workflow.&lt;/strong&gt; Checking a bunch of dependencies at once makes this kind of work much less tedious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spring Boot fits well.&lt;/strong&gt; MCP server wiring, caching, HTTP client, configuration—Spring handles the boring parts.&lt;/p&gt;

&lt;p&gt;I used GraalVM native compilation to keep startup time and memory use low. That matters for a tool launched alongside the assistant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code
&lt;/h2&gt;

&lt;p&gt;Everything's MIT licensed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/arvindand/maven-tools-mcp" rel="noopener noreferrer"&gt;github.com/arvindand/maven-tools-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Hub&lt;/strong&gt;: &lt;a href="https://hub.docker.com/r/arvindand/maven-tools-mcp" rel="noopener noreferrer"&gt;arvindand/maven-tools-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try it, let me know what works and what doesn't. Issues and feedback welcome.&lt;/p&gt;




&lt;p&gt;This started as a weekend experiment—Spring + curiosity about AI and MCP + impatience with dependency busywork. It turned into something I use daily and notice when it's missing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;: I'm a software architect at Rockwell Automation. I write about architecture, developer tooling, and the use of AI in software engineering. You can find me on &lt;a href="https://github.com/arvindand" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; or &lt;a href="https://linkedin.com/in/arvindsmenon/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Updated September 2026 to clarify tool behaviour and limitations.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>springboot</category>
      <category>java</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
