# Agent Integration Patterns

LLMS index: [llms.txt](/llms.txt)

---

This guide covers common patterns for integrating AI agents with Go Micro services, from single-agent workflows to multi-agent architectures.

## Pattern 1: Single Agent with Multiple Services

The simplest and most common pattern. One AI agent has access to multiple microservices as MCP tools.

```
User → AI Agent → MCP Gateway → [Service A, Service B, Service C]
```

### Setup

Run multiple services and expose them all through one MCP gateway:

```go
users := micro.NewService("users", micro.Address(":8081"))
tasks := micro.NewService("tasks", micro.Address(":8082"))
notifications := micro.NewService("notifications", micro.Address(":8083"))

// Run all together as a modular monolith
g := micro.NewGroup(users, tasks, notifications)
g.Run()
```

With `micro run`, all services are discovered automatically via the registry, and the MCP tools endpoint at `/mcp/tools` exposes every endpoint from every service.

### When to Use

- Most applications start here
- Agent needs to orchestrate across services (e.g., "create a task and notify the assignee")
- You want the agent to choose which service to call based on the user's request

## Pattern 2: Scoped Agents

Different agents have access to different subsets of tools via scopes.

```
Customer Agent  → MCP Gateway → [orders:read, support:write]
Internal Agent  → MCP Gateway → [orders:*, users:*, billing:*]
Admin Agent     → MCP Gateway → [*]
```

### Setup

Create tokens with different scopes for each agent:

```go
// Gateway with scope enforcement
mcp.ListenAndServe(":3000", mcp.Options{
    Registry: reg,
    Auth:     authProvider,
    Scopes: map[string][]string{
        "billing.Billing.Charge":    {"billing:admin"},
        "users.Users.Delete":        {"users:admin"},
        "orders.Orders.List":        {"orders:read"},
        "orders.Orders.Create":      {"orders:write"},
        "support.Support.CreateTicket": {"support:write"},
    },
})
```

Then issue different tokens:
- Customer-facing agent token: `scopes=["orders:read", "support:write"]`
- Internal agent token: `scopes=["orders:read", "orders:write", "users:read"]`
- Admin agent token: `scopes=["*"]`

### When to Use

- Different trust levels for different agents
- Customer-facing vs internal agents
- Compliance requirements (e.g., PCI, HIPAA)

## Pattern 3: Agent as Service Consumer

Your Go Micro service itself calls an AI model to process data, using the `ai` package.

```
User → API → Your Service → AI Model (Claude/GPT)
                          → Other Services
```

### Setup

```go
import (
    "go-micro.dev/v6/ai"
    _ "go-micro.dev/v6/ai/anthropic"
)

type SummaryService struct {
    ai    ai.Model
    tasks *TaskClient
}

func NewSummaryService() *SummaryService {
    return &SummaryService{
        ai: ai.New("anthropic",
            ai.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
            ai.WithModel("claude-sonnet-4-20250514"),
        ),
    }
}

// Summarize generates an AI summary of a project's tasks.
// Returns a natural language summary of task status, blockers, and progress.
//
// @example {"project_id": "proj-1"}
func (s *SummaryService) Summarize(ctx context.Context, req *SummarizeRequest, rsp *SummarizeResponse) error {
    // Fetch tasks from another service
    tasks, err := s.tasks.List(ctx, req.ProjectID)
    if err != nil {
        return err
    }

    // Use AI to summarize
    resp, err := s.ai.Generate(ctx, &ai.Request{
        Prompt:       fmt.Sprintf("Summarize these tasks:\n%s", formatTasks(tasks)),
        SystemPrompt: "You are a concise project manager. Summarize task status in 2-3 sentences.",
    })
    if err != nil {
        return err
    }

    rsp.Summary = resp.Reply
    return nil
}
```

### When to Use

- Your service needs to process natural language
- Generating summaries, classifications, or extractions
- Enriching data with AI before returning to the caller

## Pattern 4: Agent with Tool Calling

An AI model calls your services as tools, with automatic tool execution via the ai package.

```
User → Your App → AI Model ←→ MCP Tools (your services)
```

### Setup

