What are Tools?
- Understand what are Agents
- Learn what are LLMs and the Messages system
- Study Tools and Actions
- Learn the Agent workflow
- Code your first Agent
- Unit Quiz
One crucial aspect of AI Agents is their ability to take actions. As we saw, this happens through Tools.
In this section you’ll learn what a Tool is, how the model uses it and how we describe it to the model via the system message. At the end you’ll write a tool in C# and run it on your own computer, with no model needed.
What are AI Tools?
Section titled “What are AI Tools?”A Tool is a function given to the LLM. It should have a clear objective. For a C# developer it is an ordinary method.
Here are some commonly used tools:
| Tool | Description |
|---|---|
| Web Search | Fetches up-to-date information from the internet. |
| Image Generation | Creates images from a text description. |
| Retrieval | Retrieves information from an external source. |
| API Interface | Works with an external API (GitHub, YouTube, Spotify, etc.). |
Those are only examples. You can create a tool for any task.
A good tool complements the power of an LLM, meaning it does something the model cannot do by itself or does not do well:
- Exact calculations. The model predicts text, it does not compute. A calculator tool gives the right result every time.
- Up-to-date data. The model knows only what was in its training data. If you ask it for today’s weather and it has no tool for that, it will probably make up a forecast. This is called a hallucination.

