# How Embabel‑Agent Integrates with External Tools and Platforms: A Complete Integration Guide

> Learn how Embabel-agent integrates with external tools and platforms using LLM provider abstractions, MCP, and A2A protocols for seamless interoperability. Explore our complete integration guide.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-14

---

**Embabel-agent integrates with external tools and platforms through three core layers: LLM provider abstractions via Spring‑AI, MCP (Model Context Protocol) clients and servers for tool interoperability, and A2A protocol support for agent federation, all wired together with Spring Boot auto‑configuration.**

The [Embabel Agent Platform](https://github.com/embabel/embabel-agent) is a Spring‑aware, JVM‑native framework designed to connect language models, external tools, and observability systems through a unified architecture. This article examines how embabel-agent achieves deep integration with LLM providers, MCP‑based tools, and monitoring platforms using concrete source code references and working configuration examples.

---

## LLM Provider Integration via Spring‑AI

Embabel-agent does not implement LLM clients directly. Instead, it relies on Spring‑AI's `ChatModel` abstraction, auto‑configuring provider‑specific beans through dedicated starter modules.

### Supported Provider Starters

| Provider | Starter Artifact | Configuration Class |
|----------|-----------------|---------------------|
| OpenAI | `embabel-agent-starter-openai` | [[`OpenAiAutoConfiguration.java`](https://github.com/embabel/embabel-agent/blob/main/OpenAiAutoConfiguration.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/models/embabel-agent-openai-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/models/openai/OpenAiAutoConfiguration.java) |
| Anthropic | `embabel-agent-starter-anthropic` | `LLMAnthropicStreamingBuilderIT` (test reference) |
| Ollama | `emabel-agent-starter-ollama` | Production auto‑configuration shipped with starter |
| OCI Generative AI | `embabel-agent-starter-oci` | Oracle Cloud Infrastructure integration |
| Gemini | `embabel-agent-starter-gemini` | Google AI integration |
| MiniMax, Mistral‑AI | Dedicated starters | Provider‑specific model enums |

Each starter creates a `ChatModel` bean that the [`AgentPlatform`](https://github.com/embabel/embabel-agent) injects into action execution contexts. Runtime model selection occurs through the `Ai` fluent API:

```java
import com.embabel.agent.core.model.models.OpenAiModels;
import static com.embabel.agent.core.model.models.OpenAiModels.GPT_4;

// OpenAI provider
return ai.withLlm(GPT_4)
         .createObject(prompt, Result.class);

// Anthropic provider  
return ai.withLlm(LlmAnthropicModels.CLAUDE)
         .createObject(prompt, Result.class);

```

The provider layer is completely **interchangeable**—no code changes are required beyond the `withLlm()` call.

---

## MCP (Model Context Protocol) Tool Integration

MCP is the standardized protocol for exposing external capabilities to LLMs. Embabel-agent implements both **client** (consuming tools) and **server** (exposing tools) roles.

### MCP Client: Consuming External Tools

The [`QuiteMcpClientAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/QuiteMcpClientAutoConfiguration.java) creates resilient MCP clients that survive individual server failures. Unlike Spring‑AI's default implementation, this configuration tolerates startup errors and logs them without crashing the application.

Configure MCP clients in [`application.yml`](https://github.com/embabel/embabel-agent/blob/main/application.yml):

```yaml
spring:
  ai:
    mcp:
      client:
        enabled: true
        name: embabel
        version: 1.0.0
        type: SYNC  # or ASYNC for non‑blocking operations

        stdio:
          connections:
            brave-search:
              command: docker
              args: [run, -i, --rm, brave/search:latest]
            wikipedia:
              command: docker
              args: [run, -i, --rm, wikipedia/mcp:latest]
            postgres:
              command: docker
              args: [run, -i, --rm, postgres/mcp:latest]

```

The **resilience design** is critical: if the `brave-search` container fails to start, the platform continues with `wikipedia` and `postgres` available. This behavior is implemented through custom exception handling in `QuiteMcpClientAutoConfiguration` that wraps standard Spring‑AI MCP client creation with fallback logic.

### Enabling MCP Servers via @EnableAgents

The [`@EnableAgents`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/config/annotation/EnableAgents.java) annotation declares which MCP servers activate for a given agent configuration:

```java
import com.embabel.agent.config.annotation.EnableAgents;

@Configuration
@EnableAgents(mcpServers = { "brave-search", "wikipedia", "postgres" })
public class TravelAgentConfiguration {
    // Additional beans...
}

```

During context initialization, the platform:

1. Scans for `@EnableAgents` annotations
2. Creates `McpServer` beans for each named server
3. Registers them with the planning engine for goal‑selection

### MCP Server: Exposing Tools to Other Agents

The [`AgentMcpServerAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-mcpserver-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/mcpserver/AgentMcpServerAutoConfiguration.java) module publishes an SSE endpoint at `/sse` that Claude Desktop, Copilot, or other MCP‑aware clients can consume.

Configuration properties control server behavior:

```yaml
embabel:
  agent:
    mcp:
      server:
        enabled: true
        execution-mode: SYNC  # or ASYNC

        transport: sse        # Server‑Sent Events transport

```

When enabled, any `@Action` method with explicit tool descriptions becomes available through the MCP protocol to external consumers.

---

## A2A Protocol: Agent‑to‑Agent Federation

Embabel-agent supports the [A2A protocol](https://github.com/google-a2a/A2A) for cross‑platform agent communication. Activating the `a2a` Spring profile starts an HTTP endpoint that accepts and responds to A2A messages:

```bash

# Start with A2A profile enabled

java -jar my-agent.jar --spring.profiles.active=a2a

```

The server binds to `/a2a` by default (e.g., `http://localhost:8080/a2a`), enabling:

- **Remote task discovery**: Other A2A agents query capability advertisements
- **Secure delegation**: Tasks execute with authenticated context propagation
- **Status streaming**: Long‑running operations report progress via SSE

This integration allows embabel-agent instances to participate in heterogeneous agent ecosystems without protocol translation.

---

## Observability Integration: Micrometer and OpenTelemetry

The `embabel-agent-observability` module auto‑configures tracing and metrics through [`EmbabelSpanEventListener`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/tracing/EmbabelSpanEventListener.java) and `EmbabelMetricsEventListener`.

### Automatic Span Generation

Every action execution, LLM call, and tool invocation becomes a child span:

```

Agent: TravelPlannerAgent
├─ Action: FindHotels
│  ├─ @Tracked: enrichCustomer (PROCESSING)
│  │  └─ Tool: brave-search (300ms)
│  ├─ ChatModel: gpt-4 (Spring AI) (1.2s)
│  └─ Tool: postgres/query-hotels (45ms)
└─ status: completed (traceId: abc123...)

```

### Custom Tracking with @Tracked

The [`@Tracked`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/annotation/Tracked.java) annotation adds business‑context spans:

```java
import com.embabel.agent.observability.annotation.Tracked;
import com.embabel.agent.observability.annotation.TrackType;

@Service
public class CustomerEnrichmentService {

    @Tracked(
        value = "enrichCustomer",
        type = TrackType.PROCESSING,
        description = "Enriches a Customer record with external data sources"
    )
    public Customer enrich(Customer input, Map<String, Object> externalData) {
        // Implementation...
        return enrichedCustomer;
    }
}

```

Supported `TrackType` values include `PROCESSING`, `VALIDATION`, `EXTERNAL_CALL`, and `AGGREGATION`.

Exporter configuration follows standard Spring Boot properties:

```yaml
management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans
  metrics:
    export:
      otlp:
        endpoint: http://localhost:4318/v1/metrics

```

Langfuse, Datadog, and custom OTel collectors are supported through Micrometer registries.

---

## Platform Resilience: Auto‑Configuration Filtering

The [`AgentPlatformAutoConfigurationFilter`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/AgentPlatformAutoConfigurationFilter.java) prevents Spring‑AI's default MCP client auto‑configuration from activating when embabel-agent's resilient client is present. This avoids double‑bean registration and ensures the platform uses failure‑tolerant client implementations.

The filter implements `AutoConfigurationImportFilter` and excludes:

- `McpClientAutoConfiguration` (Spring‑AI default)
- `ToolCallbackAutoConfiguration` where conflicting

---

## Complete Integration Example

The following configuration demonstrates a production‑ready embabel-agent setup with multiple LLM providers, MCP tools, A2A federation, and observability:

```java
package com.example.travel;

import com.embabel.agent.config.annotation.EnableAgents;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAgents(
    mcpServers = { "brave-search", "postgres", "wikipedia" },
    profiles = { "a2a" }
)
public class TravelAgentPlatformConfiguration {
}

```

```yaml

# application.yml

spring:
  ai:
    mcp:
      client:
        enabled: true
        name: travel-platform
        version: 2.1.0
        type: ASYNC
        request-timeout: 30s
        stdio:
          connections:
            brave-search:
              command: docker
              args: [run, -i, --rm, -e, BRAVE_API_KEY=${BRAVE_KEY}, brave/search:latest]
            postgres:
              command: docker
              args: [run, -i, --rm, -e, DATABASE_URL=${DB_URL}, postgres/mcp:latest]

embabel:
  agent:
    mcp:
      server:
        enabled: true
        execution-mode: ASYNC

management:
  tracing:
    enabled: true
    sampling:
      probability: 0.1
  endpoints:
    web:
      exposure:
        include: health, metrics, prometheus

```

```java
// Action using tool groups
@Agent(description = "Intelligent travel planning assistant")
public class TravelPlanner {

    @Action(
        description = "Find and rank hotels based on user preferences",
        toolGroups = { CoreToolGroups.WEB, CoreToolGroups.DATABASE }
    )
    public HotelRecommendations findHotels(
            UserPreferences preferences,
            TravelDates dates,
            Ai ai) {
        
        String prompt = buildHotelPrompt(preferences, dates);
        
        return ai.withLlm(selectModelForComplexity(preferences))
                 .toolGroup(CoreToolGroups.WEB)      // Requires brave-search
                 .toolGroup(CoreToolGroups.DATABASE) // Requires postgres
                 .createObject(prompt, HotelRecommendations.class);
    }
    
    private LlmModel selectModelForComplexity(UserPreferences prefs) {
        return prefs.requiresReasoning() 
            ? OpenAiModels.GPT_4 
            : OpenAiModels.GPT_4_MINI;
    }
}

```

---

## Key Source Files Reference

| Integration Layer | Source File | Purpose |
|-------------------|-------------|---------|
| Platform bootstrap | [[`EnableAgents.java`](https://github.com/embabel/embabel-agent/blob/main/EnableAgents.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/config/annotation/EnableAgents.java) | Declares MCP servers and activation profiles |
| MCP client resilience | [[`QuiteMcpClientAutoConfiguration.java`](https://github.com/embabel/embabel-agent/blob/main/QuiteMcpClientAutoConfiguration.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/QuiteMcpClientAutoConfiguration.java) | Fault‑tolerant client creation |
| MCP server exposure | [[`AgentMcpServerAutoConfiguration.java`](https://github.com/embabel/embabel-agent/blob/main/AgentMcpServerAutoConfiguration.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-mcpserver-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/mcpserver/AgentMcpServerAutoConfiguration.java) | SSE endpoint for external tool consumers |
| Auto‑config filtering | [[`AgentPlatformAutoConfigurationFilter.java`](https://github.com/embabel/embabel-agent/blob/main/AgentPlatformAutoConfigurationFilter.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/AgentPlatformAutoConfigurationFilter.java) | Prevents Spring‑AI default bean conflicts |
| OpenAI provider | [[`OpenAiAutoConfiguration.java`](https://github.com/embabel/embabel-agent/blob/main/OpenAiAutoConfiguration.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/models/embabel-agent-openai-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/models/openai/OpenAiAutoConfiguration.java) | Example LLM provider wiring |
| Distributed tracing | [[`EmbabelSpanEventListener.java`](https://github.com/embabel/embabel-agent/blob/main/EmbabelSpanEventListener.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/tracing/EmbabelSpanEventListener.java) | Span creation and context propagation |
| Custom metrics | [[`EmbabelMetricsEventListener.java`](https://github.com/embabel/embabel-agent/blob/main/EmbabelMetricsEventListener.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/metrics/EmbabelMetricsEventListener.java) | Micrometer metric registration |
| Business context tracking | [[`Tracked.java`](https://github.com/embabel/embabel-agent/blob/main/Tracked.java)](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/annotation/Tracked.java) | Annotation for method‑level spans |

---

## Summary

- **LLM integration** occurs through Spring‑AI `ChatModel` beans with provider‑specific starters for OpenAI, Anthropic, Ollama, and others
- **MCP client integration** uses [`QuiteMcpClientAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/QuiteMcpClientAutoConfiguration.java) for resilient, failure‑tolerant tool consumption
- **MCP server integration** exposes agent capabilities via SSE endpoints configured in [`AgentMcpServerAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-mcpserver-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/mcpserver/AgentMcpServerAutoConfiguration.java)
- **Tool activation** is declarative through [`@EnableAgents`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/config/annotation/EnableAgents.java) and runtime `toolGroups` in action definitions
- **A2A federation** enables cross‑platform agent communication with profile‑based activation
- **Observability** integrates Micrometer and OpenTelemetry through automatic span generation and [`@Tracked`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/annotation/Tracked.java) annotations
- **Platform stability** is guaranteed by [`AgentPlatformAutoConfigurationFilter`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/AgentPlatformAutoConfigurationFilter.java) preventing conflicting auto‑configurations

---

## Frequently Asked Questions

### How do I add a custom MCP server to embabel-agent?

Create a Docker container or native binary that implements the MCP JSON‑RPC protocol over stdio, then register it in [`application.yml`](https://github.com/embabel/embabel-agent/blob/main/application.yml) under `spring.ai.mcp.client.stdio.connections`. The [`QuiteMcpClientAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/QuiteMcpClientAutoConfiguration.java) will automatically create a client and inject it into the `AgentPlatform`. No Java code changes are required—only YAML configuration and container availability.

### What happens if an MCP server fails to start?

The platform continues operating with reduced functionality. Unlike Spring‑AI's default implementation, embabel-agent's resilient client catches startup exceptions, logs them at `WARN` level, and excludes the failed server from the tool registry. Other configured MCP servers remain available. This behavior is implemented in [`QuiteMcpClientAutoConfiguration`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-autoconfigure/embabel-agent-platform-autoconfigure/src/main/java/com/embabel/agent/autoconfigure/platform/QuiteMcpClientAutoConfiguration.java).

### Can I use multiple LLM providers in the same application?

Yes. Add multiple provider starters to your classpath, then select the provider at call time using `ai.withLlm(ModelEnum.SPECIFIC_MODEL)`. The `Ai` interface maintains separate client instances per provider, allowing mixed usage within the same agent or even the same action sequence when combined with conditional logic.

### How do I integrate with Langfuse or a custom tracing backend?

Configure standard Spring Boot management properties for OTLP or Zipkin export. The [`EmbabelSpanEventListener`](https://github.com/embabel/embabel-agent/blob/main/embabel-agent-observability/src/main/java/com/embabel/agent/observability/tracing/EmbabelSpanEventListener.java) emits all agent, action, and tool spans with consistent trace IDs. For Langfuse specifically, use the OpenTelemetry intake endpoint: `https://cloud.langfuse.com/api/public/otel` as your `management.otlp.tracing.endpoint`.