Skip to main content

Generate Entry Point

The generateEntryPoint | gep task will generate a module in Infrastructure layer, this task has one required parameter type.
Whether you'll use generic one also parameter name is required.

gradle generateEntryPoint --type=[entryPointType]
gradle gep --type [entryPointType]
TypeNameParameterValuesDefault
genericEmpty Entry Point--nameString-
asynceventhandlerAsync Event Handler--edatrue, falsefalse
--techrabbitmq, kafka, rabbitmq,kafkarabbitmq
graphqlAPI GraphQL--pathgqlString (path)/graphql
kafkaKafka Consumer---
mcpMCP Server (Model Context Protocol)--nameString-
--enable-toolstrue, falsetrue
--enable-resourcestrue, falsetrue
--enable-promptstrue, falsetrue
--enable-securitytrue, falsetrue
--enable-audittrue, falsetrue
mqJMS MQ Client to listen messages---
restmvcAPI REST (Spring Boot Starter Webmvc)--servertomcat, jettytomcat
--authorizationtrue, falsefalse
--versioningHEADER, PATH, NONENONE
--from-swaggerFile pathswagger.yaml
--swaggertrue, falsefalse
rsocketRsocket Controller Entry Point---
sqsSQS Listener---
webfluxAPI REST (Spring Boot Starter WebFlux)--routertrue, falsetrue
--authorizationtrue, falsefalse
--versioningHEADER, PATH, NONENONE
--from-swaggerFile pathswagger.yaml
--swaggertrue, falsefalse
kafkastrimziKafka Strimzi Consumer Entry Point--nameString-
--topic-consumerString (topic name)test-with-registries
agentSpring AI A2A Reactive Agent--nameStringproject name
--agent-enable-kafkatrue, falsetrue
--agent-enable-mcp-clienttrue, falsetrue

Additionally, if you'll use a restmvc, you can specify the web server on which the application will run. By default, Tomcat.

Reference for serverOptionName
tomcatTomcat server (default)
jettyJetty server
gradle generateEntryPoint --type=restmvc --server=[serverOption]
gradle gep --type=restmvc --server=[serverOption]

This task will generate something like that:

πŸ“¦infrastructure
┣ πŸ“‚entry-points
┃ β”— πŸ“‚generic
┃ ┃ ┣ πŸ“‚src
┃ ┃ ┃ ┣ πŸ“‚main
┃ ┃ ┃ ┃ β”— πŸ“‚java
┃ ┃ ┃ ┃ ┃ β”— πŸ“‚[package]
┃ ┃ ┃ ┃ ┃ ┃ β”— πŸ“‚generic
┃ ┃ ┃ β”— πŸ“‚test
┃ ┃ ┃ ┃ β”— πŸ“‚java
┃ ┃ ┃ ┃ ┃ β”— πŸ“‚[package]
┃ ┃ ┃ ┃ ┃ ┃ β”— πŸ“‚generic
┃ ┃ β”— πŸ“œbuild.gradle

Usage Example for Kafka Strimzi Consumer​

gradle generateEntryPoint --type=kafkastrimzi 
gradle gep --type=kafkastrimzi
gradle generateEntryPoint --type=kafkastrimzi --name=myConsumer --topic-consumer=myTopic
gradle gep --type=kafkastrimzi --name=myConsumer --topic-consumer=myTopic

This will generate a specialized entry point for consuming Kafka messages using Strimzi, with custom parameters.

Usage Example for MCP (Model Context Protocol)​

The mcp entry point type generates a reactive MCP server with Tools, Resources, and Prompts capabilities, based on Spring AI.

Basic Command​

gradle generateEntryPoint --type=mcp
gradle gep --type=mcp

Available Parameters​

ParameterValuesDefaultDescription
--nameStringnullMCP Server Name
--enable-toolstrue/falsetrueEnable Tools
--enable-resourcestrue/falsetrueEnable Resources
--enable-promptstrue/falsetrueEnable Prompts
--enable-securitytrue/falsetrueEnable OAuth2/Entra ID Security
--enable-audittrue/falsetrueEnable Audit Logging (requires AOP)

Usage Examples​

# Generate with all capabilities enabled (default: includes security and audit)
gradle generateEntryPoint --type=mcp

# Only Tools
gradle generateEntryPoint --type=mcp --enable-tools=true --enable-resources=false --enable-prompts=false

# Only Resources
gradle generateEntryPoint --type=mcp --enable-tools=false --enable-resources=true --enable-prompts=false

# With custom name
gradle generateEntryPoint --type=mcp --name=BancolombiaAssistant

# Without security (development mode only)
gradle generateEntryPoint --type=mcp --enable-security=false

# Without audit logging
gradle generateEntryPoint --type=mcp --enable-audit=false

Generated Structure​

