Skip to content

Commit e465c7a

Browse files
author
Katia Aresti
committed
[##608] MCP simple tutorial
1 parent bc11f71 commit e465c7a

13 files changed

Lines changed: 451 additions & 27 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[id='ai-tutorials']
2+
:context: ai-tutorials
3+
= AI integrations
4+
5+
Use {brandname} with AI frameworks and tools to build intelligent applications with vector search, embedding storage, and natural language interaction.
6+
7+
include::{topics}/ref_ai_tutorials.adoc[leveloffset=+1]
8+
9+
// Restore the parent context.
10+
ifdef::parent-context[:context: {parent-context}]
11+
ifndef::parent-context[:!context:]

documentation/asciidoc/titles/stories.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ include::{stories}/assembly_remote_tutorials.adoc[leveloffset=+1]
66
include::{stories}/assembly_spring_tutorials.adoc[leveloffset=+1]
77
include::{stories}/assembly_quarkus_tutorials.adoc[leveloffset=+1]
88
include::{stories}/assembly_hibernate_tutorials.adoc[leveloffset=+1]
9+
include::{stories}/assembly_ai_tutorials.adoc[leveloffset=+1]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[id='ai-tutorials_{context}']
2+
= AI tutorials
3+
4+
[%header,cols=2*]
5+
|===
6+
|Tutorial link
7+
|Description
8+
9+
|link:{repository}/infinispan-ai/langchain4j[LangChain4j]
10+
|Demonstrates how to use {brandname} as a vector store with LangChain4j for embedding storage and similarity search.
11+
12+
|link:{repository}/infinispan-ai/mcp-server[MCP Server]
13+
|Demonstrates how to enable and use the {brandname} MCP (Model Context Protocol) endpoint to interact with caches, counters, and schemas through AI assistants.
14+
15+
|===

infinispan-ai/langchain4j/pom.xml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<artifactId>infinispan-simple-tutorials-ai-langchain4j</artifactId>
6+
<parent>
7+
<relativePath>../../pom.xml</relativePath>
8+
<version>16.2.0-SNAPSHOT</version>
9+
<groupId>org.infinispan.tutorial.simple</groupId>
10+
<artifactId>infinispan-simple-tutorials</artifactId>
11+
</parent>
12+
<name>Infinispan Simple Tutorials: AI LangChain4j Embedding Store</name>
13+
14+
<properties>
15+
<langchain4j.version>1.13.0-beta23</langchain4j.version>
16+
</properties>
17+
18+
<build>
19+
<plugins>
20+
<plugin>
21+
<groupId>org.codehaus.mojo</groupId>
22+
<artifactId>exec-maven-plugin</artifactId>
23+
<executions>
24+
<execution>
25+
<goals>
26+
<goal>exec</goal>
27+
</goals>
28+
</execution>
29+
</executions>
30+
<configuration>
31+
<executable>java</executable>
32+
<arguments>
33+
<argument>-Djava.net.preferIPv4Stack=true</argument>
34+
<argument>-Djava.util.logging.config.file=src/main/resources/logging.properties</argument>
35+
<argument>-classpath</argument>
36+
<classpath />
37+
<argument>org.infinispan.tutorial.simple.ai.langchain4j.InfinispanLangchain4j</argument>
38+
</arguments>
39+
</configuration>
40+
</plugin>
41+
</plugins>
42+
</build>
43+
44+
<dependencies>
45+
<dependency>
46+
<groupId>org.infinispan.tutorial.simple</groupId>
47+
<artifactId>connect-to-infinispan-server</artifactId>
48+
<version>${project.version}</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>org.infinispan</groupId>
52+
<artifactId>infinispan-client-hotrod</artifactId>
53+
</dependency>
54+
<dependency>
55+
<groupId>dev.langchain4j</groupId>
56+
<artifactId>langchain4j-infinispan</artifactId>
57+
<version>${langchain4j.version}</version>
58+
</dependency>
59+
<dependency>
60+
<groupId>dev.langchain4j</groupId>
61+
<artifactId>langchain4j-embeddings-all-minilm-l6-v2-q</artifactId>
62+
<version>${langchain4j.version}</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.junit.jupiter</groupId>
66+
<artifactId>junit-jupiter</artifactId>
67+
<scope>test</scope>
68+
</dependency>
69+
</dependencies>
70+
</project>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package org.infinispan.tutorial.simple.ai.langchain4j;
2+
3+
import dev.langchain4j.data.document.Metadata;
4+
import dev.langchain4j.data.embedding.Embedding;
5+
import dev.langchain4j.data.segment.TextSegment;
6+
import dev.langchain4j.model.embedding.EmbeddingModel;
7+
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;
8+
import dev.langchain4j.store.embedding.EmbeddingMatch;
9+
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
10+
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
11+
import dev.langchain4j.store.embedding.infinispan.InfinispanEmbeddingStore;
12+
import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
13+
import org.infinispan.tutorial.simple.connect.TutorialsConnectorHelper;
14+
15+
import java.util.List;
16+
17+
public class InfinispanLangchain4j {
18+
19+
static InfinispanEmbeddingStore embeddingStore;
20+
static EmbeddingModel embeddingModel;
21+
22+
public static void main(String[] args) {
23+
initEmbeddingModel();
24+
connectAndCreateStore();
25+
try {
26+
storeAndSearch();
27+
} finally {
28+
disconnect();
29+
}
30+
}
31+
32+
static void initEmbeddingModel() {
33+
embeddingModel = new AllMiniLmL6V2QuantizedEmbeddingModel();
34+
System.out.println("Embedding model initialized. Dimension: " + embeddingModel.dimension());
35+
}
36+
37+
static void connectAndCreateStore() {
38+
ConfigurationBuilder builder = TutorialsConnectorHelper.connectionConfig();
39+
embeddingStore = InfinispanEmbeddingStore.builder()
40+
.cacheName("langchain4j-embeddings")
41+
.dimension(embeddingModel.dimension())
42+
.infinispanConfigBuilder(builder)
43+
.distance(3)
44+
.build();
45+
System.out.println("Connected to Infinispan and created embedding store.");
46+
}
47+
48+
static void storeAndSearch() {
49+
// Store some text segments with metadata
50+
addEmbedding("Infinispan is a distributed in-memory key/value data store",
51+
Metadata.from("source", "docs").put("topic", "overview"));
52+
addEmbedding("Infinispan supports vector search for AI use cases",
53+
Metadata.from("source", "docs").put("topic", "ai"));
54+
addEmbedding("Infinispan can be used as an embedding store with LangChain4j",
55+
Metadata.from("source", "tutorial").put("topic", "ai"));
56+
57+
System.out.println("Stored 3 text segments with embeddings.\n");
58+
59+
// Search by similarity
60+
String query = "How can I use Infinispan with AI?";
61+
System.out.println("Query: \"" + query + "\"");
62+
63+
Embedding queryEmbedding = embeddingModel.embed(query).content();
64+
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
65+
.queryEmbedding(queryEmbedding)
66+
.maxResults(3)
67+
.build();
68+
69+
EmbeddingSearchResult<TextSegment> result = embeddingStore.search(searchRequest);
70+
List<EmbeddingMatch<TextSegment>> matches = result.matches();
71+
72+
System.out.println("Found " + matches.size() + " results:");
73+
for (EmbeddingMatch<TextSegment> match : matches) {
74+
System.out.printf(" Score: %.4f | Text: %s%n",
75+
match.score(), match.embedded().text());
76+
}
77+
}
78+
79+
static void addEmbedding(String text, Metadata metadata) {
80+
TextSegment segment = TextSegment.from(text, metadata);
81+
Embedding embedding = embeddingModel.embed(segment).content();
82+
embeddingStore.add(embedding, segment);
83+
}
84+
85+
static void disconnect() {
86+
if (embeddingStore != null) {
87+
embeddingStore.removeAll();
88+
}
89+
}
90+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
handlers=java.util.logging.ConsoleHandler
2+
java.util.logging.ConsoleHandler.level=INFO
3+
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
4+
.level=INFO
5+
org.infinispan.level=INFO
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.infinispan.tutorial.simple.ai.langchain4j;
2+
3+
import org.junit.jupiter.api.AfterAll;
4+
import org.junit.jupiter.api.BeforeAll;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.junit.jupiter.api.Assertions.assertNotNull;
8+
9+
public class InfinispanLangchain4jTest {
10+
11+
@BeforeAll
12+
public static void start() {
13+
InfinispanLangchain4j.initEmbeddingModel();
14+
InfinispanLangchain4j.connectAndCreateStore();
15+
}
16+
17+
@AfterAll
18+
public static void stop() {
19+
InfinispanLangchain4j.disconnect();
20+
}
21+
22+
@Test
23+
public void testStoreAndSearch() {
24+
assertNotNull(InfinispanLangchain4j.embeddingStore);
25+
assertNotNull(InfinispanLangchain4j.embeddingModel);
26+
InfinispanLangchain4j.storeAndSearch();
27+
}
28+
}

infinispan-ai/mcp-server/.mcp.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"mcpServers": {
3+
"infinispan": {
4+
"type": "http",
5+
"url": "http://localhost:11222/rest/v3/mcp",
6+
"headersHelper": "python3 get-mcp-headers.py"
7+
}
8+
}
9+
}

infinispan-ai/mcp-server/README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Infinispan MCP Server Tutorial
2+
3+
This tutorial shows how to enable and use Infinispan's MCP (Model Context Protocol) endpoint.
4+
5+
Infinispan exposes an MCP endpoint that allows AI assistants and LLM-based tools to interact with
6+
your Infinispan cluster:
7+
* managing caches
8+
* counters
9+
* schemas
10+
11+
... and more through natural language.
12+
13+
## Prerequisites
14+
15+
- Podman and Podman Compose or Docker and Docker Compose
16+
- An MCP client (e.g., Claude Code, Claude Desktop, an IDE with MCP support)
17+
- Python 3 (required for the Digest auth helper script)
18+
19+
## Running the Example
20+
21+
Run all commands from inside this folder.
22+
23+
This starts Infinispan Server with the MCP endpoint enabled at `http://localhost:11222/rest/v3/mcp`.
24+
25+
Infinispan uses HTTP Digest authentication by default. Digest auth is more secure
26+
because credentials are never sent in plain text — instead, a challenge-response mechanism is used.
27+
However, most MCP clients don't support Digest natively, so a Python helper script
28+
(`get-mcp-headers.py`) is included to compute the required headers for each request.
29+
30+
## Connecting Claude Code
31+
32+
Run the following command from inside the `digest-auth` folder.
33+
34+
```bash
35+
claude mcp add infinispan --transport http http://localhost:11222/rest/v3/mcp \
36+
-e INFINISPAN_USER=admin -e INFINISPAN_PASS=password \
37+
--headers-helper "python3 get-mcp-headers.py"
38+
```
39+
40+
### Using the `.mcp.json` file
41+
42+
Alternatively, the folder contains an `mcp.json` file that you can copy to your project root:
43+
44+
```bash
45+
cp mcp.json /path/to/your/project/.mcp.json
46+
```
47+
48+
You can configure the connection with environment variables:
49+
- `INFINISPAN_URL` — MCP endpoint URL (default: `http://localhost:11222/rest/v3/mcp`)
50+
- `INFINISPAN_USER` — Username (default: `admin`)
51+
- `INFINISPAN_PASS` — Password (default: `password`)
52+
53+
## Connecting Claude Desktop
54+
55+
Add the following to your Claude Desktop MCP configuration (`claude_desktop_config.json`).
56+
57+
```json
58+
{
59+
"mcpServers": {
60+
"infinispan": {
61+
"type": "http",
62+
"url": "http://localhost:11222/rest/v3/mcp",
63+
"headersHelper": "python3 /absolute/path/to/digest-auth/get-mcp-headers.py"
64+
}
65+
}
66+
}
67+
```
68+
69+
## Testing Locally
70+
71+
Once Infinispan is running and your MCP client is connected, you can interact with the server
72+
using natural language. Try asking your AI assistant to:
73+
74+
**Create a cache:**
75+
> Create a cache called "my-cache"
76+
77+
**Put an entry:**
78+
> Put the key "greeting" with value "hello world" in my-cache
79+
80+
**Read an entry:**
81+
> Get the value for key "greeting" from my-cache
82+
83+
**List all caches:**
84+
> List all caches
85+
86+
**Create a counter:**
87+
> Create a strong counter called "visitor-count"
88+
89+
You can also verify the MCP endpoint directly with `curl`:
90+
91+
```bash
92+
curl http://localhost:11222/rest/v3/mcp \
93+
--digest -u admin:password \
94+
-H "Content-Type: application/json" \
95+
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
96+
```
97+
98+
## Available MCP Capabilities
99+
100+
Once connected, the Infinispan MCP server exposes:
101+
102+
### Tools
103+
- Cache operations (create, list, get, put, remove, query)
104+
- Counter operations (get, increment, decrement)
105+
- Schema management
106+
107+
### Resources
108+
- Server information and configuration
109+
- Audit and access logs
110+
111+
### Prompts
112+
- Documentation search guidance
113+
114+
## Stopping Infinispan
115+
116+
From the folder you started:
117+
118+
```bash
119+
docker compose down
120+
```
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
infinispan:
3+
image: quay.io/infinispan/server:16.2
4+
ports:
5+
- "11222:11222"
6+
environment:
7+
- USER=admin
8+
- PASS=password
9+
- JAVA_OPTIONS=-Dorg.infinispan.feature.mcp=true

0 commit comments

Comments
 (0)