Elastic.Clients.AgentBuilder 0.48.0

Prefix Reserved
dotnet add package Elastic.Clients.AgentBuilder --version 0.48.0
                    
NuGet\Install-Package Elastic.Clients.AgentBuilder -Version 0.48.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Elastic.Clients.AgentBuilder" Version="0.48.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Elastic.Clients.AgentBuilder" Version="0.48.0" />
                    
Directory.Packages.props
<PackageReference Include="Elastic.Clients.AgentBuilder" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Elastic.Clients.AgentBuilder --version 0.48.0
                    
#r "nuget: Elastic.Clients.AgentBuilder, 0.48.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Elastic.Clients.AgentBuilder@0.48.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Elastic.Clients.AgentBuilder&version=0.48.0
                    
Install as a Cake Addin
#tool nuget:?package=Elastic.Clients.AgentBuilder&version=0.48.0
                    
Install as a Cake Tool

Elastic.Clients.AgentBuilder

A .NET client for the Elastic Agent Builder Kibana API. Create and manage custom AI tools, agents, and conversations in Kibana — and connect to the Kibana MCP server for use with Microsoft.Extensions.AI.

Why?

Elastic Agent Builder lets you build AI agents that use Elasticsearch data. This library gives you a strongly-typed C# API to:

  • Define tools and agents in code and deploy them idempotently via hash-based bootstrapping — just like infrastructure-as-code.
  • CRUD all four custom tool types: ES|QL queries, index search, MCP, and workflow.
  • Execute tools and consume tabular results with ergonomic column-name access.
  • Drive conversations with agents programmatically.
  • Connect to the Kibana MCP server so agent tools are immediately usable as AIFunction instances with any IChatClient.

The library targets netstandard2.0, netstandard2.1, net8.0, and net10.0 with full AOT compatibility via System.Text.Json source generators.

Getting Started

AgentTransportConfiguration handles all Kibana-specific wiring automatically (the kbn-xsrf header, Cloud ID → Kibana URL resolution, and space prefixes).

From an Elastic Cloud ID

using Elastic.Transport;
using Elastic.Clients.AgentBuilder;

var config = new AgentTransportConfiguration("my-cloud-id", new ApiKey("base64key"));
var client = new AgentBuilderClient(config);

From a direct Kibana URL

var config = new AgentTransportConfiguration(
    new Uri("https://my-kibana:5601"), new ApiKey("base64key"));
var client = new AgentBuilderClient(config);

Basic authentication

var config = new AgentTransportConfiguration(
    "my-cloud-id", new BasicAuthentication("user", "password"));
var client = new AgentBuilderClient(config);

Kibana Spaces

Set the Space property to scope all API calls to a specific Kibana space. All requests will be prefixed with /s/{Space}/api/agent_builder/...:

var config = new AgentTransportConfiguration("my-cloud-id", new ApiKey("base64key"))
{
    Space = "my-space"
};
var client = new AgentBuilderClient(config);

Using AgentTransport directly

If you need an ITransport instance (for example, to share with Elastic.Extensions.AI or custom code), create an AgentTransport:

var config = new AgentTransportConfiguration("my-cloud-id", new ApiKey("base64key"))
{
    Space = "analytics"
};
var transport = new AgentTransport(config);

// Pass to the client
var client = new AgentBuilderClient(transport);

// Or use the transport directly — kbn-xsrf is already wired

Advanced: raw ITransport

For full control you can pass any ITransport directly. You are responsible for setting the kbn-xsrf header yourself:

var transport = new DistributedTransport(
    new TransportConfigurationDescriptor(new SingleNodePool(new Uri("https://my-kibana:5601")))
        .Authentication(new ApiKey("base64key"))
        .GlobalHeaders(new NameValueCollection { { "kbn-xsrf", "true" } }));

var client = new AgentBuilderClient(transport, space: "my-space");

Creating Tools

ES|QL Tool

Define a parameterized ES|QL query that agents can invoke:

using Elastic.Clients.AgentBuilder.Tools;

var tool = await client.CreateToolAsync(new CreateEsqlToolRequest
{
    Id = "top-books-by-pages",
    Description = "Find the books with the most pages",
    Tags = ["analytics", "books"],
    Configuration = new EsqlToolConfiguration
    {
        Query = "FROM books | SORT page_count DESC | LIMIT ?limit",
        Params = new Dictionary<string, EsqlToolParam>
        {
            ["limit"] = new()
            {
                Type = "integer",
                Description = "Maximum number of results to return",
                DefaultValue = 10
            }
        }
    }
});

Index Search Tool