infrastructure/
└── entry-points/
└── mcp-server/
β”œβ”€β”€ build.gradle
└── src/
β”œβ”€β”€ main/java/[package]/mcp/
β”‚ β”œβ”€β”€ tools/
β”‚ β”‚ β”œβ”€β”€ HealthTool.java
β”‚ β”‚ └── ExampleTool.java
β”‚ β”œβ”€β”€ resources/
β”‚ β”‚ β”œβ”€β”€ SystemInfoResource.java
β”‚ β”‚ └── UserInfoResource.java
β”‚ β”œβ”€β”€ prompts/
β”‚ β”‚ └── ExamplePrompt.java
β”‚ └── audit/ # If audit enabled
β”‚ └── McpAuditAspect.java
└── test/java/[package]/mcp/
β”œβ”€β”€ tools/
β”œβ”€β”€ resources/
β”œβ”€β”€ prompts/
└── audit/ # If audit enabled
└── McpAuditAspectTest.java

applications/
└── app-service/
└── src/
β”œβ”€β”€ main/java/co/com/bancolombia/config/
β”‚ └── McpSecurityConfig.java # If security enabled
└── test/java/co/com/bancolombia/config/
└── McpSecurityConfigTest.java # If security enabled

Automatic Configuration​

The command also automatically updates application.yaml with the MCP configuration:

spring:
ai:
mcp:
server:
protocol: "STATELESS"
name: "${spring.application.name}"
version: "1.0.0"
type: "ASYNC"
instructions: |
Reactive MCP Server with capabilities:
- Tools: Executable tools
- Resources: Access to system and user data
- Prompts: Custom conversation templates

Security: Authenticated via Entra ID (Bearer Token)
streamable-http:
mcp-endpoint: "/mcp/${spring.application.name}"
capabilities:
tool: true
resource: true
prompt: true
request-timeout: "30s"
# Security configuration (if --enable-security=true)
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://login.microsoftonline.com/${TENANT_ID}/v2.0
client-id: ${CLIENT_ID}

jwt:
json-exp-roles: /roles # JSON path for role extraction

Security and Audit Features​

By default, the MCP entry point is generated with security and audit enabled.

Security (McpSecurityConfig)​

When --enable-security=true (default), the generator creates a complete OAuth2/Entra ID security configuration:

  • OAuth2 Resource Server: Validates JWT tokens from Entra ID
  • JWT Validation: Validates audience (aud), app ID (appid), and issuer
  • Role Extraction: Extracts roles from JWT claims using configurable JSON path
  • Method Security: Enables @PreAuthorize annotations for RBAC
  • Public Endpoints: Actuator health and info endpoints remain public
  • Access Denied Logging: Explicitly logs security rejections with user and path details

Audit Logging (McpAuditAspect)​

When --enable-audit=true (default), the generator creates an AOP aspect that automatically logs all MCP operations:

  • What is audited: All calls to @Tool, @McpResource, and @McpPrompt methods
  • Information logged:
    • Who: Client ID extracted from JWT token (appid, azp, or aud)
    • What: Class, method name, and arguments
    • When: Timestamp (automatic via logging framework)
    • Result: Success or failure
    • Performance: Execution time in milliseconds
  • Reactive Support: Integrates seamlessly with Mono return types
  • Security Context: Extracts authentication details from ReactiveSecurityContextHolder

Example audit log output:

πŸ“Š [AUDIT] TOOL llamado por: a1b2c3d4-client-id | MΓ©todo: ExampleTool.echo | Args: ["hello"]
βœ… [AUDIT] TOOL exitoso | Client: a1b2c3d4-client-id | MΓ©todo: ExampleTool.echo | Tiempo: 45ms

Component Development​

Create a Tool​


@Component
public class CalculatorTool {
@McpTool(name = "multiply", description = "Multiplies two numbers")
public Mono<Integer> multiply(
@McpToolParam(description = "First number", required = true) int a,
@McpToolParam(description = "Second number", required = true) int b) {
return Mono.just(a * b);
}
}

Create a Resource​


@Component
public class ConfigResource {
@McpResource(
uri = "resource://config/app",
name = "app-config",
description = "Application configuration")
public Mono<ReadResourceResult> getConfig() {
return Mono.fromCallable(() -> {
// Implementation
});
}
}

Create a Prompt​


@Component
public class SupportPrompt {
@McpPrompt(
name = "customer-support",
description = "Generates a customer support prompt")
public Mono<GetPromptResult> customerSupport(
@McpArg(name = "issue", required = true) String issue) {
return Mono.fromCallable(() -> {
// Implementation
});
}
}

Usage Example for Agent (Spring AI A2A)​

The agent entry point type generates a full reactive A2A (Agent-to-Agent) skeleton based on Spring AI and WebFlux. It exposes two standard A2A REST endpoints (POST /message:send and GET /.well-known/agent-card.json) and optionally Kafka transport, using the A2A protocol with correlation and trace identifiers for observability.

The generated chat adapter is mutually exclusive:

  • with --agent-enable-mcp-client=true the scaffold adds mcp-client
  • with --agent-enable-mcp-client=false the scaffold adds spring-ai-adapter

Basic Command​

gradle generateEntryPoint --type=agent
gradle gep --type=agent

Available Parameters​

