🚀 Building Your First AMCP Agent - Step-by-Step Tutorial

Complete beginner guide to creating your first AMCP agent with Quarkus and Kafka


Table of Contents

  1. Prerequisites
  2. Project Setup
  3. Create Your First Agent
  4. Run Your Agent
  5. Test Your Agent
  6. Next Steps

Prerequisites

Before starting, ensure you have:

# Check Java version (11+)
java -version

# Check Maven version (3.6+)
mvn -version

# Install Quarkus CLI
curl -Ls https://sh.quarkus.io | bash

# Install Kafka (optional, for advanced examples)
# Using Docker:
docker run -d --name kafka \
  -p 9092:9092 \
  confluentinc/cp-kafka:latest

Project Setup

Step 1: Create Quarkus Project

# Create new Quarkus project with AMCP extension
quarkus create app my-first-agent \
  --extension=amcp-quarkus,kafka

# Navigate to project
cd my-first-agent

Step 2: Project Structure

my-first-agent/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── MyFirstAgent.java
│   │   └── resources/
│   │       └── application.properties
│   └── test/
│       └── java/
│           └── MyFirstAgentTest.java
├── pom.xml
└── README.md

Step 3: Update Dependencies

Edit pom.xml:

<dependency>
    <groupId>org.amcp</groupId>
    <artifactId>amcp-core</artifactId>
    <version>1.6.0</version>
</dependency>

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-kafka-client</artifactId>
</dependency>

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-client-reactive</artifactId>
</dependency>

Create Your First Agent

Step 1: Configure Application Properties

Edit src/main/resources/application.properties:

# AMCP Configuration
amcp.enabled=true
amcp.agent.name=my-first-agent
amcp.agent.version=1.0.0

# Kafka Configuration
kafka.bootstrap.servers=localhost:9092
kafka.group.id=my-first-agent-group

# LLM Configuration (optional)
amcp.llm.provider=local
amcp.llm.local.endpoint=http://localhost:8000
amcp.llm.local.model=llama2-7b

# Server Configuration
quarkus.http.port=8080
quarkus.application.name=my-first-agent

Step 2: Create Your First Agent

Create src/main/java/MyFirstAgent.java:

package org.example;

import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
import org.amcp.agent.Agent;
import org.amcp.agent.AgentContext;
import org.amcp.agent.Message;
import org.amcp.llm.LLMService;
import org.amcp.llm.ChatConfig;
import jakarta.inject.Inject;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * My First AMCP Agent
 * 
 * This is a simple greeting agent that:
 * 1. Listens for messages on a Kafka topic
 * 2. Processes the message with LLM (optional)
 * 3. Generates a response
 * 4. Publishes the response
 */
@QuarkusMain
public class MyFirstAgent extends Agent implements QuarkusApplication {
    
    @Inject
    LLMService llmService;
    
    @Override
    public void initialize(AgentContext context) {
        System.out.println("🤖 Initializing My First Agent...");
        
        // Set agent metadata
        this.setAgentName("my-first-agent");
        this.setVersion("1.0.0");
        
        // Subscribe to incoming messages
        context.subscribe("greetings", this::handleGreeting);
        context.subscribe("questions", this::handleQuestion);
        
        System.out.println("✅ Agent initialized successfully!");
    }
    
    /**
     * Handle greeting messages
     */
    private void handleGreeting(Message message) {
        String userGreeting = message.getPayload();
        
        System.out.println("📨 Received greeting: " + userGreeting);
        
        // Generate response
        String response = generateGreetingResponse(userGreeting);
        
        System.out.println("📤 Sending response: " + response);
        
        // Publish response
        this.publish("greeting-responses", response);
    }
    
    /**
     * Handle question messages with LLM
     */
    private void handleQuestion(Message message) {
        String question = message.getPayload();
        
        System.out.println("❓ Received question: " + question);
        
        try {
            // Use LLM to answer question
            String answer = llmService.chat(
                question,
                new ChatConfig()
                    .model("llama2-7b")
                    .temperature(0.7)
                    .maxTokens(500)
            );
            
            System.out.println("💡 Generated answer: " + answer);
            
            // Publish answer
            this.publish("question-answers", answer);
            
        } catch (Exception e) {
            System.err.println("⚠️ Error processing question: " + e.getMessage());
            this.publish("question-answers", "Sorry, I couldn't process your question.");
        }
    }
    
    /**
     * Generate greeting response
     */
    private String generateGreetingResponse(String greeting) {
        String timestamp = LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        
        return String.format(
            "Hello! You said: '%s' at %s. Welcome to AMCP!",
            greeting,
            timestamp
        );
    }
    
    @Override
    public int run(String... args) throws Exception {
        System.out.println("🚀 Starting My First Agent...");
        
        // Agent will run indefinitely
        Thread.currentThread().join();
        
        return 0;
    }
}

Step 3: Create REST Endpoint

Create src/main/java/GreetingResource.java:

package org.example;

import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.amcp.agent.AgentContext;

@Path("/api")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class GreetingResource {
    
    @Inject
    AgentContext agentContext;
    
    @POST
    @Path("/greet")
    public Response greet(String message) {
        try {
            // Publish message to agent
            agentContext.publish("greetings", message);
            
            return Response.ok()
                .entity(new Response("Message sent to agent"))
                .build();
        } catch (Exception e) {
            return Response.serverError()
                .entity(new ErrorResponse(e.getMessage()))
                .build();
        }
    }
    
    @POST
    @Path("/ask")
    public Response ask(String question) {
        try {
            // Publish question to agent
            agentContext.publish("questions", question);
            
            return Response.ok()
                .entity(new Response("Question sent to agent"))
                .build();
        } catch (Exception e) {
            return Response.serverError()
                .entity(new ErrorResponse(e.getMessage()))
                .build();
        }
    }
    
    @GET
    @Path("/health")
    public Response health() {
        return Response.ok()
            .entity(new HealthResponse("Agent is running", "healthy"))
            .build();
    }
    
    // Response classes
    public static class Response {
        public String message;
        
        public Response(String message) {
            this.message = message;
        }
    }
    
    public static class ErrorResponse {
        public String error;
        
        public ErrorResponse(String error) {
            this.error = error;
        }
    }
    
    public static class HealthResponse {
        public String status;
        public String health;
        
        public HealthResponse(String status, String health) {
            this.status = status;
            this.health = health;
        }
    }
}

