Apricot Framework

Agentic

Declare an AI tool once, beside the code that runs it, and surface it to any agent surface.

A tool an AI agent can call is two things at once: an operation, and a prompt. The operation belongs beside the code that implements it. The prompt — the name, the description a model selects on, the shape it fills in — belongs there too, because a declaration kept anywhere else drifts from the thing it describes.

What does not belong there is how the tool is reached, or what a caller must hold to reach it. Those are the host's, and this library is built so it never has to learn either.

A tool is an AIFunction

Not something adapted into one. AgentTool derives from Microsoft.Extensions.AI.AIFunction, which is the currency the whole .NET AI ecosystem already speaks — so the same declaration reaches every surface with nothing in between:

SurfaceWhat it takes
An in-process agent loopChatOptions.Tools.AddRange(await executor.GetAvailableFunctionsAsync())
An MCP serverMcpServerTool.Create(function, options)
A tool read off an upstream MCP servernothing — McpClientTool is already an AIFunction
Another service, over gRPCa declaration off the wire and a client to call back with

That last row is the point of the exercise. Tools arrive from four directions and leave through four, and a registry holds them all without knowing which is which.

Packages

Nothing implies anything else. A library that only declares tools takes the first; a console application federating MCP servers takes the second and fourth, and no web framework comes with them.

PackageWhat it is
ApricotFramework.Agentic.Tools.AbstractionsWhat a tool is: the base classes, the declaration, the descriptor, schema generation
ApricotFramework.Agentic.ToolsWhat composes and runs them: the registry, the executor, sources, filters, validators, registration
ApricotFramework.Agentic.Tools.AspNetCoreAuthorization from the attributes a tool declares, and a caller taken from the request
ApricotFramework.Agentic.Tools.Mcp.ClientTools from upstream MCP servers
ApricotFramework.Agentic.Tools.Mcp.ServerThis host's tools, over MCP
ApricotFramework.Agentic.Tools.GrpcThe apricot.agentic.v1 contract — messages only
ApricotFramework.Agentic.Tools.Grpc.ServerThis host's tools, over gRPC
ApricotFramework.Agentic.Tools.Grpc.ClientTools from another service, over gRPC

Three things it refuses to know

How a tool is reached. Being local or remote is a property of the caller. Nothing in a declaration mentions a transport, which is what lets one tool serve an agent loop and an MCP session at once — and what lets a tool that is really a call to another service sit in the registry beside one written here.

What a permission is. Where permissions live, how they are named, and what decides them are answered by the application already. IAgentToolAuthorizationFilter is the whole of what this library knows about the subject, and the ASP.NET Core package implements one by reading the authorization attributes a tool declares and handing them to the host's own pipeline.

Who the caller is. A host answers that once, in an IAgentToolContextFactory, and every surface goes through it. No endpoint, MCP handler or gRPC method builds a caller of its own.

Install

dotnet add package ApricotFramework.Agentic.Tools

and whichever surfaces this host actually has.

Status

Preview. The shape is still moving and breaking changes should be expected until 1.0. Three have already happened in design: authorization moved from a property on the tool to an attribute, results moved from a single value to a sequence, and a tool became an AIFunction with its agentic properties moved onto the descriptor beside it.

On this page