ADR-010: MCP Server for AI Integration
Status
Superseded by ADR-013 (LangChain4j @Tool Approach)
Date: 2025-12-01 (Superseded: 2025-12-06)
Decision Outcome
This ADR originally proposed using the Quarkus MCP Server extension for AI integration. During implementation (December 2025), we adopted LangChain4j's @Tool annotation approach instead (see ADR-013), which provides:
- Better integration with existing CLI infrastructure
- Unified tool logic layer (
ai/shared/) - Support for multiple AI frameworks (MCP, LangChain4j, Chat API)
- Simpler dependency management
MCP functionality still exists but uses LangChain4j @Tool wrappers in mcp/tools/ package rather than Quarkus MCP Server extension. The tools expose the same capabilities via HTTP/SSE on port 8765.
See ADR-013 for the implemented architecture.
Original Proposal (Historical Context)
Context
The CLI needs to be accessible from AI assistants (Claude Code, Claude Desktop) and automation tools (n8n). The Model Context Protocol (MCP) provides a standardized way to expose tools to AI systems.
Why MCP?
| Aspect | MCP | REST API |
|---|---|---|
| AI Integration | Native (Claude Code, Claude Desktop) | Requires custom integration |
| Natural Language | Built-in tool descriptions | Needs OpenAPI + LLM wrapper |
| Streaming | Progress notifications, logging | Polling or SSE |
| Context Awareness | Resources, prompts, sampling | Manual implementation |
| Transport | stdio (local), SSE (remote) | HTTP only |
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code / Claude Desktop │
│ (MCP Client) │
└──────────────────────────┬──────────────────────────────────────┘
│ JSON-RPC over HTTP/SSE (port 8765)
┌──────────────────────────▼──────────────────────────────────────┐
│ idempiere-cli (Quarkus MCP Server) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ MCP Tools (using @Tool annotations): │ │
│ │ - McpRegistryTools: listTables, describeTable, etc. │ │
│ │ - McpQueryTools: executeQuery, explainQuery │ │
│ │ - McpTableTools: createTable, syncTable, deleteTable │ │
│ │ - McpGeneratorTools: generatePlugin, generateModel, etc. │ │
│ │ - McpDoctorTools: checkEnvironment, checkApi, etc. │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────┐ │
│ │ Shared Tool Logic Layer │ │
│ │ (org.idempiere.cli.ai.shared) │ │
│ └────────────────────────────────┘ │
└──────────────────────────┬──────────────────────────────────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ iDempiere │ │ PostgreSQL│ │ Local │
│ REST API │ │ Database │ │ Files │
└───────────┘ └───────────┘ └───────────┘
Decision
1. Use Quarkus MCP Server Extension
Instead of implementing MCP manually with the raw MCP Java SDK, we use the Quarkus MCP Server extension which provides:
- Declarative
@Tool,@ToolArgannotations - Automatic stdio/HTTP transport handling
- CDI integration for dependency injection
- Native compilation support
Maven Dependency:
<!-- Quarkus MCP Server (ADR-010) -->
<!-- NOTE: Using HTTP transport instead of stdio to avoid stdout capture conflict with Picocli -->
<dependency>
<groupId>io.quarkiverse.mcp</groupId>
<artifactId>quarkus-mcp-server-http</artifactId>
<version>${quarkus-mcp.version}</version>
</dependency>
Why HTTP instead of STDIO?
The CLI uses Picocli which captures stdout for command output. STDIO transport conflicts with this because MCP also uses stdout for JSON-RPC messages. HTTP/SSE transport runs on a separate port, avoiding this conflict.
2. Shared Tool Logic Layer
All business logic is in the org.idempiere.cli.ai.shared package, shared between:
- MCP Tools (this ADR) - for Claude Code/Desktop
- LangChain4j Tools (ADR-013) - for the
askcommand
org.idempiere.cli.ai/
├── shared/ # Core business logic
│ ├── ToolResult.java # Standardized result format
│ ├── RegistryToolLogic.java # AD registry operations
│ ├── QueryToolLogic.java # SQL query execution
│ ├── TableToolLogic.java # Table operations
│ ├── GeneratorToolLogic.java# Code generation
│ └── DoctorToolLogic.java # Diagnostics
│
├── langchain/tools/ # LangChain4j wrappers (ADR-013)
│ ├── RegistryTools.java
│ └── QueryTools.java
│
└── ../mcp/tools/ # MCP wrappers (this ADR)
├── McpRegistryTools.java
├── McpQueryTools.java
├── McpTableTools.java
├── McpGeneratorTools.java
└── McpDoctorTools.java
3. Tool Implementation Example
@ApplicationScoped
public class McpRegistryTools {
@Inject
RegistryToolLogic registryLogic;
@Tool(description = "List tables in the iDempiere Application Dictionary.")
ToolResponse listTables(
@ToolArg(description = "SQL LIKE pattern to filter tables") String pattern,
@ToolArg(description = "Only show custom tables (XX_ prefix)") Boolean customOnly,
@ToolArg(description = "Maximum number of results") Integer limit) {
ToolResult result = registryLogic.listTables(pattern,
customOnly != null ? customOnly : false, limit);
return result.isSuccess()
? ToolResponse.success(result.toJson())
: ToolResponse.error(result.toJson());
}
}
4. Registered Tools
| Category | Tools |
|---|---|
| Registry | listTables, describeTable, listColumns, listWindows, listProcesses, listReferences, searchRegistry, getStatistics |
| Query | executeQuery, explainQuery, getQueryTemplates |
| Table | createTable, syncTable, listTablesByEntity, deleteTable, getColumnPrefixHelp |
| Generator | listGenerators, getGeneratorInfo, generatePlugin, generateModel, generateProcess, generateCallout, runGenerator |
| Doctor | checkEnvironment, checkApi, checkDatabase, getConfigStatus |
5. Running the MCP Server
The CLI runs in two modes:
| Mode | HTTP Port | Usage |
|---|---|---|
| CLI (default) | Disabled (0) | java -jar idempiere-hub-runner.jar doctor |
| MCP Server | 8765 | java -Dquarkus.profile=mcp -jar idempiere-hub-runner.jar mcp-server |
Start MCP Server:
# With dual database connection (iDempiere + RAG Vector DB)
IDEMPIERE_DB_HOST="localhost" \
IDEMPIERE_DB_PORT="5433" \
IDEMPIERE_DB_NAME="idempiere" \
IDEMPIERE_DB_USER="adempiere" \
IDEMPIERE_DB_PASSWORD="adempiere" \
RAG_VECTORDB_PG_HOST="localhost" \
RAG_VECTORDB_PG_PORT="5432" \
RAG_VECTORDB_PG_NAME="vector" \
RAG_VECTORDB_PG_USER="postgres" \
RAG_VECTORDB_PG_PASSWORD="postgres" \
java -Dquarkus.profile=mcp -jar target/idempiere-hub-runner.jar server mcp
# MCP endpoints will be available at:
# - Streamable HTTP: http://localhost:8765/mcp
# - SSE: http://localhost:8765/mcp/sse
6. Claude Desktop Configuration
For HTTP/SSE transport (recommended), configure Claude Desktop to connect to the running MCP server with Bearer token authentication:
Step 1: Obtain JWT Token from iDempiere
# Login to get JWT access token
POST http://localhost:8080/api/v1/auth/tokens
{
"userName": "SuperUser",
"password": "System",
"parameters": {
"clientId": 0, # System tenant for AD operations
"roleId": 0, # System Administrator
"organizationId": 0
}
}
# Response
{
"token": "eyJraWQiOiJpZ...", # ← Use this as Bearer token
"refresh_token": "...",
"userId": 100
}
Step 2: Configure Claude Desktop with Bearer Token
~/.claude/mcp.json:
{
"mcpServers": {
"iDempiere": {
"httpUrl": "http://localhost:8080/mcp/streaming",
"timeout": 30000,
"trust": true,
"headers": {
"Authorization": "Bearer eyJraWQiOiJpZ..."
}
}
}
}
Note on Token Expiration:
- JWT access tokens expire in 1 hour by default
- For long-running MCP sessions, implement automatic token refresh (see AUTH_STRATEGY.md)
- Or use refresh tokens to obtain new access tokens periodically
Alternative: STDIO transport (requires separate build with quarkus-mcp-server-stdio):
{
"mcpServers": {
"idempiere": {
"command": "java",
"args": ["-jar", "/path/to/idempiere-hub-runner.jar"],
"env": {
"IDEMPIERE_DB_HOST": "localhost",
"IDEMPIERE_DB_PORT": "5432",
"IDEMPIERE_DB_NAME": "idempiere",
"IDEMPIERE_DB_USER": "adempiere",
"IDEMPIERE_DB_PASSWORD": "adempiere"
}
}
}
}
Consequences
Positive
- Native AI Integration: Claude Code/Desktop work natively via MCP
- Declarative Approach: Simple
@Toolannotations instead of manual MCP SDK - Shared Logic: Business logic reused between MCP and LangChain4j
- Quarkus Integration: CDI, native compilation, and Quarkus ecosystem
- Type Safety: Compile-time validation of tool signatures
Negative
- Quarkus Dependency: Tied to Quarkus MCP Server extension
- HTTP Transport Requires Server: MCP server must be running separately (not subprocess spawned by Claude Desktop)
Neutral
- LangChain4j (
askcommand) provides an alternative AI interface - Both MCP and LangChain4j share the same tool logic
Usage Guide
See USER_GUIDE.md for detailed usage instructions.
References
- Model Context Protocol Specification
- Quarkus MCP Server Documentation
- quarkiverse/quarkus-mcp-server
- ADR-013: LangChain4j Integration
- Authentication Architecture - Operational authentication for CLI, Chat API, and MCP Server
- Simple Authentication - System tenant authentication for AD operations
- Authentication Strategy - Tenant/role decisions, operational scenarios