Run Your Agent

Step 1: Start in Development Mode

# Start Quarkus in development mode
quarkus dev

# Output:
# __  ____  __  _____   ___  __ ____  ______
# --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
# -/ /_/ / /_/ / __ |/ __, / ,< / /_/ /\ \
#--\___\_\____/_/ |_/_/ |_/_/|_|\____/___/
# Quarkus 3.5.0 on JVM
# Listening on: http://localhost:8080
# 
# 🤖 Initializing My First Agent...
# ✅ Agent initialized successfully!

Step 2: Verify Agent is Running

# Check health endpoint
curl http://localhost:8080/api/health

# Response:
# {
#   "status": "Agent is running",
#   "health": "healthy"
# }

Test Your Agent

Test 1: Send a Greeting

# Send greeting message
curl -X POST http://localhost:8080/api/greet \
  -H "Content-Type: application/json" \
  -d '"Hello, AMCP Agent!"'

# Response:
# {
#   "message": "Message sent to agent"
# }

# Check agent output:
# 📨 Received greeting: Hello, AMCP Agent!
# 📤 Sending response: Hello! You said: 'Hello, AMCP Agent!' at 2025-11-11 08:15:30. Welcome to AMCP!

Test 2: Ask a Question

# Send question
curl -X POST http://localhost:8080/api/ask \
  -H "Content-Type: application/json" \
  -d '"What is AMCP?"'

# Response:
# {
#   "message": "Question sent to agent"
# }

# Check agent output:
# ❓ Received question: What is AMCP?
# 💡 Generated answer: AMCP is the Agent Mesh Communication Protocol...

Test 3: Using Kafka Topics

# In another terminal, consume responses
kafka-console-consumer --bootstrap-server localhost:9092 \
  --topic greeting-responses \
  --from-beginning

# Send greeting
curl -X POST http://localhost:8080/api/greet \
  -H "Content-Type: application/json" \
  -d '"Hi there!"'

# You should see the response in the consumer terminal

Create Unit Tests

Create src/test/java/MyFirstAgentTest.java:

package org.example;

import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.amcp.agent.Message;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

@QuarkusTest
public class MyFirstAgentTest {
    
    @Inject
    MyFirstAgent agent;
    
    @Test
    public void testAgentInitialization() {
        assertNotNull(agent);
        assertEquals("my-first-agent", agent.getAgentName());
    }
    
    @Test
    public void testGreetingHandling() {
        Message greeting = new Message("Hello, Agent!");
        
        // This would be called by the agent
        agent.handleGreeting(greeting);
        
        // Verify response was generated
        assertNotNull(greeting);
    }
    
    @Test
    public void testAgentVersion() {
        assertEquals("1.0.0", agent.getVersion());
    }
}

Run tests:

# Run all tests
mvn test

# Run specific test
mvn test -Dtest=MyFirstAgentTest

# Output:
# [INFO] -------------------------------------------------------
# [INFO] T E S T S
# [INFO] -------------------------------------------------------
# [INFO] Running org.example.MyFirstAgentTest
# [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
# [INFO] -------------------------------------------------------

Build for Production

Step 1: Build JAR

# Build executable JAR
mvn clean package

# Output:
# [INFO] Building jar: target/my-first-agent-1.0.0-runner.jar

Step 2: Build Native Image

# Build native executable (requires GraalVM)
mvn clean package -Dnative

# Output:
# [INFO] Building native executable...
# [INFO] Native executable created: target/my-first-agent-1.0.0-runner

Step 3: Run Native Image

# Run native executable
./target/my-first-agent-1.0.0-runner

# Output:
# 🚀 Starting My First Agent...
# ✅ Agent initialized successfully!

Deploy with Docker

Create Dockerfile:

FROM quay.io/quarkus/quarkus-distroless-image:2.0

COPY target/my-first-agent-1.0.0-runner /application

EXPOSE 8080

CMD ["/application", "-Dquarkus.http.host=0.0.0.0"]

Build and run:

# Build Docker image
docker build -t my-first-agent:1.0.0 .

# Run container
docker run -p 8080:8080 my-first-agent:1.0.0

# Test from host
curl http://localhost:8080/api/health

Next Steps

1. Add More Features

2. Learn Advanced Topics

3. Explore Examples

4. Join Community


Troubleshooting

Issue: Port 8080 already in use

# Use different port
quarkus dev -Dquarkus.http.port=8081

Issue: Kafka connection error

# Verify Kafka is running
docker ps | grep kafka

# Start Kafka if needed
docker run -d --name kafka \
  -p 9092:9092 \
  confluentinc/cp-kafka:latest

Issue: LLM connection error

# Verify LLM endpoint is running
curl http://localhost:8000/health

# Or disable LLM for now
# Comment out LLM configuration in application.properties

Summary

You’ve successfully created your first AMCP agent! You learned:

✅ How to set up a Quarkus project with AMCP
✅ How to create an agent class
✅ How to handle messages
✅ How to integrate with Kafka
✅ How to test your agent
✅ How to deploy to production


Resources


Happy agent building! 🚀