An AI agent is a system that uses a language model to understand instructions, decide on actions, and execute them using available tools.
In practice, what does this look like?
In this article, we build a simple task-management AI agent in Java using Micronaut, LangChain4j, and Model Context Protocol (MCP). It demonstrates how an agent interprets natural language, selects the right action, and executes it safely through a structured tool interface.

Full code for this project is available here:

What is an AI Agent?

An AI agent is a software system that uses a language model to interpret user input, reason about it, and take actions by invoking tools or APIs.

At a minimum, an AI agent consists of:

  1. A reasoning model – typically an LLM that understands user instructions
  2. A set of tools – functions or APIs the agent can invoke
  3. An execution loop – a cycle of:
    → understand → decide → act → return result

In this project, that loop is implemented cleanly and explicitly.

How the agent works in this repo

  • TaskPlannerAiService (LangChain4j) prompts the model to produce a single structured JSON tool call
  • TaskAgentOrchestrator parses and validates that JSON
  • McpTaskClient executes the selected tool via MCP

This design enforces an important rule:

The model never directly modifies business data.
It only decides what should happen, while the system controls how it happens.


What is MCP (Model Context Protocol)?

Model Context Protocol (MCP) is a standardized protocol that defines how AI agents interact with external tools and services in a structured and reliable way.

Without MCP, applications often implement custom tool-calling formats, leading to inconsistent integrations and fragile systems.

MCP provides:

  • A standard interface for exposing tools
  • Structured schemas for tool arguments
  • A JSON-RPC-based communication model
  • A clean separation between AI decision-making and system execution

Why MCP matters

In this project, MCP provides:

  • A stable tool interface (create-task, list-tasks, complete-task, etc.)
  • Structured and validated arguments
  • A predictable lifecycle (initializetools/call)
  • Loose coupling between the agent and backend services

In simple terms:

MCP is the contract between AI reasoning and real-world actions.

Project Architecture

This project is split into two modules:

1. task-mcp-server — MCP Tool Server (Micronaut)

This module exposes task-related operations as MCP tools using Micronaut.

Tools are defined using annotations like:

  • @Tool(name = "create-task")
  • @Tool(name = "list-tasks")
  • @Tool(name = "complete-task")
  • @Tool(name = "set-priority")

All tools operate on an in-memory TaskStore.

💡 Key detail:
Both REST APIs and MCP tools share the same store. So:

  • Data created via REST is visible to MCP
  • Data created via MCP is visible to REST

2. task-agent — AI Agent Runtime

This module contains the AI-driven decision-making layer.

Skills as configuration

Instead of hardcoding behavior, the agent uses a skills.md file:

@SystemMessage(fromResource = "skills.md") @UserMessage("User instruction: {{instruction}}") String plan(@V("instruction") String instruction);

Enter fullscreen mode

Exit fullscreen mode

This allows you to:

  • Update agent behavior without recompiling
  • Define tool usage rules in Markdown

Orchestration layer

TaskAgentOrchestrator is responsible for:

  • Parsing model output
  • Validating JSON structure
  • Applying safe defaults
  • Calling MCP tools via McpTaskClient

MCP client

McpTaskClient communicates with the MCP server using JSON-RPC:

  • Endpoint: http://127.0.0.1:8080/mcp
  • Flow: initializetools/call

End-to-End Flow

Example instruction

"Create task Buy milk with high priority and tag home"

Execution steps

  1. Agent sends instruction + skills definition to the model
  2. Model returns structured JSON:

{ "tool": "create-task", "arguments": { "title": "Buy milk", "priority": "HIGH", "tags": "home" } }

Enter fullscreen mode

Exit fullscreen mode

  1. Orchestrator parses and validates the JSON
  2. MCP client calls create-task
  3. MCP server executes and returns the result

Why This Pattern Works

This architecture is simple but powerful.

Benefits

  • Add new tools without changing agent logic
  • Update behavior via skills.md
  • Swap LLM providers easily
  • Keep execution deterministic and safe
  • Avoid unpredictable model side effects

Instead of letting the model “do everything,” you:

  • Let the model decide
  • Let your system execute

Running the Project Locally

Start MCP server

cd task-mcp-server mvn exec:java

Enter fullscreen mode

Exit fullscreen mode

Start agent

cd task-agent OPENAI_API_KEY=<your-key> mvn exec:java

Enter fullscreen mode

Exit fullscreen mode

Call the agent

curl -sS -X POST http://127.0.0.1:8081/api/agent/run \ -H 'content-type: application/json' \ -d '{"instruction":"Create task Buy milk with high priority and tag home"}'

Enter fullscreen mode

Exit fullscreen mode

Inspect skills

curl -sS http://127.0.0.1:8081/api/agent/skills

Enter fullscreen mode

Exit fullscreen mode

Repositories

Here are the key modules used in this article and what they do:

task-mcp-server
https://github.com/jobinesh/java-ai-lab/tree/main/task-mcp-server
Micronaut-based MCP server that exposes task management tools (create-task, list-tasks, etc.) via MCP and REST. This is where all actual business logic executes.

task-agent
https://github.com/jobinesh/java-ai-lab/tree/main/task-agent
LangChain4j-based AI agent that interprets user instructions, decides which tool to call, and invokes MCP endpoints.

Final Takeaway

Think of the system in three layers:

  • AI Agent (LangChain4j): decides what to do
  • MCP Server (Micronaut): defines what can be done
  • Business Logic: ensures how it is done safely

That separation is the key to building reliable AI systems.

It keeps your AI flexible, your APIs stable, and your business logic safe.


If you're exploring AI agents in Java, this pattern is a great starting point—and a solid foundation for production-grade systems.