Scope an agent's search to specific index patterns:

var searchTool = await client.CreateToolAsync(new CreateIndexSearchToolRequest
{
    Id = "search-application-logs",
    Description = "Search application logs for errors and patterns",
    Tags = ["observability"],
    Configuration = new IndexSearchToolConfiguration
    {
        IndexPattern = "logs-myapp-*",
        RowLimit = 100,
        CustomInstructions = "Always include @timestamp and log.level in results"
    }
});

MCP Tool

Connect to an external MCP server through Kibana:

var mcpTool = await client.CreateToolAsync(new CreateMcpToolRequest
{
    Id = "github-issues",
    Description = "Search GitHub issues via MCP",
    Configuration = new McpToolConfiguration
    {
        ConnectorId = "my-mcp-connector",
        ToolName = "search_issues"
    }
});

Workflow Tool

Trigger an Elastic Workflow:

var workflowTool = await client.CreateToolAsync(new CreateWorkflowToolRequest
{
    Id = "run-remediation",
    Description = "Run the incident remediation workflow",
    Configuration = new WorkflowToolConfiguration
    {
        WorkflowId = "incident-remediation-v2"
    }
});

Managing Tools

// List all tools (built-in and custom)
var all = await client.ListToolsAsync();
foreach (var t in all.Results)
    Console.WriteLine($"{t.Id} ({t.Type}) — {t.Description}");

// Get a specific tool and inspect its typed configuration
var tool = await client.GetToolAsync("top-books-by-pages");
var esqlConfig = tool.AsEsql();
Console.WriteLine($"Query: {esqlConfig?.Query}");

// Update
await client.UpdateToolAsync("top-books-by-pages", new UpdateEsqlToolRequest
{
    Description = "Find the longest books in the catalogue",
    Configuration = new EsqlToolConfiguration
    {
        Query = "FROM books | SORT page_count DESC | LIMIT ?limit",
        Params = new Dictionary<string, EsqlToolParam>
        {
            ["limit"] = new() { Type = "integer", Description = "Max results" }
        }
    }
});

// Delete
await client.DeleteToolAsync("top-books-by-pages");

Executing Tools

Execute a tool and consume the tabular results:

var result = await client.ExecuteToolAsync(new ExecuteToolRequest
{
    ToolId = "top-books-by-pages",
    ToolParams = new() { ["limit"] = JsonSerializer.SerializeToElement(5) }
});

foreach (var item in result.Results)
{
    if (item.AsTabularData() is { } tabular)
    {
        Console.WriteLine($"Source: {tabular.Source}, Columns: {tabular.Columns.Count}");
        for (var i = 0; i < tabular.Values.Count; i++)
        {
            var row = tabular.Row(i);
            Console.WriteLine($"  {row.GetString("title")} — {row.GetInt32("page_count")} pages");
        }
    }

    if (item.AsQuery() is { } query)
        Console.WriteLine($"Generated ES|QL: {query.Esql}");
}

Creating Agents

using Elastic.Clients.AgentBuilder.Agents;

var agent = await client.CreateAgentAsync(new CreateAgentRequest
{
    Id = "books-research-agent",
    Name = "Books Research Assistant",
    Description = "Helps users explore and analyse the book catalogue",
    AvatarColor = "#BFDBFF",
    AvatarSymbol = "📚",
    Labels = ["books", "research"],
    Configuration = new AgentConfiguration
    {
        Instructions = """
            You are a helpful assistant that answers questions about our book catalogue.
            Use the top-books-by-pages tool when users ask about long or popular books.
            Use the search tool for general queries.
            Always cite your sources.
            """,
        Tools =
        [
            new AgentToolGroup
            {
                ToolIds = ["top-books-by-pages", "search-application-logs", "platform.core.search"]
            }
        ]
    }
});

Conversations

Drive a conversation with an agent:

using Elastic.Clients.AgentBuilder.Conversations;

// Start a new conversation
var response = await client.ConverseAsync(new ConverseRequest
{
    Input = "What are the three longest books in our collection?",
    AgentId = "books-research-agent"
});

Console.WriteLine(response.Response?.Message);
Console.WriteLine($"Tokens: {response.ModelUsage?.InputTokens} in / {response.ModelUsage?.OutputTokens} out");

// Continue the conversation
var followUp = await client.ConverseAsync(new ConverseRequest
{
    Input = "Who wrote them?",
    AgentId = "books-research-agent",
    ConversationId = response.ConversationId
});

// List and manage conversations
var conversations = await client.ListConversationsAsync();
await client.DeleteConversationAsync(response.ConversationId);