How do tools work?
Section titled “How do tools work?”An LLM can only read and write text. It has no way of calling a method by itself. So the work is split between two parties: the model says what it wants, and the Agent carries it out. Here the Agent is the program around the model.
Say we gave the model a tool for checking the weather, and the user asks what the weather is like in Paris:
- The model recognizes that it needs this tool. Instead of an answer it writes text that describes the call, such as
GetWeather("Paris"). - The Agent reads that text, understands that it is a tool call, and runs the real
GetWeathermethod. - The Agent adds the result to the conversation as a new message and passes the conversation to the model again.
- The model reads the result and writes the answer for the user.
The user sees only the last step. To them it looks as if the model checked the weather itself, but all the work was done by the Agent.
How do we give tools to an LLM?
Section titled “How do we give tools to an LLM?”The model reads only text. So “giving it a tool” means something simple: we describe the tool in text and put the description into the system prompt.
You are an AI assistant designed to help users efficiently and accurately.Your primary goal is to provide helpful, precise, and clear responses.
You have access to the following tools:{tools_description}The descriptions of our tools take the place of {tools_description}.
What does the model need to know about a tool?
Section titled “What does the model need to know about a tool?”When you hover over a method in Visual Studio, IntelliSense shows you its name, its parameters with their types, the return type and a short description. You don’t see the method body, and you don’t need it to call the method correctly.
The model needs the same four things:
- The name of the tool.
- A description of what it does.
- The inputs: the names and types of the arguments.
- The output: the type of the result.
Let’s take a simple calculator tool that multiplies two integers as an example:
int Calculator(int a, int b) => a * b;Written as text, the four things look like this:
Tool Name: Calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: intImportant: This text is everything the model knows about the tool. It never sees the C# code itself.
This exact format is not mandatory, it could just as well be JSON. What matters is that the description is precise and uses the same format for every tool.
The description can be written by hand, but that is fragile. Rename a parameter, forget to update the text, and the model starts calling the tool incorrectly, with no warning from the compiler. It is better to let the program build the description from the code. That is what we will do now.
Tools in C#
Section titled “Tools in C#”We will write the Calculator tool, make the program build its description by itself, and insert it into the system prompt. The program will not call a model.
All you need is the .NET SDK from Unit 0. You don’t need Ollama, a model or NuGet packages.
1. Create the project
Section titled “1. Create the project”Open a terminal and run:
dotnet new console -n FirstToolcd FirstToolThe first command creates a FirstTool folder with a new console application, and the second one moves into it. Open the folder in your editor. In the next steps we will work with three small files.
2. Write the tool
Section titled “2. Write the tool”Create a new file named MyTools.cs:
using System.ComponentModel;
public static class MyTools{ [Description("Multiply two integers.")] public static int Calculator(int a, int b) => a * b;}This is the method from above with one addition: the [Description] attribute. The name, the parameters and the return type are already written in the method itself. Only the description in words was missing, and the attribute adds it.
Why an attribute and not a /// comment? Comments disappear at compile time. Attributes stay in the program, and it can read them while it runs.
3. Write the Tool class
Section titled “3. Write the Tool class”Create a second file, Tool.cs. It keeps everything about a tool in one place:
using System.ComponentModel;using System.Reflection;
public record Tool( string Name, string Description, Delegate Function, string Arguments, string Outputs){ public static Tool FromMethod(Delegate function) { MethodInfo method = function.Method;
string name = method.Name; string description = method.GetCustomAttribute<DescriptionAttribute>()?.Description ?? ""; string arguments = string.Join(", ", method.GetParameters() .Select(p => $"{p.Name}: {TypeName(p.ParameterType)}")); string outputs = TypeName(method.ReturnType);
return new Tool(name, description, function, arguments, outputs); }
public override string ToString() => $"Tool Name: {Name}, Description: {Description}, " + $"Arguments: {Arguments}, Outputs: {Outputs}";
public object? Invoke(params object?[] args) => Function.DynamicInvoke(args);
private static string TypeName(Type type) => type.Name switch { "Int32" => "int", "String" => "string", "Boolean" => "bool", "Double" => "double", var other => other, };}The first lines list what a tool consists of: the four things from the description plus the method itself (Function). Below them are three methods:
FromMethodcreates aToolfrom the method you pass in. It reads everything it needs from the method itself, through theMethodInfoobject that describes it.ToStringlays out the description on one line. This is the text for the model.Invokeruns the method itself. This is what the Agent will do when the model asks for the tool.
Here is where FromMethod gets the four things:
| What we need | Where it comes from | Result for Calculator |
|---|---|---|
| Name | method.Name |
Calculator |
| Description | the [Description] attribute |
Multiply two integers. |
| Inputs | method.GetParameters() |
a: int, b: int |
| Output | method.ReturnType |
int |
When a program reads information about its own code while it runs, that is called reflection. The TypeName helper only replaces the .NET names Int32 and String with the familiar int and string.
4. Use the tool
Section titled “4. Use the tool”Open Program.cs, delete its contents and put in the following:
Tool calculator = Tool.FromMethod(MyTools.Calculator);
Console.WriteLine(calculator);Console.WriteLine(calculator.Invoke(6, 7));
string systemPrompt = $""" You are an AI assistant designed to help users efficiently and accurately. Your primary goal is to provide helpful, precise, and clear responses.
You have access to the following tools: {calculator} """;
Console.WriteLine();Console.WriteLine(systemPrompt);
// The example ends here.// The next step would be to send this system prompt to a model.The program does three things: it creates a Tool from the Calculator method, prints its description and the result of one call, and finally inserts the description into the system prompt.
The comment at the end marks where we stop. The next step would be to send the system prompt to a model, and we don’t have a model yet.
5. Run the program
Section titled “5. Run the program”In the terminal, inside the FirstTool folder, run:
dotnet runoutput:
Tool Name: Calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int42
You are an AI assistant designed to help users efficiently and accurately.Your primary goal is to provide helpful, precise, and clear responses.
You have access to the following tools:Tool Name: Calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: intHere is how the program arrived at this output:
Tool.FromMethod(MyTools.Calculator)received the method itself, without running it, and read its name, description, parameters and return type.Console.WriteLine(calculator)calledToStringand printed the first line. It is the same description we wrote by hand above, but this time it comes from the code.calculator.Invoke(6, 7)ran the realCalculatormethod and returned42. In an Agent this happens when the model asks for the tool. Here we called it ourselves so you can see that it works.{calculator}insidesystemPromptcalledToStringagain and put the description where{tools_description}stood in the template above.
6. Experiment
Section titled “6. Experiment”Try these two changes and run dotnet run after each one.
Rename the parameters. In MyTools.cs change a and b to x and y:
public static int Calculator(int x, int y) => x * y;The output now says Arguments: x: int, y: int, in both places. You did not touch a single piece of text: the description comes from the code and cannot drift away from it.
Add a second tool. Add one more method to the MyTools class:
[Description("Get the current weather in a given location.")]public static string GetWeather(string location) => $"the weather in {location} is sunny with low temperatures.";In Program.cs create a Tool for it as well, below the first line:
Tool weather = Tool.FromMethod(MyTools.GetWeather);and add it to the system prompt on a new line below {calculator}:
You have access to the following tools: {calculator} {weather} """;A second tool appears at the end of the output, described in the same format:
Tool Name: GetWeather, Description: Get the current weather in a given location., Arguments: location: string, Outputs: stringYou will meet this description again in the Dummy Agent Library, where we will send it to a real model.
How it works in a real application
Section titled “How it works in a real application”The Tool class is a teaching example, but real libraries work the same way. In .NET this is done by AIFunctionFactory from the Microsoft.Extensions.AI library. With AIFunctionFactory.Create(MyTools.Calculator) it also reads the method name, the [Description] attribute and the parameters. The difference is that it describes the inputs as JSON Schema, a format modern models understand.
We’ll use it when building our first Agent. How an Agent calls the tool is covered in the Actions section.
Model Context Protocol (MCP)
Section titled “Model Context Protocol (MCP)”Our Tool class only works inside our own program. Every Agent library has a similar class of its own, so the same tool has to be described again for each of them.
Model Context Protocol (MCP) is an open protocol that standardizes how applications provide tools to LLMs. A tool is implemented once, in a separate program called an MCP server, and any framework that supports MCP can use it. There are already many ready-made MCP servers that your Agent can plug into directly.
In .NET there is an official MCP C# SDK (the ModelContextProtocol NuGet package) that works directly with Microsoft.Extensions.AI. If you want to dive deeper into MCP, check out the free MCP Course by Hugging Face.
Summary
Section titled “Summary”- A Tool is a function that gives an LLM capabilities beyond generating text: exact calculations, up-to-date data, actions in external systems.
- The model does not run tools. It only writes which tool it wants and with what arguments, and the Agent runs it and returns the result.
- To use a tool, the model has to know its name, description, inputs and output. That description lives in the system prompt.
- In C# the description is taken from the method itself through reflection and the
[Description]attribute, so it cannot drift away from the code. - MCP lets a tool be implemented once and used by different frameworks.
Now we can move on to the Agent Workflow, where you’ll see how an Agent observes, thinks, and acts. It brings together everything we’ve covered so far and sets the stage for creating your own AI Agent.
But first, it’s time for another short quiz!