{"slug": "spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend", "title": "Spring Boot MCP Server in 2026: The Transport Trap That Wastes Your Weekend", "summary": "A developer built a Spring Boot MCP server that exposes database queries, REST API calls, and file system access as tools for AI agents like Claude, GitHub Copilot, and Cursor. The project highlights a common transport trap where using the wrong Maven starter (stdio vs. SSE) causes silent failures with no error messages. The fix is a single configuration line matching the starter to the client type.", "body_md": "I spent an afternoon staring at \"connection refused\" on my first MCP server.\n\nThe fix was one config line. Here's what no README tells you upfront.\n\nModel Context Protocol is the standard that lets AI agents — Claude, GitHub\n\nCopilot, Cursor — call your code as a tool. Instead of the AI just generating\n\ntext, it can actually invoke your functions and get real data back.\n\nThink of it as giving Claude a set of keys to specific doors in your Java\n\nbackend. It asks \"can you run this query?\" — your MCP server runs it, returns\n\nthe result — Claude uses that result in its response.\n\nFor Java teams, this is significant. There are millions of Spring Boot services\n\nsitting in production right now that AI agents can't touch. MCP changes that.\n\nHere's the full working server — a Spring Boot MCP server that exposes\n\ndatabase queries, REST API calls, and file system access as tools\n\nany AI agent can call.\n\nMaven dependencies:\n\n```\n<dependency>\n    <groupId>org.springframework.ai</groupId>\n    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>\n</dependency>\n<dependencyManagement>\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.ai</groupId>\n      <artifactId>spring-ai-bom</artifactId>\n      <version>1.0.0</version>\n      <type>pom</type>\n      <scope>import</scope>\n    </dependency>\n  </dependencies>\n</dependencyManagement>\n```\n\nYour first tool:\n\n```\n@Service\npublic class DatabaseMcpTools {\n\n    @Autowired private JdbcTemplate jdbc;\n\n    @Tool(description = \"Run a read-only SQL query on the application database\")\n    public String queryDatabase(\n        @ToolParam(description = \"SQL SELECT query to execute\") String sql\n    ) {\n        if (!sql.trim().toUpperCase().startsWith(\"SELECT\")) {\n            return \"Error: only SELECT queries are permitted\";\n        }\n        return jdbc.queryForList(sql).toString();\n    }\n\n    @Tool(description = \"List all tables in the database schema\")\n    public String listTables() {\n        return jdbc.queryForList(\n            \"SELECT table_name FROM information_schema.tables \" +\n            \"WHERE table_schema = 'public'\"\n        ).toString();\n    }\n}\n```\n\n`application.yml`\n\n:\n\n```\nspring:\n  ai:\n    mcp:\n      server:\n        name: my-mcp-server\n        version: 1.0.0\n        instructions: \"Provides database query and table listing tools.\"\n```\n\nRun it:\n\n```\nmvn spring-boot:run\n```\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json`\n\n:\n\n```\n{\n  \"mcpServers\": {\n    \"my-spring-server\": {\n      \"command\": \"java\",\n      \"args\": [\"-jar\", \"/absolute/path/to/your-server.jar\"]\n    }\n  }\n}\n```\n\nRestart Claude Desktop. You should see a 🔨 hammer icon in the chat input.\n\nClick it — your tool names should appear. Type:\n\n\"List all the tables in the database\"\n\nClaude calls your tool, your Spring Boot logs fire, Claude gets real data back.\n\nThat's your first working MCP integration.\n\nHere's what burned me. There are two transports and they are not\n\ninterchangeable:\n\n| Client | Transport | Maven starter |\n|---|---|---|\n| Claude Desktop, Claude Code CLI | stdio (subprocess) | `spring-ai-starter-mcp-server` |\n| VS Code, Cursor, Windsurf | SSE (HTTP) | `spring-ai-starter-mcp-server-webmvc` |\n\nThe failure mode is brutal: **no error message**. Claude Desktop just shows\n\nno tools. VS Code just shows no server. The process starts fine. Logs look\n\nfine. The handshake silently fails.\n\nThe rule: if the client is an IDE connecting over HTTP, use the `webmvc`\n\nstarter. If the client is a CLI spawning your jar as a subprocess, use the\n\nplain starter without `webmvc`\n\n.\n\nFor VS Code / Cursor, add to `.vscode/mcp.json`\n\nwhile the app is running:\n\n```\n{\n  \"servers\": {\n    \"my-spring-server\": {\n      \"type\": \"sse\",\n      \"url\": \"http://localhost:8080/sse\"\n    }\n  }\n}\n```\n\n**1. Guard against path traversal in file tools:**\n\n```\nPath target = BASE_DIR.resolve(userInput).normalize();\nif (!target.startsWith(BASE_DIR)) return \"Error: access denied\";\n```\n\n**2. Guard against SQL writes:**\n\n```\nif (!sql.trim().toUpperCase().startsWith(\"SELECT\")) \n    return \"Error: only SELECT queries are permitted\";\n```\n\n**3. Never return null from a @Tool method — return empty string instead.**\n\n**4. Use absolute paths in your Claude Desktop config**, not `~/`\n\nor `./`\n\n.\n\n**5. Add a docker-compose.yml** so clients can run it with one command:\n\n```\nservices:\n  mcp-server:\n    build: .\n    ports:\n      - \"8080:8080\"\n    environment:\n      - SPRING_DATASOURCE_URL=${DB_URL}\n      - SPRING_DATASOURCE_USERNAME=${DB_USER}\n      - SPRING_DATASOURCE_PASSWORD=${DB_PASSWORD}\n```\n\nEverything above plus file system tools, REST API wrapper, and setup\n\nguides for both transports:\n\n→ [github.com/anirbandashfx-commits/spring-boot-mcp-server](https://github.com/anirbandashfx-commits/spring-boot-mcp-server)\n\nBuilding a custom MCP server for your Java team?\n\n→ [Connect on LinkedIn](https://www.linkedin.com/in/anirbandas1986/)", "url": "https://wpnews.pro/news/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend", "canonical_source": "https://dev.to/anirbandashfxcommits/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-afternoon-4962", "published_at": "2026-06-26 02:08:21+00:00", "updated_at": "2026-06-26 02:33:50.418976+00:00", "lang": "en", "topics": ["developer-tools", "large-language-models", "ai-agents"], "entities": ["Spring Boot", "Claude", "GitHub Copilot", "Cursor", "Model Context Protocol", "Maven", "VS Code", "Claude Desktop"], "alternates": {"html": "https://wpnews.pro/news/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend", "markdown": "https://wpnews.pro/news/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend.md", "text": "https://wpnews.pro/news/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend.txt", "jsonld": "https://wpnews.pro/news/spring-boot-mcp-server-in-2026-the-transport-trap-that-wastes-your-weekend.jsonld"}}