ParameterValuesDefaultDescription
--nameStringproject nameAgent name (used in spring.application.name)
--agent-enable-kafkatrue/falsetrueAdd Kafka consumer + producer transport
--agent-enable-mcp-clienttrue/falsetrueAdd mcp-client instead of spring-ai-adapter for tool use

Usage Examples​

# Full agent: REST + Kafka + MCP client (Default behavior)
gradle generateEntryPoint --type=agent --name=my-agent

# Minimal REST-only agent without async transport and without MCP
# Generates spring-ai-adapter as the ChatGateway implementation
gradle generateEntryPoint --type=agent --name=my-agent --agent-enable-kafka=false --agent-enable-mcp-client=false

# Agent with Kafka only
# Generates spring-ai-adapter and Kafka modules
gradle generateEntryPoint --type=agent --name=my-agent --agent-enable-mcp-client=false

# Agent with MCP client only (REST + MCP)
gradle generateEntryPoint --type=agent --name=my-agent --agent-enable-kafka=false

Generated Structure​

domain/
β”œβ”€β”€ model/src/main/java/[package]/model/
β”‚ β”œβ”€β”€ a2a/
β”‚ β”‚ β”œβ”€β”€ SendMessageRequest.java # Inbound A2A request envelope
β”‚ β”‚ β”œβ”€β”€ SendMessageResponse.java # Outbound A2A response envelope
β”‚ β”‚ β”œβ”€β”€ Message.java # Message content (role + content)
β”‚ β”‚ β”œβ”€β”€ Task.java # Task result with status and timing
β”‚ β”‚ β”œβ”€β”€ Error.java # Structured error model
β”‚ β”‚ └── AgentCard.java # Agent metadata for /.well-known/agent-card.json
β”‚ └── chat/gateways/
β”‚ β”œβ”€β”€ ChatGateway.java # Port: send prompt β†’ LLM β†’ Mono<String>
β”‚ └── AgentResponseGateway.java # Port: publish response to Kafka
└── usecase/src/main/java/[package]/usecase/
└── AgentChatUseCase.java # Core logic: LLM call + response routing

infrastructure/
β”œβ”€β”€ entry-points/
β”‚ └── reactive-web/
β”‚ β”œβ”€β”€ build.gradle
β”‚ └── src/
β”‚ β”œβ”€β”€ main/java/[package]/api/
β”‚ β”‚ β”œβ”€β”€ Handler.java # Handles POST /message:send
β”‚ β”‚ β”œβ”€β”€ RouterRest.java # Routes: /message:send + /.well-known/agent-card.json
β”‚ β”‚ └── config/
β”‚ β”‚ β”œβ”€β”€ CorsConfig.java
β”‚ β”‚ β”œβ”€β”€ JacksonConfig.java # JsonMapper bean (Jackson 3)
β”‚ β”‚ └── SecurityHeadersConfig.java
β”‚ └── test/java/[package]/api/
β”‚ β”œβ”€β”€ HandlerTest.java
β”‚ └── RouterRestTest.java
└── driven-adapters/
β”œβ”€β”€ mcp-client/ # Generated when --agent-enable-mcp-client=true
β”‚ β”œβ”€β”€ build.gradle
β”‚ └── src/main/java/[package]/mcpclient/adapter/
β”‚ └── ChatGatewayAdapter.java
└── spring-ai-adapter/ # Generated when --agent-enable-mcp-client=false
β”œβ”€β”€ build.gradle
└── src/main/java/[package]/chat/
└── SpringAiChatAdapter.java

# If --agent-enable-kafka=true:
infrastructure/
β”œβ”€β”€ entry-points/
β”‚ └── reactive-web/src/main/java/[package]/kafka/
β”‚ β”œβ”€β”€ consumer/
β”‚ β”‚ β”œβ”€β”€ KafkaConsumer.java
β”‚ β”‚ └── config/
β”‚ β”‚ └── KafkaConfig.java
β”‚ └── producer/
β”‚ β”œβ”€β”€ KafkaProducerAdapter.java
β”‚ └── config/
β”‚ └── KafkaProducerConfig.java

Automatic Configuration​

The command automatically updates application.yaml:

spring:
application:
name: "my-agent"
ai:
openai:
api-key: "${LLM_API_KEY:lm-studio}"
base-url: "${LLM_URL:http://localhost:1234}"
chat:
options:
model: "${LLM_MODEL:local-model}"
temperature: "0.0"
# If --agent-enable-mcp-client=true
mcp:
client:
streamable-http:
connections:
mcp-server-1:
url: "${MCP_SERVER_URL:http://localhost:8080}"
endpoint: "${MCP_SERVER_ENDPOINT:/mcp/stream}"

# If --agent-enable-kafka=true:
adapters:
kafka:
consumer:
topic: "${KAFKA_CONSUMER_TOPIC:ms_test-commands}"
producer:
topic: "${KAFKA_PRODUCER_TOPIC:ms_test-responses}"

agent:
system-prompt: "You are a specialised agent called 'my-agent'. Use available MCP tools. Respond in JSON."

cors:
allowed-origins: "${CORS_ALLOWED_ORIGINS:http://localhost:4200}"