```go
import (
    "go-micro.dev/v6/ai"
    _ "go-micro.dev/v6/ai/anthropic"
)

// Define tools from your service endpoints
tools := []ai.Tool{
    {
        Name:        "create_task",
        Description: "Create a new task with title and assignee",
        Properties: map[string]any{
            "title":    map[string]any{"type": "string", "description": "Task title"},
            "assignee": map[string]any{"type": "string", "description": "Username"},
        },
    },
    {
        Name:        "list_tasks",
        Description: "List tasks filtered by status",
        Properties: map[string]any{
            "status": map[string]any{"type": "string", "description": "Filter: todo, in_progress, done"},
        },
    },
}

// Handle tool calls by routing to your services. The handler mirrors a
// go-micro RPC handler: context first, the call in, a result out.
toolHandler := func(ctx context.Context, call ai.ToolCall) ai.ToolResult {
    switch call.Name {
    case "create_task":
        var rsp CreateResponse
        err := client.Call(ctx, "tasks", "TaskService.Create", call.Input, &rsp)
        if err != nil {
            return ai.ToolResult{ID: call.ID, Content: fmt.Sprintf(`{"error": "%s"}`, err)}
        }
        b, _ := json.Marshal(rsp)
        return ai.ToolResult{ID: call.ID, Value: rsp, Content: string(b)}
    case "list_tasks":
        var rsp ListResponse
        err := client.Call(ctx, "tasks", "TaskService.List", call.Input, &rsp)
        if err != nil {
            return ai.ToolResult{ID: call.ID, Content: fmt.Sprintf(`{"error": "%s"}`, err)}
        }
        b, _ := json.Marshal(rsp)
        return ai.ToolResult{ID: call.ID, Value: rsp, Content: string(b)}
    }
    return ai.ToolResult{ID: call.ID, Content: `{"error": "unknown tool"}`}
}

m := ai.New("anthropic",
    ai.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
    ai.WithToolHandler(toolHandler),
)

// The model will automatically call tools and return the final answer
resp, err := m.Generate(ctx, &ai.Request{
    Prompt:       "Create a task for Alice to review the PR and tell me what tasks she has",
    SystemPrompt: "You are a helpful project management assistant",
    Tools:        tools,
})

fmt.Println(resp.Answer)
// "I've created a task for Alice to review the PR. She now has 3 tasks: ..."
```

### When to Use

- Building a chatbot or assistant that manages your services
- The agent playground in `micro run` uses this pattern
- You want the AI to decide which tools to call and in what order

## Pattern 5: Event-Driven Agent Triggers

Services emit events that trigger agent actions via the broker.

```
Service → Broker Event → Agent Handler → AI Model → Action
```

### Setup

```go
// Publisher: emit events from your service
broker.Publish("tasks.created", &broker.Message{
    Body: taskJSON,
})

// Subscriber: agent handler reacts to events
broker.Subscribe("tasks.created", func(p broker.Event) error {
    var task Task
    json.Unmarshal(p.Message().Body, &task)

    // Use AI to auto-assign based on task content
    resp, err := aiModel.Generate(ctx, &ai.Request{
        Prompt: fmt.Sprintf("Who should handle this task? Title: %s, Description: %s. Team: alice (frontend), bob (backend), charlie (devops)", task.Title, task.Description),
        SystemPrompt: "Reply with just the username of the best person to handle this task.",
    })

    // Auto-assign
    client.Call(ctx, "tasks", "TaskService.Update", map[string]any{
        "id": task.ID,
        "assignee": strings.TrimSpace(resp.Reply),
    }, nil)

    return nil
})
```

### When to Use

- Automated workflows triggered by service events
- AI-powered routing, classification, or triage
- Background processing without user interaction

## Pattern 6: Claude Code Integration

Developers use Claude Code with your services as MCP tools for local development workflows.

```
Developer → Claude Code → stdio MCP → [local services]
```

### Setup

```bash
# Start services locally
micro run

# In another terminal, use Claude Code with your services
# Claude Code config (~/.claude/claude_desktop_config.json):
```

```json
{
  "mcpServers": {
    "my-project": {
      "command": "micro",
      "args": ["mcp", "serve"]
    }
  }
}
```

Now in Claude Code:

```
"List all tasks that are blocked"
"Create a user account for the new hire"
"Check the health of all services"
```

### When to Use

- Developer productivity workflows
- Managing services during development
- Testing and debugging with natural language

## Pattern 7: LangChain / LlamaIndex Integration

Use the official Python SDKs to connect agent frameworks directly to your services.

### LangChain

```python
from langchain_go_micro import GoMicroToolkit

# Connect to MCP gateway
toolkit = GoMicroToolkit(
    base_url="http://localhost:3000",
    token="Bearer <token>",
)

# Get LangChain tools automatically
tools = toolkit.get_tools()

# Use with any LangChain agent
from langchain.agents import AgentExecutor, create_tool_calling_agent
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools)
executor.invoke({"input": "Create a task for Alice"})
```

### LlamaIndex

```python
from go_micro_llamaindex import GoMicroToolkit

toolkit = GoMicroToolkit(
    base_url="http://localhost:3000",
    token="Bearer <token>",
)

# Use as LlamaIndex tools
tools = toolkit.to_tool_list()

# Use with a LlamaIndex agent
from llama_index.core.agent import ReActAgent
agent = ReActAgent.from_tools(tools, llm=llm)
agent.chat("What tasks are assigned to Bob?")
```

