Spring AI Ikanos: Declarative Tools, Running Inside Your Spring AI Agent Spring AI Ikanos, an open-source project from Naftiko, adds a third way to give a Spring AI agent tools: declaring them in reviewable YAML and running them in the same JVM as the agent, rather than hand-writing @Tool methods or running a separate MCP server. Each declared tool becomes a Spring AI ToolCallback built with Spring AI's McpToolUtils, with no extra process or bound port, and MCP annotations such as readOnlyHint and destructiveHint drive an approval gate that fails closed. The project notes a caveat: Ikanos MCP servers speak MCP protocol 2026-07-28, which the MCP Java SDK in current Spring AI releases does not yet support — support landed in SDK 2.2.0-M1 — so until Spring AI adopts it, the in-JVM bridge is the way to use Ikanos tools from Spring AI. Two options, each with a cost A Spring Boot service that runs its own agent loop on enterprise APIs has two ways to give the model tools today. 1. Hand-write @Tool methods. The tool surface lives in Java. It ships with the service, which is convenient, but it is reviewed as code, and whether a tool is safe to call lives in a developer’s head or a Javadoc comment. 2. Run an MCP server next to the service and consume it with Spring AI’s MCP client. The surface is now declarative and governed, but the service pays for a second process, credential plumbing to its own tool layer, one more failure point and two traces to stitch together. Spring AI Ikanos https://github.com/naftiko/spring-ai-ikanos adds a third option: declare the tools in reviewable YAML, and run them in the same JVM as the agent. The value proposition - One artifact, two deployments. The tools come from the exposes: type: mcp block of an Ikanos https://github.com/naftiko/ikanos capability. The same file can be served as a remote MCP server or embedded in-process. Moving between the two is a deployment decision, not a rewrite. - No extra moving parts. Each tool becomes a Spring AI ToolCallback . No MCP server is started, no port is bound and no second process runs. Calls go straight from the tool loop to the engine, then out to the upstream API. - Same view for the model. Tool definitions are built with Spring AI’s own McpToolUtils , and results are serialized like SyncMcpToolCallback does. A parity test checks that a tool’s definition, output and annotations are identical in-JVM and from an Ikanos MCP server. - Risk hints that are actually enforced. MCP tool annotations such as readOnlyHint and destructiveHint are usually just metadata. Here they drive an approval gate that fails closed. - Plain Spring AI. The project uses ToolCallback , ToolCallbackProvider and Boot auto-configuration unchanged, and it works with ToolSearchToolCallingAdvisor . When should you pick in-JVM over remote MCP? Look at lifecycle coupling: | Agent and tools share… | Use | |---|---| | Team, release cadence, deployment unit | In-JVM , with Spring AI Ikanos | | Nothing: tools are shared or owned by another team | Remote MCP , an Ikanos MCP server | The project does not compete with Spring AI’s MCP support. It gives the same declarative artifact a second deployment option. One caveat on the remote side, stated plainly: Ikanos MCP servers speak MCP protocol 2026-07-28 , and the MCP Java SDK in current Spring AI releases does not yet. Support has landed in SDK 2.2.0-M1 , so the gap closes when Spring AI adopts it. Until then, Spring AI’s own MCP client cannot connect to an Ikanos server, and the in-JVM bridge is the way to use Ikanos tools from Spring AI. How it works You declare a tool once, in a capability: exposes: - type: mcp namespace: fleet tools: list-ships: description: List ships by operational status hints: readOnly: true inputParameters: status: type: string required: true call: registry.list-ships with: status: fleet.status You add the starter, point it at your capabilities, and attach the tools to a ChatClient : spring: ai: ikanos: capabilities: - classpath:capabilities/ .yml @Bean ChatClient chatClient ChatClient.Builder builder, IkanosToolCallbackProvider ikanosTools { return builder.defaultTools ikanosTools .build ; } At startup, the starter loads each capability, starts only its outbound HTTP clients, and publishes one ToolCallbackProvider . When the model calls list-ships , Spring AI’s tool loop invokes the callback, which hands the arguments to the Ikanos engine in the same heap. The engine maps the inputs, calls the upstream API, shapes the response, and returns structured JSON to the model. Startup fails fast on mistakes you would otherwise find in production: a location that matches nothing, two tools with the same name, or a tool that may be destructive with no one to approve it. An approval gate built on MCP annotations Every tool is gated unless its capability declares readOnly: true or destructive: false . That follows the MCP defaults, so a write tool with no hints is gated rather than waved through. Before a gated tool runs, a ToolApprovalHandler decides: php @Bean ToolApprovalHandler toolApprovalHandler { return request - hasChangeTicket request ? ToolApprovalDecision.approve : ToolApprovalDecision.deny "needs a change ticket" ; } A denial goes back to the model as the tool result, so it can explain or choose another path. If no handler exists, the application does not start. The gate is a ToolCallback decorator rather than an advisor, so it composes with whatever advisor drives the loop. The approval module has no Ikanos dependency. What stops it from gating remote MCP tools today is that Spring AI’s MCP callbacks keep the annotations a server declares to themselves. We have proposed a small, vendor-neutral addition that exposes them: spring-projects/spring-ai 7239 https://github.com/spring-projects/spring-ai/issues/7239 . With it, the same annotations could drive our gate, or the tool call confirmation coming in Spring AI 2.1, for every MCP tool, not only Ikanos ones. Where it stands, and how you can help The project is a working proof of concept, public at naftiko/spring-ai-ikanos https://github.com/naftiko/spring-ai-ikanos under Apache 2.0. It has a core bridge, the approval gate, Boot auto-configuration, a starter and an example application. Its 57 tests pass against ikanos-engine 1.0.0-beta8 from Maven Central and Spring AI 2.0.2 . It requires Java 21 and Spring Boot 4. Our goal is to propose it as a project of the Spring AI Community https://springaicommunity.mintlify.app/get-involved , alongside other vendor-backed projects. Approval there is unanimous, so the case rests on value to Spring AI users, not to us. In the interest of transparency: Naftiko maintains Ikanos and sells commercial offerings around it. Here is how you can help: - Try it on a real Spring AI agent, and tell us where it breaks or where the YAML falls short of a hand-written @Tool . - Open an issue or discussion on the repository with your use case. Concrete users make a stronger proposal than any design document. - Star the repository if you would like to see it in the Spring AI Community. - Join as a maintainer. The community asks for committed developers, and we are looking for a second one. Declarative tools should not force you to run a second process. With Spring AI Ikanos, they don’t have to. The takeaway - Spring AI Ikanos runs the tools of an Ikanos capability as Spring AI ToolCallback s, in the same JVM as the agent, with no MCP server and no second process. - The same YAML can be embedded or served as a remote MCP server. Choose by lifecycle coupling, not by rewriting. - MCP ToolAnnotations become an approval gate that fails closed: unannotated tools are gated, and the app does not start without a handler. - The project is a public, Apache 2.0 proof of concept, headed for the Spring AI Community. Your use cases and feedback decide how strong that proposal is. References - 💻 naftiko/spring-ai-ikanos https://github.com/naftiko/spring-ai-ikanos — source, README and the examples/fleet application - 💻 naftiko/ikanos https://github.com/naftiko/ikanos — the Ikanos engine, published on Maven Central as io.ikanos:ikanos-engine - 💬 spring-projects/spring-ai 7239 https://github.com/spring-projects/spring-ai/issues/7239 — our proposal to expose MCP tool annotations from Spring AI’s MCP callbacks - 🌱 Spring AI Community — Get Involved https://springaicommunity.mintlify.app/get-involved and the Project Creation Guide https://springaicommunity.mintlify.app/community/project-guide - 📖 Spring AI Reference — Tool Calling https://docs.spring.io/spring-ai/reference/api/tools.html and MCP https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html - 📖 Model Context Protocol — Tool annotations https://modelcontextprotocol.io/specification/2025-06-18/server/tools