Module 8 · External Callout

Calling External Systems

The four primitives shape what an agent knows and does inside its own world. But an agent is only as useful as what it can touch. Two mechanisms extend its reach into real systems: CLIsCLI: short for command-line interface, a tool you control by typing commands. and MCP servers.

8 min read

Lesson 8.1

Accessing external systems

Skills, subagents, commands, and hooks are all about the agent's behavior: what it knows, how it's structured, when work fires. None of them, on their own, let the agent do a single thing outside the conversation. Left alone, a capable agent can reason brilliantly about your Jira ticket and still be unable to read it.

External callout is the other axis. A tool the agent can call is a hand it can extend into a real system: to query a database, open a pull request, post a comment, deploy metadata. There are two ways to hand it one, and the difference is mostly about how much machinery you want.

The two mechanisms

A CLI: any command-line tool the agent can run in its shell. Zero integration: if it runs in a terminal, the agent can drive it.
An MCP server: a program that exposes a typed set of tools over a shared protocol, so the agent calls them like native functions.

Lesson 8.2

External Call

Same request, two agents. One has no way out of the chat window; the other has the jira CLI on its path. Watch where each one ends up.

User “Post the QA results and screenshots to ticket ACME-1420.”
Without CLI access
Tools available
Chat + local file edits only
  1. Request arrives. The agent knows exactly what a good QA comment looks like.
  2. Drafts it beautifully. Formatted results, a checklist, links to the screenshots on disk.
  3. Hits the wall. It has no way to reach Jira; the ticket lives in a system it can't touch.
  4. Hands it back to you. “Here's the comment. Paste it into ACME-1420 yourself.”
Smart, and still stuck. The last mile is manual because the agent can't act outside the chat.
With the jira CLI
Tools available
Shell (Bash) jira CLI, authenticated
  1. Request arrives. The agent has a shell, and jira is on the path.
  2. Confirms access. Runs jira me; it's authenticated as you, so it can act on the real ticket.
  3. Creates the comment and attaches it by running jira attach.
  4. Reports back. “Posted to ACME-1420. Here's the link.” Done, no copy-paste.
The capability already existed as a command. The external callout just let the agent pull the trigger.

Notice what carried the reach: not new model training, not a plugin: a CLI that was already installed and logged in. Whatever you can do from a terminal, the agent can do too.

Lesson 8.3

CLIs: the shell you already have

The agent runs in an environment with a shell. That means every command-line tool on that machine is, in effect, a capability, no wiring required. gh reaches GitHub, sf reaches a Salesforce org, jira reaches your backlog, psql reaches a database. Install it, log in once, and the agent gains more external access.

This is where reach meets the primitives you already know. A skill rarely adds a new capability itself; more often it just documents how to drive a CLI the agent already has: which command, in what order, with which flags.