### When to Use

- Python-based agent pipelines
- RAG (Retrieval-Augmented Generation) workflows with LlamaIndex
- Multi-step LangChain chains that orchestrate your services
- Teams that prefer Python for AI/ML work

## Pattern 8: Standalone Gateway for Production

Run the MCP gateway as a separate, horizontally scalable process.

```
                    ┌──────────────────┐
Claude/GPT/Agent ──→│ micro-mcp-gateway │──→ Service A (consul)
                    │   (standalone)    │──→ Service B (consul)
                    └──────────────────┘──→ Service C (consul)
```

### Setup

```bash
micro-mcp-gateway \
  --registry consul \
  --registry-address consul:8500 \
  --address :3000 \
  --auth jwt \
  --rate-limit 10 \
  --rate-burst 20 \
  --audit
```

Or via Docker:

```bash
docker run -p 3000:3000 ghcr.io/micro/micro-mcp-gateway \
  --registry consul \
  --registry-address consul:8500
```

### When to Use

- Production deployments where you want the gateway to scale independently
- Multiple teams deploying services but sharing one MCP endpoint
- Enterprise environments needing centralized auth and audit

## Pattern 9: Planning and Delegation

Built into the `Agent` abstraction. Every agent gets two harness tools — `plan` and `delegate` — with no extra setup. They are plain tools, not a separate graph runtime.

```
Conductor ──plan──→ (records ordered steps in memory)
            ──delegate──→ registered agent (RPC)  or  ephemeral sub-agent
```

### Setup

Nothing to wire — the tools are added to every agent automatically. Guide their use with the prompt:

```go
conductor := micro.NewAgent("conductor",
    micro.AgentServices("task"),
    micro.AgentPrompt(
        "For multi-step requests, call the plan tool first to record your steps. "+
            "For notifications, delegate to the \"comms\" agent (to: \"comms\")."),
    micro.AgentProvider("anthropic"),
)
```

- **`plan`** records an ordered list of steps (`task` + `status`) in the agent's store-backed memory, surfaced back on later turns so it stays oriented.
- **`delegate`** hands a self-contained subtask to another agent. **Delegate-first**: if the target is a registered agent it's reached over RPC; otherwise a focused, short-lived sub-agent is created with a fresh, isolated context. A sub-agent is just an agent — created with `New`, talked to with `Ask`; there's no separate "spawn"/"fork" concept.

Full example: [examples/agent-plan-delegate](https://github.com/micro/go-micro/tree/master/examples/agent-plan-delegate).

### When to Use

- Multi-step tasks where an explicit plan keeps the agent on track
- Multi-agent systems where domain experts own their own services and you want hand-offs to stay distributed (not one agent doing everything)

## Choosing a Pattern

| Pattern | Complexity | Best For |
|---------|-----------|----------|
| Single Agent | Low | Most applications, getting started |
| Scoped Agents | Medium | Multi-tenant, compliance |
| Agent as Consumer | Medium | AI-enhanced services |
| Tool Calling | Medium | Chatbots, assistants |
| Event-Driven | High | Automation, background processing |
| Claude Code | Low | Developer workflows |
| LangChain/LlamaIndex | Medium | Python agent pipelines, RAG |
| Standalone Gateway | Medium | Production, enterprise |
| Planning & Delegation | Medium | Multi-step tasks, distributed multi-agent systems |

Start with **Pattern 1** (single agent) and add complexity as needed. Most applications don't need multi-agent architectures.

## Anti-Patterns

### Don't: Chain Agents Without Coordination

```
Agent A → Agent B → Agent C  (no shared state, no trace IDs)
```

Instead, use a single agent with multiple tools, or share trace IDs via metadata.

### Don't: Give Agents Unrestricted Access

```
Customer Agent → scopes=["*"]  (dangerous!)
```

Always use the minimum required scopes. See the [MCP Security Guide](mcp-security.md).

### Don't: Skip Error Documentation

If agents don't know what errors are possible, they can't handle them gracefully. Always document error cases in your handler comments.

### Don't: Build Agent Logic into Services

Keep services as pure business logic. Let the agent harness handle orchestration, retries, and decision-making. Your service should just do one thing well.

## Next Steps

- [Building AI-Native Services](ai-native-services.md) - End-to-end tutorial
- [MCP Security Guide](mcp-security.md) - Auth and scopes
- [Tool Description Best Practices](tool-descriptions.md) - Better docs for agents
- [AI Package](../../ai/README.md) - AI provider interface