Bootstrapping — Infrastructure as Code

The bootstrapper computes a SHA-256 hash of each definition and stores it in the resource's tags (tools) or labels (agents). On subsequent runs, a resource is only updated when its hash has changed — making deployments fast and idempotent.

var bootstrapper = new AgentBuilderBootstrapper(client);

var definition = new BootstrapDefinition
{
    EsqlTools =
    [
        new CreateEsqlToolRequest
        {
            Id = "top-books-by-pages",
            Description = "Find books with the most pages",
            Configuration = new EsqlToolConfiguration
            {
                Query = "FROM books | SORT page_count DESC | LIMIT ?limit",
                Params = new Dictionary<string, EsqlToolParam>
                {
                    ["limit"] = new() { Type = "integer", Description = "Max results" }
                }
            }
        }
    ],
    IndexSearchTools =
    [
        new CreateIndexSearchToolRequest
        {
            Id = "search-logs",
            Description = "Search application logs",
            Configuration = new IndexSearchToolConfiguration { IndexPattern = "logs-*" }
        }
    ],
    Agents =
    [
        new CreateAgentRequest
        {
            Id = "ops-agent",
            Name = "Operations Agent",
            Configuration = new AgentConfiguration
            {
                Instructions = "You help the operations team investigate issues.",
                Tools = [new AgentToolGroup { ToolIds = ["search-logs", "platform.core.search"] }]
            }
        }
    ]
};

// BootstrapMethod.Failure throws on errors; .Silent swallows them; .None skips entirely
await bootstrapper.BootstrapAsync(BootstrapMethod.Failure, definition);

// Safe to call on every application startup — unchanged resources are skipped

Using with Elastic.Esql — LINQ-generated queries

Elastic.Esql lets you write LINQ and get ES|QL query strings with full IntelliSense and compile-time checking. You can feed the generated queries straight into Agent Builder tool definitions.

Inline queries

using Elastic.Esql.Core;
using Elastic.Clients.AgentBuilder.Tools;

var query = new EsqlQueryable<Book>()
    .Where(b => b.PageCount > 200)
    .OrderByDescending(b => b.PageCount)
    .Take(50)
    .ToString();
// "FROM books | WHERE page_count > 200 | SORT page_count DESC | LIMIT 50"

var tool = await client.CreateToolAsync(new CreateEsqlToolRequest
{
    Id = "long-books",
    Description = "Find books with more than 200 pages",
    Configuration = new EsqlToolConfiguration { Query = query }
});

Parameterized queries

Elastic.Esql natively captures C# variables and turns them into named parameters when you call ToEsqlString(inlineParameters: false). Use this to define the query shape in LINQ while exposing parameters the agent supplies at runtime:

var minPages = 100;
var limit = 25;

var queryable = new EsqlQueryable<Book>()
    .Where(b => b.PageCount > minPages)
    .OrderByDescending(b => b.PageCount)
    .Take(limit);

var esql = queryable.ToEsqlString(inlineParameters: false);
// "FROM books | WHERE page_count > ?minPages | SORT page_count DESC | LIMIT ?limit"

await client.CreateToolAsync(new CreateEsqlToolRequest
{
    Id = "top-books",
    Description = "Find books above a page threshold",
    Configuration = new EsqlToolConfiguration
    {
        Query = esql,
        Params = new Dictionary<string, EsqlToolParam>
        {
            ["minPages"] = new()
            {
                Type = "integer",
                Description = "Minimum number of pages",
                DefaultValue = 100
            },
            ["limit"] = new()
            {
                Type = "integer",
                Description = "Maximum number of results to return",
                DefaultValue = 25
            }
        }
    }
});

This gives you compile-time field name resolution and IntelliSense for the query logic, while the agent supplies dynamic parameter values at runtime.

Microsoft.Extensions.AI & MCP

For IChatClient integration, MCP tool discovery, and DI extensions see the companion package Elastic.Extensions.AI.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Elastic.Clients.AgentBuilder:

Package Downloads
Elastic.Extensions.AI

Microsoft.Extensions.AI integration for Elastic Agent Builder — IChatClient, MCP tools, and DI extensions

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.48.0 44 6/3/2026
0.47.0 46 6/3/2026
0.46.0 87 6/2/2026
0.45.0 148 5/12/2026
0.44.1 140 5/12/2026
0.44.0 135 5/11/2026
0.43.0 137 4/20/2026
0.42.0 141 4/20/2026
0.41.2 143 4/15/2026
0.41.1 141 4/15/2026
0.41.0 159 3/31/2026