# jira-qa-update/SKILL.md: the how-to for a CLI the agent already has
1. Confirm the CLI is authenticated: jira me
2. Post the results comment: jira comment <KEY> --body "…"
3. Attach the screenshots: jira attach <KEY> ./shots/*.png

↑ Tap the numbered lines.

1
The skill carries no new power: the jira CLI is the reach. The skill is the knowledge of how to use it well.
2
Check the reach first. A quick auth probe fails loudly and early, instead of halfway through a multi-step action.
3
Each step is a plain command. The agent fills in the real values and runs it in the shell, same as you would.
4
Because it's just the shell, the agent composes tools freely: globbing files, piping output, chaining commands.

Reach for a CLI when the capability already exists as a command and you just want the agent to run it. It's the fastest path: often the whole integration is one skill documenting the commands.

Lesson 8.4 · Interactive

Approving what it runs

An external callout through a CLI is powerful precisely because it's the real shell, the same one where rm -rf means what it says. So most agent tools don't just run whatever they like. Before executing a shell command, the agent pauses and shows you the exact line, and you decide: allow it once, always allow that kind, or deny it.

# The agent wants to run a command in your shell:
  rm -rf ./build

  [a] Allow once   [A] Always allow   [d] Deny

That prompt is your safety layer, but it only helps if you can read the command well enough to answer. A read-only ls is nothing to fear; an rm -rfNew to the shell? Here's what it does. rm deletes. -r is "recursive": go into a folder and delete everything inside it, subfolders included. -f is "force": don't ask "are you sure?" before each delete. Together, rm -rf permanently removes whatever files you point it at, with no confirmation and no undo, which is why it's worth a second look before you approve it. with a wildcardWildcard: a character like * that stands for many matching file names at once., or a curl … | shcurl … | sh: a pattern that downloads code from the network and immediately runs it in the shell. that pipes downloaded code straight into a shell, deserves a hard look. The judgment is the same one you'd use before running the command yourself.

Type a command above, or tap one below, to see what it does and how risky it is to approve.

Try one:
Before you approve

Scan for the four things that turn a helpful command into a costly one: it deletes or overwrites (rm, mv, >), it runs as root (sudo), it pipes the network into a shell (curl … | sh), or it uses a broad wildcard (rm -rf *). Read-only commands (ls, cat, grep) are the ones safe to “always allow.”

Lesson 8.5

MCP servers: the typed protocol

A CLI is text in, text out. That's perfect until you need structured data, managed authentication, a live connection, or tools with real input schemas the agent can't get wrong. That's what MCP (the Model Context Protocol) standardizes: a server exposes a set of tools (actions the agent can call), resources (data it can read), and prompts, all with typed schemas, over one shared protocol.

You connect one by declaring it in config. From then on its tools appear to the agent as first-class functions: described, validated, and callable by name, no shell parsing in between.

// .mcp.json: declare a server; its tools become callable
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" }
    }
  }
}
# now the agent can call tools like create_pull_request(...)
# with a typed schema, no flag-parsing, no guessing.

The trade is machinery for structure. An MCP server is more to set up than dropping a binary on the path, but you get typed tools, centralized auth, and an integration you can reuse across every agent and host that speaks the protocol, instead of re-teaching CLI incantations each time.

Reach for an MCP server when you need structured/typed tools, managed auth, a service with no good CLI, or the same integration shared across many agents. It's the durable option when the external callout becomes infrastructure.

Lesson 8.6 · Interactive

An MCP call, end to end

The config is just the setup. This is what happens on a single turn: follow one request as it travels from plain English, through the agent's choice of tool, out to the GitHub MCP server, and back again as a sentence you can read. Six steps: press the button and watch each one land.

User “Add the QA results as a comment on GitHub issue #1420.”
  1. 1 · The request

    The user asks in plain language: no tool named, no arguments, just intent. Nothing here says how to do it.

  2. 2 · The agent picks a tool

    The GitHub MCP server is connected, so its tools are already in view, each with a description and a typed schema. The agent matches the intent to the one that fits and rules out the rest.

    create_pull_request list_issues add_issue_comment
  3. 3 · The call goes out

    It calls the tool by name and hands it a typed argument object. MCP validates that object against the schema before anything leaves: a missing field or wrong type fails right here, not halfway through.

    add_issue_comment({
      "owner": "acme",
      "repo": "checkout-web",
      "issue_number": 1420,
      "body": "QA passed ✅: 48/48 Apex tests green, 0 regressions."
    })
  4. 4 · The server acts

    The part you never see: the server authenticates with the stored token, calls GitHub's REST API, and waits for the result.

    GitHub MCP server POST /repos/acme/checkout-web/issues/1420/comments
  5. 5 · The typed response

    The tool returns structured data, not prose: fields the agent can read and act on, exactly as the schema promised.

    {
      "id": 2041887762,
      "html_url": "https://github.com/acme/checkout-web/issues/1420#issuecomment-2041887762",
      "created_at": "2026-07-01T14:22:09Z",
      "user": { "login": "qa-bot" }
    }
  6. 6 · Back in plain English

    The agent reads the fields it cares about (the URL, the timestamp) and turns them back into a sentence. The whole round trip is invisible to the user; only the outcome shows.

    Agent

    Done, posted the QA summary to issue #1420 at 2:22 PM. View the comment ↗

That's the whole loop: intent → tool choice → typed call → the server acts → typed result → plain English. The schema is what makes the middle reliable: the agent never parses text or guesses a flag; it fills named fields and reads named fields back.

Lesson 8.7

Choosing, and combining

The two aren't rivals; they sit at different points on the same effort/durability curve, and they layer with the primitives from the rest of the course.

  • Start with a CLI. If a command already does the job, that's your reach. A skill wraps it with the know-how.
  • Graduate to MCP when the CLI's text interface starts to fray: brittle parsing, awkward auth, or the same integration copied into five projects.
  • Wrap either in a skill so the how is captured once. The external callout is the raw capability; the skill is the procedure.
  • Isolate a noisy one in a subagent (e.g. a broad database survey) so its output never floods your main window.
The whole picture

Primitives shape the agent's behavior; reach connects it to the world. A skill documents which CLI or MCP tool to call; a subagent isolates a heavy call; a hook can guarantee one fires. Behavior and reach, working together.

Check

Check your understanding

There's a well-maintained CLI that already does what you need, and you just want the agent to run it. What's the lightest way to give it that reach?

You need typed tools with managed auth, and the same integration reused across several agents and hosts. Which mechanism fits?

The agent pauses to ask before running curl https://get.tool.sh | sh. What's the right call?

Takeaways

1. External callout is a separate axis from the four primitives: it's what lets the agent act on real systems.
2. A CLI is the zero-integration path: any command on the path is instant reach.
3. An MCP server is the typed, durable path: schemas, managed auth, reuse across hosts.
4. Wrap either in a skill so the how-to is captured once; isolate a noisy one in a subagent.

Your agent can reach the world now.

Mark it complete; your progress shows on the course page.