<?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: Alkademy</title>
    <description>The latest articles on DEV Community by Alkademy (@alkademy).</description>
    <link>https://dev.to/alkademy</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%2F4007064%2Fce1ab31d-dcda-42bf-9f3c-c4294e19a6a3.png</url>
      <title>DEV Community: Alkademy</title>
      <link>https://dev.to/alkademy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alkademy"/>
    <language>en</language>
    <item>
      <title>Spring AI + MCP Bridge Tutorial — Connect External Tool Servers to ChatClient (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:51:50 +0000</pubDate>
      <link>https://dev.to/alkademy/spring-ai-mcp-bridge-tutorial-connect-external-tool-servers-to-chatclient-2026-4n8d</link>
      <guid>https://dev.to/alkademy/spring-ai-mcp-bridge-tutorial-connect-external-tool-servers-to-chatclient-2026-4n8d</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/spring-ai-mcp-bridge-tutorial-2026/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🔗 The missing link&lt;/strong&gt; — You learned &lt;strong&gt;@Tool&lt;/strong&gt; agents in our &lt;a href="https://www.munonye.com/spring-ai-agents-tutorial-tool-calling-2026/" rel="noopener noreferrer"&gt;Spring AI agents tutorial&lt;/a&gt; and MCP basics in &lt;a href="https://www.munonye.com/model-context-protocol-mcp-tutorial-developers/" rel="noopener noreferrer"&gt;M9-A&lt;/a&gt;. This &lt;strong&gt;Spring AI MCP bridge&lt;/strong&gt; tutorial connects them: your &lt;strong&gt;ChatClient&lt;/strong&gt; calls &lt;strong&gt;external MCP tool servers&lt;/strong&gt; the same way Cursor does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is how IDE agents discover tools. &lt;strong&gt;Spring AI&lt;/strong&gt; is how you ship AI in production APIs. The &lt;strong&gt;Spring AI MCP bridge&lt;/strong&gt; lets one tool server serve both — no duplicate integrations.&lt;/p&gt;

&lt;p&gt;This hands-on guide is part of the &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials hub&lt;/a&gt;. Time: &lt;strong&gt;~45 minutes&lt;/strong&gt;. Prerequisites: &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;Spring AI first REST endpoint (M7-A)&lt;/a&gt;, OpenAI API key, Node.js (for the sample MCP server).&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why bridge MCP and Spring AI?&lt;/li&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;Step 1 — Dependencies&lt;/li&gt;
&lt;li&gt;Step 2 — Configure MCP client&lt;/li&gt;
&lt;li&gt;Step 3 — ChatClient + ToolCallbackProvider&lt;/li&gt;
&lt;li&gt;Step 4 — REST endpoint&lt;/li&gt;
&lt;li&gt;Step 5 — Test&lt;/li&gt;
&lt;li&gt;Bonus — Expose Java tools as MCP server&lt;/li&gt;
&lt;li&gt;Production checklist&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why bridge MCP and Spring AI? {#why-bridge}
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Where tools run&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;@Tool&lt;/strong&gt; (M13, M14)&lt;/td&gt;
&lt;td&gt;Inside Spring Boot JVM&lt;/td&gt;
&lt;td&gt;CRUD agents tied to your services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;MCP server&lt;/strong&gt; (M9-A)&lt;/td&gt;
&lt;td&gt;Separate process / remote host&lt;/td&gt;
&lt;td&gt;Shared tools for Cursor + APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spring AI MCP bridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spring Boot orchestrates MCP clients&lt;/td&gt;
&lt;td&gt;Production agents using ecosystem tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;💡 Real-world pattern:&lt;/strong&gt; Your team builds an MCP server for internal docs search. Developers use it in &lt;strong&gt;Cursor&lt;/strong&gt;. With this bridge, the same server powers your &lt;strong&gt;customer-facing Spring Boot agent&lt;/strong&gt; — one tool implementation, two consumers.&lt;/p&gt;

&lt;p&gt;Related reading: &lt;a href="https://www.munonye.com/add-ai-to-angular-spring-boot-crud-app-weekend-2026/" rel="noopener noreferrer"&gt;Add AI to Angular CRUD app (M14)&lt;/a&gt; for in-process @Tool on an existing app · &lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;Function calling from Angular (M8-B)&lt;/a&gt; for structured tool UX.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture {#architecture}
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

┌─────────────────┐     stdio/SSE      ┌──────────────────────┐
│  MCP tool server │ ◄──────────────► │  Spring Boot app      │
│  (Node, Java, …) │                    │  spring-ai-starter-   │
└─────────────────┘                    │  mcp-client           │
                                       │         │             │
                                       │         ▼             │
                                       │  ChatClient + OpenA

---

**Read the full tutorial with all code on munonye.com →**

---

**Full tutorial:** [Spring AI + MCP Bridge Tutorial — Connect External Tool Servers to ChatClient (2026)](https://www.munonye.com/spring-ai-mcp-bridge-tutorial-2026/)

**Kindson Munonye** — [GitHub](https://github.com/KindsonTheGenius) · [LinkedIn](https://www.linkedin.com/in/kindson) · [About](https://www.munonye.com/about/)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spring AI Agents Tutorial — Build a Tool-Calling AI Assistant (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:46:35 +0000</pubDate>
      <link>https://dev.to/alkademy/spring-ai-agents-tutorial-build-a-tool-calling-ai-assistant-2026-3d60</link>
      <guid>https://dev.to/alkademy/spring-ai-agents-tutorial-build-a-tool-calling-ai-assistant-2026-3d60</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/spring-ai-agents-tutorial-tool-calling-2026/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;🔥 Why this matters in 2026&lt;/strong&gt; — &lt;em&gt;Agentic AI&lt;/em&gt; is the fastest-growing search topic in Java developer communities. Teams want LLMs that &lt;strong&gt;do things&lt;/strong&gt; — query databases, call REST APIs, send emails — not just chat. This &lt;strong&gt;Spring AI agents tutorial&lt;/strong&gt; shows the production pattern: &lt;strong&gt;ChatClient + @Tool&lt;/strong&gt; on Spring Boot 3, the same stack as our &lt;a href="https://www.munonye.com/complete-crud-operations-with-angular-9-step-by-step-part-1setup/" rel="noopener noreferrer"&gt;Angular CRUD series&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic AI&lt;/strong&gt; is the defining backend trend of 2026. If you already ship &lt;strong&gt;Spring Boot REST APIs&lt;/strong&gt; and &lt;strong&gt;Angular&lt;/strong&gt; frontends, the next feature users expect is an &lt;strong&gt;AI assistant that acts on your data&lt;/strong&gt; — look up orders, summarize tickets, recommend products — using &lt;strong&gt;tool calling&lt;/strong&gt;, not prompt hacks.&lt;/p&gt;

&lt;p&gt;This hands-on guide is part of the &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials hub&lt;/a&gt;. You will build a &lt;strong&gt;tool-calling AI agent&lt;/strong&gt; with &lt;strong&gt;Spring AI&lt;/strong&gt;, step by step, in about &lt;strong&gt;60 minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;Spring AI first REST endpoint (M7-A)&lt;/a&gt;, Java 17+, OpenAI API key, basic Spring Boot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is agentic AI?&lt;/li&gt;
&lt;li&gt;Architecture overview&lt;/li&gt;
&lt;li&gt;Step 1 — Define @Tool methods&lt;/li&gt;
&lt;li&gt;Step 2 — Configure the agent ChatClient&lt;/li&gt;
&lt;li&gt;Step 3 — REST API for the agent&lt;/li&gt;
&lt;li&gt;Step 4 — Test multi-step prompts&lt;/li&gt;
&lt;li&gt;Step 5 — Angular UI (optional)&lt;/li&gt;
&lt;li&gt;Production checklist&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is agentic AI? {#what-is-agentic-ai}
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Spring AI agent&lt;/strong&gt; combines:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Plans steps and interprets user intent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;@Tool methods&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Your Java functions the model can invoke&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatClient&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Orchestrates the tool-calling loop&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unlike a basic chat endpoint (&lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;M7-A tutorial&lt;/a&gt;), an &lt;strong&gt;agent&lt;/strong&gt; may execute &lt;strong&gt;multiple tool calls&lt;/strong&gt; before answering — e.g. &lt;em&gt;"What's the status of order 1042 and when will it ship?"&lt;/em&gt; → &lt;code&gt;getOrder(1042)&lt;/code&gt; → &lt;code&gt;getShippingEstimate(1042)&lt;/code&gt; → natural language summary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip:&lt;/strong&gt; Start with &lt;strong&gt;2–3 narrow tools&lt;/strong&gt;. Agents fail when you expose twenty vague functions. Same lesson as microservices boundaries — see our &lt;a href="https://www.munonye.com/microservices-tutorials/" rel="noopener noreferrer"&gt;Microservices hub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture overview {#architecture}
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User prompt
    │
    ▼
POST /api/agent
    │
    ▼
ChatClient (Spring AI)
    ├──► LLM plans tool use
    ├──► @Tool getOrderStatus(orderId)
    ├──► @Tool listLowStockProducts()
    └──► Final answer to user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stack alignment:&lt;/strong&gt; This agent sits beside your existing &lt;strong&gt;FriendsAPI&lt;/strong&gt;-style CRUD backend from the [complete CRUD guide](&lt;a href="https://www.munonye.com/angu" rel="noopener noreferrer"&gt;https://www.munonye.com/angu&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Read the full tutorial with all code on munonye.com →&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/spring-ai-agents-tutorial-tool-calling-2026/" rel="noopener noreferrer"&gt;Spring AI Agents Tutorial — Build a Tool-Calling AI Assistant (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spring AI Tutorial — Your First REST Endpoint with OpenAI (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:46:01 +0000</pubDate>
      <link>https://dev.to/alkademy/spring-ai-tutorial-your-first-rest-endpoint-with-openai-2026-43a1</link>
      <guid>https://dev.to/alkademy/spring-ai-tutorial-your-first-rest-endpoint-with-openai-2026-43a1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This &lt;strong&gt;Spring AI tutorial step by step&lt;/strong&gt; walks you through your first LLM-powered REST endpoint on &lt;strong&gt;Spring Boot 3&lt;/strong&gt;. You will call OpenAI from Java using &lt;strong&gt;ChatClient&lt;/strong&gt;, keep API keys out of source code, and verify with curl — the backend foundation for our &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt; series.&lt;/p&gt;

&lt;p&gt;If you have built REST APIs with our &lt;a href="https://www.munonye.com/complete-crud-operations-with-angular-9-step-by-step-part-1setup/" rel="noopener noreferrer"&gt;Angular CRUD + Spring Boot series&lt;/a&gt;, you already know the architecture; we are adding an AI layer on top.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt; Java 17+, Maven, OpenAI API key, basic Spring Boot REST knowledge.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Time:&lt;/strong&gt; ~45 minutes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client (curl / Angular)
    POST /api/chat  { "message": "Hello" }
         ▼
ChatController → ChatClient → OpenAI API
         ▼
    { "reply": "..." }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1 — Create the project
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://start.spring.io/starter.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;dependencies&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;web &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;javaVersion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;17 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ai-chat-api &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; ai-chat-api.zip
unzip ai-chat-api.zip &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;ai-chat-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add Spring AI BOM and OpenAI starter in &lt;code&gt;pom.xml&lt;/code&gt;:&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;dependencyManagement&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dependencies&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-bom&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;pom&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/scope&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;span class="nt"&gt;&amp;lt;/dependencyManagement&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;dependencies&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-openai-spring-boot-starter&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;h2&gt;
  
  
  Step 2 — Configure OpenAI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# application.properties
&lt;/span&gt;&lt;span class="py"&gt;server.port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8080&lt;/span&gt;
&lt;span class="py"&gt;spring.ai.openai.api-key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${OPENAI_API_KEY}&lt;/span&gt;
&lt;span class="py"&gt;spring.ai.openai.chat.options.model&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;
&lt;span class="py"&gt;spring.ai.openai.chat.options.temperature&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sk-...
./mvnw spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never commit API keys. Use environment variables or a secrets manager in production (see &lt;a href="https://www.munonye.com/secure-ai-features-api-keys-jwt-rate-limiting-spring-boot/" rel="noopener noreferrer"&gt;M11-A secure AI tutorial&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Chat REST endpoint
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/chat"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@CrossOrigin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;origins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://localhost:4200"&lt;/span&gt;&lt;span class="o"&gt;)&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;ChatController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ChatController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ChatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultSystem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You are a helpful Java and Spring Boot assistant."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ChatResponse&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;ChatRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;)&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;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&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;ChatResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ChatRequest&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;message&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ChatResponse&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;reply&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;h2&gt;
  
  
  Step 4 — Test with curl
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8080/api/chat &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"message":"Explain Spring Boot in one sentence"}'&lt;/span&gt; | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: JSON with a &lt;code&gt;reply&lt;/code&gt; field containing the model response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;401 from OpenAI&lt;/td&gt;
&lt;td&gt;Check &lt;code&gt;OPENAI_API_KEY&lt;/code&gt; is set and valid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bean ChatClient missing&lt;/td&gt;
&lt;td&gt;Ensure &lt;code&gt;spring-ai-openai-spring-boot-starter&lt;/code&gt; is on classpath&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CORS blocked from Angular&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;@CrossOrigin&lt;/code&gt; or configure &lt;code&gt;WebMvcConfigurer&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;M7-B:&lt;/strong&gt; [Build a streaming chat UI in Angular 19](&lt;a href="https://www.munonye.com/angular-19-streaming-c" rel="noopener noreferrer"&gt;https://www.munonye.com/angular-19-streaming-c&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Read the full tutorial with all code on munonye.com →&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;Spring AI Tutorial — Your First REST Endpoint with OpenAI (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Secure AI Features — API Keys, JWT, and Rate Limiting in Spring Boot (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:40:22 +0000</pubDate>
      <link>https://dev.to/alkademy/secure-ai-features-api-keys-jwt-and-rate-limiting-in-spring-boot-2026-1pom</link>
      <guid>https://dev.to/alkademy/secure-ai-features-api-keys-jwt-and-rate-limiting-in-spring-boot-2026-1pom</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/secure-ai-features-api-keys-jwt-rate-limiting-spring-boot/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Spring Boot secure OpenAI API&lt;/strong&gt; patterns for production AI features. Required reading after &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;M7-A&lt;/a&gt; in &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rules
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;API keys only in server env / vault
&lt;/li&gt;
&lt;li&gt;Angular sends JWT, not OpenAI keys
&lt;/li&gt;
&lt;li&gt;Rate limit per user/IP
&lt;/li&gt;
&lt;li&gt;Validate and sanitize all prompts
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  JWT-secured controller
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/chat"&lt;/span&gt;&lt;span class="o"&gt;)&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;ChatController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;
  &lt;span class="nd"&gt;@PreAuthorize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"isAuthenticated()"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="nd"&gt;@RateLimiter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"chat"&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;ChatResponse&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;ChatRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// log user id, not full prompt in prod&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;ChatResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;content&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;Link &lt;a href="https://www.munonye.com/spring-boot-tutorials/" rel="noopener noreferrer"&gt;Spring Boot hub&lt;/a&gt; for REST fundamentals.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/secure-ai-features-api-keys-jwt-rate-limiting-spring-boot/" rel="noopener noreferrer"&gt;Secure AI Features — API Keys, JWT, and Rate Limiting in Spring Boot (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>RAG with Spring Boot — Embeddings and Vector Search Step by Step (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:39:46 +0000</pubDate>
      <link>https://dev.to/alkademy/rag-with-spring-boot-embeddings-and-vector-search-step-by-step-2026-5fpk</link>
      <guid>https://dev.to/alkademy/rag-with-spring-boot-embeddings-and-vector-search-step-by-step-2026-5fpk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/rag-spring-boot-embeddings-vector-search-step-by-step/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Learn &lt;strong&gt;how to build a RAG Spring Boot tutorial&lt;/strong&gt; pipeline that answers questions from your own documents. This post extends the &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt; series and connects to &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;M7-A Spring AI REST basics&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents → chunk → embed → VectorStore
User question → embed → top-K similar chunks → prompt → LLM → answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&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;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-pgvector-store-spring-boot-starter&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;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-openai-spring-boot-starter&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ingestion service
&lt;/h2&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;DocumentIngestionService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;docsFolder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DocumentIngestionService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;VectorStore&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"classpath:docs/"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;docsFolder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;vectorStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;docsFolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;docsFolder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ingestAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;docsFolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;listFiles&lt;/span&gt;&lt;span class="o"&gt;())&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFile&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toPath&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;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&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="kd"&gt;private&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;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;split&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;text&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;overlap&lt;/span&gt;&lt;span class="o"&gt;)&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;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;overlap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&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="n"&gt;out&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;h2&gt;
  
  
  Question endpoint
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/ask"&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;AnswerResponse&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestBody&lt;/span&gt; &lt;span class="nc"&gt;QuestionRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;)&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;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;similar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vectorStore&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;similaritySearch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;5&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;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;similar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Document:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getContent&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;joining&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n---\n"&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;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Answer only from the context below. Say 'I don't know' if not found.\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&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;AnswerResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&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;h2&gt;
  
  
  Next: function calling from Angular
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;M8-B — Structured JSON from LLMs in Angular&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/rag-spring-boot-embeddings-vector-search-step-by-step/" rel="noopener noreferrer"&gt;RAG with Spring Boot — Embeddings and Vector Search Step by Step (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Run Local LLMs with Ollama + Spring Boot REST API (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:33:59 +0000</pubDate>
      <link>https://dev.to/alkademy/run-local-llms-with-ollama-spring-boot-rest-api-2026-2pf</link>
      <guid>https://dev.to/alkademy/run-local-llms-with-ollama-spring-boot-rest-api-2026-2pf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/ollama-spring-boot-rest-api-tutorial/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This &lt;strong&gt;Ollama Spring Boot tutorial&lt;/strong&gt; runs &lt;strong&gt;local LLMs&lt;/strong&gt; with no OpenAI bill — ideal for development and air-gapped environments. Part of &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Ollama
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama pull llama3.2
ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Spring configuration
&lt;/h2&gt;

&lt;p&gt;Replace OpenAI starter with:&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;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-ollama-spring-boot-starter&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.ai.ollama.base-url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434&lt;/span&gt;
&lt;span class="py"&gt;spring.ai.ollama.chat.options.model&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;llama3.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your &lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;M7-A ChatController&lt;/a&gt; works unchanged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next:&lt;/strong&gt; &lt;a href="https://www.munonye.com/angular-signals-ai-chat-state-management-2026/" rel="noopener noreferrer"&gt;Angular signals for chat state (M10-B)&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/ollama-spring-boot-rest-api-tutorial/" rel="noopener noreferrer"&gt;Run Local LLMs with Ollama + Spring Boot REST API (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Model Context Protocol (MCP) for Developers — Build a Simple Tool Server (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:33:24 +0000</pubDate>
      <link>https://dev.to/alkademy/model-context-protocol-mcp-for-developers-build-a-simple-tool-server-2026-2kbo</link>
      <guid>https://dev.to/alkademy/model-context-protocol-mcp-for-developers-build-a-simple-tool-server-2026-2kbo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/model-context-protocol-mcp-tutorial-developers/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; is a 2026 must-know for developers building AI tooling. This hands-on guide is in our &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt; hub.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP roles
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Host&lt;/td&gt;
&lt;td&gt;Cursor IDE, Claude Desktop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;MCP client inside the host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Your Java/Node service exposing tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Minimal tool server (concept)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pseudocode — MCP SDK pattern&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_weather&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Weather in &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: 22°C`&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bridge to Spring AI
&lt;/h2&gt;

&lt;p&gt;Your existing &lt;code&gt;@Tool&lt;/code&gt; methods in &lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;M8-B&lt;/a&gt; solve the same problem inside the JVM. MCP generalizes this for IDE agents and polyglot stacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next:&lt;/strong&gt; &lt;a href="https://www.munonye.com/event-driven-ai-agents-axon-spring-ai/" rel="noopener noreferrer"&gt;Event-driven AI agents with Axon (M9-B)&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/model-context-protocol-mcp-tutorial-developers/" rel="noopener noreferrer"&gt;Model Context Protocol (MCP) for Developers — Build a Simple Tool Server (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Full-Stack AI Starter Kit — Hub Summary (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:27:36 +0000</pubDate>
      <link>https://dev.to/alkademy/full-stack-ai-starter-kit-hub-summary-2026-3dfi</link>
      <guid>https://dev.to/alkademy/full-stack-ai-starter-kit-hub-summary-2026-3dfi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/full-stack-ai-starter-kit-hub-summary-2026/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This &lt;strong&gt;full stack AI app tutorial&lt;/strong&gt; summary links every post in the &lt;strong&gt;Modern Dev + AI&lt;/strong&gt; series on &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning path
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Posts&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Foundation&lt;/td&gt;
&lt;td&gt;M7-A, M7-B&lt;/td&gt;
&lt;td&gt;Chat MVP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG&lt;/td&gt;
&lt;td&gt;M8-A, M8-B, M11-B&lt;/td&gt;
&lt;td&gt;Grounded answers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced&lt;/td&gt;
&lt;td&gt;M9-A, M9-B, M10-A&lt;/td&gt;
&lt;td&gt;MCP, agents, local LLMs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;M11-A, M12-A&lt;/td&gt;
&lt;td&gt;Security + tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference&lt;/td&gt;
&lt;td&gt;M10-B, M12-B&lt;/td&gt;
&lt;td&gt;Signals + this summary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  All tutorials
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/spring-ai-tutorial-first-rest-endpoint-openai-2026/" rel="noopener noreferrer"&gt;Spring AI first REST endpoint (M7-A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/angular-19-streaming-chat-ui-openai-2026/" rel="noopener noreferrer"&gt;Angular 19 streaming chat UI (M7-B)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/rag-spring-boot-embeddings-vector-search-step-by-step/" rel="noopener noreferrer"&gt;RAG Spring Boot (M8-A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;Angular function calling (M8-B)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/model-context-protocol-mcp-tutorial-developers/" rel="noopener noreferrer"&gt;MCP for developers (M9-A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/event-driven-ai-agents-axon-spring-ai/" rel="noopener noreferrer"&gt;Axon + Spring AI agents (M9-B)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/ollama-spring-boot-rest-api-tutorial/" rel="noopener noreferrer"&gt;Ollama + Spring Boot (M10-A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/angular-signals-ai-chat-state-management-2026/" rel="noopener noreferrer"&gt;Angular signals chat (M10-B)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/secure-ai-features-api-keys-jwt-rate-limiting-spring-boot/" rel="noopener noreferrer"&gt;Secure AI features (M11-A)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/documentation-rag-bot-codebase-tutorial/" rel="noopener noreferrer"&gt;Documentation RAG bot (M11-B)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.munonye.com/ai-assisted-testing-angular-spring-boot/" rel="noopener noreferrer"&gt;AI-assisted testing (M12-A)&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Overview:&lt;/strong&gt; &lt;a href="https://www.munonye.com/spring-ai-angular-chat-feature-tutorial-2026/" rel="noopener noreferrer"&gt;Spring AI + Angular chat feature&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;munonye-ai-chat-spring-angular&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related hubs:&lt;/strong&gt; &lt;a href="https://www.munonye.com/angular-tutorials/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; · &lt;a href="https://www.munonye.com/spring-boot-tutorials/" rel="noopener noreferrer"&gt;Spring Boot&lt;/a&gt; · &lt;a href="https://www.munonye.com/microservices-tutorials/" rel="noopener noreferrer"&gt;Microservices&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/full-stack-ai-starter-kit-hub-summary-2026/" rel="noopener noreferrer"&gt;Full-Stack AI Starter Kit — Hub Summary (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Event-Driven AI Agents with Axon and Spring AI (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 05:26:59 +0000</pubDate>
      <link>https://dev.to/alkademy/event-driven-ai-agents-with-axon-and-spring-ai-2026-4jfc</link>
      <guid>https://dev.to/alkademy/event-driven-ai-agents-with-axon-and-spring-ai-2026-4jfc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/event-driven-ai-agents-axon-spring-ai/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Connect &lt;strong&gt;event-driven AI microservices&lt;/strong&gt; using &lt;strong&gt;Axon Framework&lt;/strong&gt; and &lt;strong&gt;Spring AI&lt;/strong&gt;. Start with &lt;a href="https://www.munonye.com/axon-framework-cqrs-tutorial-step-by-step/" rel="noopener noreferrer"&gt;Axon CQRS tutorial&lt;/a&gt; and &lt;a href="https://www.munonye.com/ingredients-of-a-cqrs-and-event-sourcing-application-a-simple-explanation/" rel="noopener noreferrer"&gt;CQRS intro&lt;/a&gt; from the &lt;a href="https://www.munonye.com/microservices-tutorials/" rel="noopener noreferrer"&gt;Microservices hub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP → CommandGateway → Aggregate → Event
EventHandler → ChatClient (classify / plan) → Follow-up Command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Event handler example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&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;SupportTicketAiHandler&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ChatClient&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CommandGateway&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@EventHandler&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TicketCreatedEvent&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;)&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;priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Classify priority 1-5 for: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;call&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SetTicketPriorityCommand&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ticketId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;priority&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;See &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt; for the full series.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/event-driven-ai-agents-axon-spring-ai/" rel="noopener noreferrer"&gt;Event-Driven AI Agents with Axon and Spring AI (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Documentation RAG Bot for Your Codebase (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 00:23:11 +0000</pubDate>
      <link>https://dev.to/alkademy/build-a-documentation-rag-bot-for-your-codebase-2026-2apc</link>
      <guid>https://dev.to/alkademy/build-a-documentation-rag-bot-for-your-codebase-2026-2apc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/documentation-rag-bot-codebase-tutorial/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Build a &lt;strong&gt;documentation RAG bot&lt;/strong&gt; for your team — capstone of &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt;. Combines &lt;a href="https://www.munonye.com/rag-spring-boot-embeddings-vector-search-step-by-step/" rel="noopener noreferrer"&gt;M8-A RAG&lt;/a&gt; and &lt;a href="https://www.munonye.com/angular-19-streaming-chat-ui-openai-2026/" rel="noopener noreferrer"&gt;M7-B Angular chat&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docs-bot-api/     Spring Boot — ingest, vector store, /api/ask
docs-bot-ui/      Angular 19 — chat + citation panel
/data/repo/       Cloned project to index
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Citation in responses
&lt;/h2&gt;

&lt;p&gt;Return chunk metadata with answers:&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;AnswerResponse&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;answer&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;Citation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Citation&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;file&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;chunkIndex&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;Display citations in Angular with links to GitHub line numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;munonye-ai-chat-spring-angular&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/documentation-rag-bot-codebase-tutorial/" rel="noopener noreferrer"&gt;Build a Documentation RAG Bot for Your Codebase (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Angular Signals for AI Chat State Management (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 00:22:35 +0000</pubDate>
      <link>https://dev.to/alkademy/angular-signals-for-ai-chat-state-management-2026-5dbn</link>
      <guid>https://dev.to/alkademy/angular-signals-for-ai-chat-state-management-2026-5dbn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/angular-signals-ai-chat-state-management-2026/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Angular signals tutorial 2026&lt;/strong&gt; for AI chat apps — extend &lt;a href="https://www.munonye.com/angular-19-streaming-chat-ui-openai-2026/" rel="noopener noreferrer"&gt;M7-B chat UI&lt;/a&gt; with &lt;code&gt;computed&lt;/code&gt; and &lt;code&gt;effect&lt;/code&gt;. From the &lt;a href="https://www.munonye.com/angular-tutorials/" rel="noopener noreferrer"&gt;Angular tutorials hub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ChatMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="nx"&gt;lastMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;isWaiting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// trigger scroll when messages change&lt;/span&gt;
    &lt;span class="nf"&gt;queueMicrotask&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scrollToBottom&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cross-link &lt;a href="https://www.munonye.com/understanding-forms-in-angular-part-2-reactive-forms/" rel="noopener noreferrer"&gt;reactive forms guide&lt;/a&gt; for validated prompt inputs.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/angular-signals-ai-chat-state-management-2026/" rel="noopener noreferrer"&gt;Angular Signals for AI Chat State Management (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Function Calling from Angular — Structured JSON from LLMs (2026)</title>
      <dc:creator>Alkademy</dc:creator>
      <pubDate>Wed, 01 Jul 2026 00:16:49 +0000</pubDate>
      <link>https://dev.to/alkademy/function-calling-from-angular-structured-json-from-llms-2026-b2a</link>
      <guid>https://dev.to/alkademy/function-calling-from-angular-structured-json-from-llms-2026-b2a</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Canonical URL:&lt;/strong&gt; Republished from &lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;munonye.com&lt;/a&gt;. Full code on &lt;a href="https://github.com/KindsonTheGenius/munonye-ai-chat-spring-angular" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This tutorial shows &lt;strong&gt;Angular function calling&lt;/strong&gt; against a &lt;strong&gt;Spring AI&lt;/strong&gt; backend with &lt;code&gt;@Tool&lt;/code&gt; methods — part of &lt;a href="https://www.munonye.com/ai-developer-tutorials/" rel="noopener noreferrer"&gt;AI Developer Tutorials&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Boot tools
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&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;ProductTools&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;"Look up product price by SKU"&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;ProductPrice&lt;/span&gt; &lt;span class="nf"&gt;getPrice&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;sku&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="n"&gt;catalog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;find&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductPrice&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Unknown"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;ProductPrice&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;sku&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;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;price&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;Register tools when building ChatClient:&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="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chatClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultTools&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productTools&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Angular display
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ProductPrice&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In component after chat response:&lt;/span&gt;
&lt;span class="nf"&gt;parseProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ProductPrice&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;@if&lt;/code&gt; blocks in the template to render a price card when the assistant returns JSON.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Related:&lt;/strong&gt; &lt;a href="https://www.munonye.com/angular-reactive-forms-validation-complete-guide-2026/" rel="noopener noreferrer"&gt;Reactive forms validation&lt;/a&gt; for input validation before sending prompts.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Full tutorial:&lt;/strong&gt; &lt;a href="https://www.munonye.com/angular-function-calling-structured-json-llms/" rel="noopener noreferrer"&gt;Function Calling from Angular — Structured JSON from LLMs (2026)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kindson Munonye&lt;/strong&gt; — &lt;a href="https://github.com/KindsonTheGenius" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://www.linkedin.com/in/kindson" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://www.munonye.com/about/" rel="noopener noreferrer"&gt;About&lt;/a&gt;&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>angular</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
