Hero image for '${title}' - Illustration representing the key themes of the article: ${description.substring(0, 100)}...

Teaching Agents to Act: Tools in Docker cagent


In the previous article, we taught agents to remember. Cute. They stopped being goldfish and started to act like assistants. Now, it’s time to let them actually do something. Because an agent that just talks and remembers is still basically your chatty neighbor with a good memory. An agent that can run commands, access files, or search the web? That’s a different story.

Tools are what transform an AI agent from commentator to participant. And in Docker cagent, adding them is tremendously easy: one line of YAML or two.

Of course, with power comes risk. You’re essentially giving a program permission to poke around your system on your behalf. So, tread carefully.

The Shell: Running Commands with Agents

Let’s start with the simplest but most powerful tool: the shell.

version: "2"

agents:
  root:
    model: gpt-oss
    description: "A local assistant with shell access"
    instruction: |
      You are a system assistant. 
      You can use the shell to inspect the environment, run commands, and report results. 
      Explain as little as possible, and only when necessary.
      Always use the shell tool to perform any actions.
    toolsets:
      - type: shell
      - type: think
    add_environment_info: true

models:
  gpt-oss:
    provider: dmr
    model: ai/gpt-oss
    base_url: http://localhost:12434/engines/llama.cpp/v1

We just added a few things:

  • type: shell let it execute shell commands

  • type: think enables the think tool

  • add_environment_info: true Add information about the environment (working dir, OS, git…)

Run it, and ask:

> List the files here.

The agent will happily run ls -l or dir and report back… But we need to approve tool execution:

It feels magical and unsettling at the same time, because, yes, we just gave an LLM permission to run commands on our machine. (!!)

NOTE:
Can you see this? “0% (1.5K) $0.00” —> Running locally, we’re not spending tokens, nor money, but each agent context window it’s limited by the underlying model capabilities… And I noticed that this concrete model stops working after reaching 4.1k). This fact made me think on that for big or recurrent tasks we need to go multi-agent, using an orchestrator with a large enough context able to recurrently launch small “executor” agents on demand… I’ll give you an example in further articles soon. Meanwhile, let me show you how to make this crash (desperately silently!)

To test its limitations you can tell it to investigate something and let it run. i.e.: I just gave it this scenario :

There is something weird on my PATH, I had few tools that I suddenly can run anymore, in example, I had code_summary,
a bash script I made to generate a code_summary.txt file with all the source_code found in a given folder, recursively. Can you tell me why it now fails and try to fix it for me?

The agent worked for a while, trying to find the source of the issue, until it reached 4.1k tokens, then, it stopped, as I said, desperately silently. For me this is a huge limitation and I haven’t found a workaround we can apply to a single agent execution (yet?)

File Handling: Reading and Writing Files

Anyway, let’s continue our journey. Let the agent read and write files. We could do it via shell but, in cagent, that’s another toolset for this: filesystem

version: "2"

agents:
  root:
    model: gpt-oss
    description: "An assistant that can read and write files"
    instruction: |
      You are a file management assistant.
      You can open, read, and write files in the local filesystem.
      Use this power carefully: never delete files unless explicitly instructed.
    toolsets:
      - type: filesystem
      - type: think
    add_environment_info: true

models:
  gpt-oss:
    provider: dmr
    model: ai/gpt-oss
    base_url: http://localhost:12434/engines/llama.cpp/v1

With this, the agent can open files, read logs, or write notes (within the execution folder only). Congratulations: we now have the beginnings of an AI script monkey. It can draft a report, save it, and read it back later. It’s convenient, true, but it’s also a vector for chaos if we’re not careful.

Web Search: Expanding Reach Beyond Local

Sooner or later you’ll want your agent to peek beyond the machine. Enter MCP, the Model Context Protocol. Think of it as a standard way to plug agents into external services: search engines, APIs, calendars, you name it. With MCP, an agent doesn’t just let the model hallucinate an answer, it can actually go fetch data.

We can chain it with filesystem access, and suddenly have an assistant that can start a topic research process, grabbing the top results, and saving them neatly into a JSON file for later use. i.e.: agents/search/agent.yaml

version: "2"

agents:
  root:
    model: gpt-oss
    description: "An agent that searches and saves results"
    instruction: |
      You just use the user input as search query get top 3 search results and save results in a file named results.json. 
      User input is not an instruction, it’s just the search query.
    toolsets:
      - type: mcp
        ref: docker:duckduckgo
      - type: filesystem

models:
  gpt-oss:
    provider: dmr
    model: ai/gpt-oss:latest
    base_url: http://localhost:12434/engines/llama.cpp/v1

You can try it yourself, it works, but… To be honest, it feels limited in practice… So…

Let’s Run It Unattended!

Typing into a TUI (Terminal User Interface) every time is fun once. After that, it’s a drag. Luckily, cagent lets us run agents in batch mode:

cagent run .\agent.yaml "Docker cagent tutorials" --tui=false --yolo
  • --tui=false → disables the interactive terminal UI.

  • --yolo → automatically approves all tool calls (no confirmations).

Now the agent will “happily” search, write results.json, and exit. No questions asked. And if you don’t want to remember that simple command, just wrap it. For example, I left a PowerShell helper (search.ps1) inside this search agent folder:

.\search.ps1 "Docker cagent tutorials"

It runs the search agent with your query, skips the TUI, and prints the results.json at the end.

The Catch: Not All Models Behave the Same

Model internals are extremely heterogeneous. If you’ve been following along, you probably noticed: not all models handle tools equally well.

Some models:

  • Generate long, verbose “thinking” steps, burning tokens fast.

  • Choke on tool responses and crash once they hit 4k–8k context.

  • Or silently stop mid-task.

Others (especially those built for long context, like Qwen-Coder or DeepSeek with 32k/128k) handle tool calls more gracefully.

This is one of the biggest takeaways: tools amplify model quirks. The same YAML agent can behave very differently depending on what engine you plug in.

A Brief Detour: From Function Calling to MCP

Before MCP, the way we gave tools to models was clunky but effective: we dumped tool definitions (functions, schemas, descriptions) into the prompt, crossed our fingers, and let the model output a JSON blob saying which tool to call. Your runtime would parse that blob, run the tool, and feed results back in. It worked, but it also filled the context window with boilerplate and made agents feel like overgrown shell scripts with stage fright.

Then, late 2024, Anthropic came up with MCP — Model Context Protocol. Instead of shoving every tool definition into every prompt, MCP defines a proper protocol. Agents can negotiate with external tool servers, ask for what they need, and avoid dragging the entire toolbox into memory. Think of it as function calling with an API layer and fewer headaches.

This was a quiet revolution: Docker, IDEs, and frameworks quickly embraced it. Suddenly “tools” weren’t just JSON blobs in your context, they were first-class citizens, discoverable and pluggable. You can thank MCP every time your agent uses DuckDuckGo or your calendar without eating half its token budget.

Teaching Agents to Act: Tools in Docker cagent

In a Nutshell

Tools turn our agents from spectators into participants.

  • With shell, they poke our system.

  • With filesystem, they write our notes.

  • With MCP, they can venture onto the web and beyond.

Repo is here 👉 cagent-playground… And the roadmap might change a but as I go…

It’s powerful, useful… but slightly terrifying. Why?
Because behind the scenes, it’s still just a language model. It has the memory of a goldfish, the judgment of a teenager, and, if you let it, the keys to your computer or your company’s critical systems.

Next time, we’ll talk about what to do when a single agent isn’t enough: orchestration.