Tools Overview: How AI Agents Interact With the World
Tools are what separate an LLM from an agent. This page covers the Model Context Protocol standard, the five tool categories used in a 15-agent production system (52 tools total), how to define tools in TypeScript, tool allowlists for multi-agent security, and best practices for naming, describing, and validating tools that LLMs actually use correctly.
Tools Overview: How AI Agents Interact With the World
A language model on its own is a reasoning machine. It can analyze, synthesize, plan, and write. What it cannot do — without tools — is take any action in the world. It cannot search the web, send an email, write to a database, or call an API. It can only produce text.
Tools are the bridge between reasoning and action. When you give an agent a tool, you give it the ability to do something real. That is the entire point of building agents: not to generate better text, but to accomplish work.
This page covers everything you need to understand tools in the context of production AI systems — what the Model Context Protocol is, how tools are structured, the categories we use across our 52-tool system, and how to design tools that agents actually use correctly.
The LLM Is the Brain. Tools Are the Hands.
The LLM provides reasoning, judgment, and language. Tools provide reach — the ability to interact with systems outside the model's context window.
A well-designed agent receives a goal, reasons about what steps are required, calls the appropriate tools to execute those steps, observes the results, and continues reasoning until the goal is met. Every meaningful agent action flows through a tool call.
When an agent produces wrong output, the failure is usually in one of three places: the prompt (the brain), the tool (the hands), or the quality of what the tool returned (the senses). Understanding which layer failed determines how you fix it.
What Is the Model Context Protocol?
The Model Context Protocol (MCP) is an open standard developed by Anthropic that defines how AI models communicate with external tools and data sources. It provides a consistent interface so that any MCP-compatible model can discover, call, and receive results from any MCP-compatible tool — regardless of language or runtime.
Before MCP, every team building agent systems invented their own tool interface format. MCP standardizes this so tooling can be built once and reused across systems.
In practice, MCP means:
- Tools are defined with a consistent schema: name, description, and a JSON Schema for inputs
- The model receives tool definitions as part of the context it reasons over
- When the model decides to use a tool, it emits a structured tool call with arguments
- The host system executes the tool and returns the result to the model
- The model reasons over the result and continues
This loop — reason, call, observe, reason — is the agent execution cycle. MCP provides the contract that makes it work reliably.
At The AI University, our MCP server wraps 52 tools across five categories. Each agent in our 15-agent system sees only the tools it is permitted to use. The MCP server handles registration, dispatch, and result formatting.
How Tools Are Structured
Every tool has three components: a name, a description, and an input schema. These are the interface between your system and the model's reasoning.
The model reads tool definitions to decide which tool to call and how to call it. If a description is vague, the model will call it incorrectly or skip it entirely. If the parameter schema is ambiguous, the model will pass wrong values. Tool design is prompt engineering for capabilities.
Here is the TypeScript interface we use:
// src/lib/agent-sdk/tools/types.ts
export interface ToolDef {
name: string;
description: string;
input_schema: {
type: "object";
properties: Record<string, unknown>;
required?: string[];
};
}
export interface ToolModule {
definitions: ToolDef[];
handleTool(
name: string,
args: Record<string, unknown>,
agentId: string
): Promise<string | null>;
}
And a concrete example — our search_web tool from the research module:
// src/lib/agent-sdk/tools/research.ts
{
name: "search_web",
description:
"Search the web using DuckDuckGo. Returns titles, URLs, and snippets. " +
"Use to find competitor news, reviews, customer mentions, feature announcements.",
input_schema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search query",
},
limit: {
type: "number",
description: "Max results (default 8, max 15)",
},
},
required: ["query"],
},
}
The description names the underlying service, describes the return format, and gives concrete examples of when to use the tool. The model uses all of this. Vague descriptions produce vague tool usage.
The handleTool function is the server-side executor. It receives the tool name and arguments, runs the actual logic, and returns a JSON string. Every tool returns a string because that is what gets injected back into the model's context.
Tool Categories
Our 52 tools fall into five categories. Each category represents a distinct type of capability. Understanding the categories helps you think about what tools to build for your own system.
| Category | Tools | Count |
|---|---|---|
| Research | search_web, fetch_url, search_twitter, search_reddit, search_github_trending, search_youtube, fetch_youtube_channel, get_video_transcript | 8 |
| Communication | send_email, notify_owner, publish_to_linkedin, check_linkedin_status | 4 |
| Data | query_visitors, save_outreach, get_outreach, list_outreach, save_memory, load_memory, get_health_scores, get_stripe_subscribers | 8 |
| Intelligence | enrich_lead, build_dossier, get_competitive_intel, get_learning_brief, generate_conversion_plan | 5 |
| Content | save_content_draft, get_brand_context, save_marketing_task, get_marketing_backlog, save_competitive_brief | 5 |
| Coordination | emit_event, read_events, get_awareness, check_contact, register_contact, claim_work | 6 |
| Skills | save_skill, load_skills, rate_skill, run_skill_script | 4 |
| Platform | create_discount_code, get_funnel_metrics, get_conversion_plan, promote_visitor | 4 |
| Other / Internal | remaining tools across enrichment, outreach, campaigns, partnerships | 8 |
Research Tools
Research tools give agents the ability to gather information from the open web and specialized sources. These are the most frequently used tools in intelligence-gathering agents.
search_web — searches DuckDuckGo and returns titles, URLs, and snippets. Our competitor-watch agent uses this to scan for competitor news, feature announcements, and customer mentions daily.
fetch_url — fetches any URL and returns parsed text content. Useful for reading competitor pricing pages, changelogs, review sites, and blog posts. Agents use it to go deeper after search_web surfaces a relevant result.
search_twitter — searches Twitter/X for recent posts. Provides real-time market signals and competitor mentions. Our ai-trend-monitor agent uses this to surface emerging topics before they reach mainstream coverage.
search_reddit — searches Reddit posts and discussions, with optional subreddit filtering. High signal-to-noise for understanding what practitioners are actually struggling with. Our marketing-strategist uses it to find pain points that map to our content gaps.
search_github_trending — finds trending and popular repositories in specified domains. Essential for technical content agents tracking which AI frameworks are gaining traction. No API key required.
Research tools return structured data — snippets, scores, metadata — that agents then reason over. They do not synthesize. They retrieve. The agent does the synthesis.
Communication Tools
Communication tools let agents take action in the external world. These are the highest-stakes tools in any system because they have real consequences: emails get delivered, posts get published, notifications get sent.
send_email — sends email via Resend with HTML body support. Our outreach, reply-handler, onboarding, retention, and win-back agents all use this. Every call to send_email goes through pre-flight checks: is the contact on the unsubscribe list? Is the cooldown respected? Has another agent already emailed them today?
notify_owner — sends an internal notification to the system owner. Used when agents need human attention: a high-value lead converted, a competitor launched a major feature, an unusual pattern was detected. Agents use this sparingly, not as a substitute for handling things autonomously.
publish_to_linkedin — publishes content to LinkedIn. Used by our content-engine and ai-trend-monitor agents after generating and reviewing content drafts.
The pattern for communication tools: always gate them with a check. Can we contact this person? Has the cooldown elapsed? Communication tools that fire without guardrails create support fires at the worst possible time.
Data Tools
Data tools read from and write to persistent storage. They are the agent's connection to your system's memory and operational data.
query_visitors — queries the visitor database with filters (minimum intent score, email presence, segment). Returns behavioral data: pages visited, time on site, content affinity, heat map zones, form hesitation signals. Agents use this to find who to focus on.
save_outreach — updates outreach records. When the outreach agent sends an email, it calls save_outreach to update the record status. When the reply-handler processes a reply, it calls save_outreach to mark it handled.
save_memory / load_memory — agent long-term memory. Agents write learnings, observations, and decisions to memory and retrieve them on the next run. This is how agents accumulate knowledge across sessions. Without this, every run starts from zero.
get_health_scores — computes engagement health scores for all active subscribers. Returns a distribution across healthy, warning, and critical states. The retention agent uses this to decide who needs attention.
Data tools are the system's source of truth. Design them to return structured, consistent schemas. If the schema changes unexpectedly, the agent's reasoning breaks.
Intelligence Tools
Intelligence tools do analysis. They take inputs and return synthesized assessments that would take a human researcher significant time to produce manually.
enrich_lead — enriches a lead with company, title, and social data from public sources. Takes 10–30 seconds. Returns a structured profile that the outreach agent uses to personalize email sequences.
build_dossier — builds a comprehensive intelligence dossier on a prospect combining enrichment data, behavioral signals from our visitor database, and competitive context. Used before high-value outreach.
get_competitive_intel — reads the latest competitive intelligence accumulated by our competitor-watch agent. Other agents call this to get context on competitor pricing, feature gaps, and customer sentiment without having to re-run research themselves.
get_learning_brief — returns data-backed learnings for a specific audience segment: what messaging converts, which subject line patterns work, what tone to use, what to avoid. The outreach and onboarding agents call this before generating any personalized email.
generate_conversion_plan — calls Claude directly to generate a personalized conversion strategy for a specific visitor based on their full behavioral profile. Saves the plan for the outreach agent to reference when crafting their sequence.
Intelligence tools are where your system compounds. The longer you run them, the richer the data they work with and the more accurate their outputs become.
Content Tools
Content tools manage the content pipeline — from brand context to draft creation to backlog management.
get_brand_context — returns the full product context: pricing, value propositions, target audience, differentiators, tone guidelines, competitor positioning. Agents call this before generating any customer-facing content. It is the single source of truth for how the product is described. Update this tool when the product changes and every agent that generates content reflects the change automatically.
save_content_draft — saves a generated content draft with type, platform, title, body, and hashtags. Creates a reviewable record before publishing.
save_marketing_task — adds a task to the marketing backlog for another agent. The marketing-strategist uses this to delegate: "content-engine, write a LinkedIn post about this competitor gap."
get_marketing_backlog — retrieves pending tasks. Specialized agents call this at the start of each run to pick up what the strategist has queued.
Content tools create the loop between strategy and execution: the strategist identifies what to create, the backlog captures it, the specialists execute it, and drafts accumulate for review.
Tool Allowlists: Restricting Agent Capabilities
In a single-agent system, tool access is straightforward: the agent gets all the tools it needs. In a multi-agent system, unrestricted tool access creates problems. A content agent that can send emails is dangerous. An outreach agent that can publish to LinkedIn is a liability. A research agent that can create discount codes has no business doing so.
Allowlists solve this by restricting which tools each agent can call. The agent's effective capabilities are the intersection of the full tool set and its allowlist.
Here is how our allowlist is structured:
// src/lib/agent-sdk/tools/allowlist.ts
export function getAllowedTools(agentId: string): string[] {
const shared = [
"emit_event", "read_events", "get_awareness",
"check_contact", "register_contact", "claim_work",
"save_memory", "load_memory",
"post_to_talkspace", "read_talkspace",
"fetch_youtube_channel", "get_video_transcript",
];
switch (agentId) {
case "outreach":
return [...shared, "query_visitors", "get_outreach", "send_email",
"save_outreach", "enrich_lead", "notify_owner", "get_brand_context",
"create_discount_code", "build_dossier", "generate_conversion_plan"];
case "competitor-watch":
return [...shared, "get_competitive_intel", "notify_owner",
"fetch_url", "search_web", "save_competitive_intel",
"search_reddit", "search_twitter", "search_github_trending", "search_youtube"];
case "content-engine":
return [...shared, "get_marketing_backlog", "complete_marketing_task",
"save_content_draft", "get_brand_context", "get_competitive_intel",
"get_funnel_metrics", "search_reddit", "search_youtube",
"publish_to_linkedin", "check_linkedin_status"];
// ... remaining agents
default:
return shared;
}
}
The shared tools are safe for every agent: coordination, memory, event bus, and passive research. They create no side effects that could harm other agents or external users.
Destructive or high-stakes tools — send_email, publish_to_linkedin, create_discount_code — appear only in the allowlists of agents that have a legitimate reason to use them and the system prompt guidance to use them correctly.
At the MCP server level, tool dispatch checks the allowlist before executing. An agent that calls a tool outside its allowlist gets a structured error. Designing allowlists forces you to think clearly about what each agent should and should not be able to do — and it is the fastest way to audit what your system can actually affect in the world.
Best Practices for Tool Design
These are the lessons we have learned running 52 tools across 15 agents. They apply whether you are building 5 tools or 500.
Use descriptive, unambiguous names
Tool names should be self-evident. search_web is clear. search is not. save_outreach tells the model exactly what it persists. save tells it nothing.
Use underscores, stick to verb_noun convention — send_email, get_health_scores, build_dossier, publish_to_linkedin — and be consistent across the full tool set. The model pattern-matches across names to build intuition about what the system can do.
Write descriptions for an LLM reader, not a human reader
Human developers scan documentation. LLMs read it. Every word in a tool description is context the model uses to decide whether to call the tool, when to call it, and what to pass it.
Include: what the tool does, what it returns, when to use it, and any caveats or ordering requirements. If a tool should only be called after another tool, say so in the description. If it has rate limits or side effects, mention them.
// Weak description — tells the model nothing useful
description: "Enrich a lead."
// Strong description — gives the model everything it needs to use this correctly
description:
"Enrich a lead with company/title/social data from public sources. " +
"Takes 10-30 seconds. Returns structured profile. " +
"Use before outreach to personalize emails. Cache is checked first."
The extra 15 words in the strong description will prevent more wrong calls than any amount of prompt engineering.
Validate inputs server-side
The model will sometimes pass malformed inputs. Percentages get passed as decimals. IDs get confused. Required fields get omitted. Validate everything on the server side and return structured error objects.
case "create_discount_code": {
const percentOff = Number(args.percent_off);
if (!percentOff || percentOff < 1 || percentOff > 25) {
return JSON.stringify({
error: "percent_off must be between 1 and 25"
});
}
// proceed with valid inputs
}
A structured error response ({ error: "..." }) is better than throwing an exception. The model sees the error in its context, understands what went wrong, and can correct its next call. An unhandled exception produces a cryptic server error that gives the model nothing useful to work with.
Return structured, predictable JSON
Every tool should return JSON. The model reasons over tool return values — if the structure is inconsistent, reasoning breaks. Use the same field names for the same concepts across tools. If visitor records always have id, email, and score, do not return visitorId, emailAddress, and intentScore from a different tool.
Keep tools narrowly focused
One tool, one responsibility. A tool that does too many things is impossible to debug when something goes wrong. If save_outreach also sent the email, you could never tell from logs whether the failure was in the save or the send. If you find yourself adding a boolean that fundamentally changes what a tool does, split it into two tools.
Design for transparency, not cleverness
Agents need to be debuggable. When notify_owner fires, the log should show the agent ID, timestamp, and full content. When send_email fires, you should be able to trace exactly which agent called it and why.
Build logging into every tool handler. Do not rely on the agent's reasoning being correct — verify at the tool layer that what was called matches what you expected.
Key Takeaways
Tools are not a feature of AI agents. They are the mechanism by which agents exist in the world. An agent without tools is a language model with a long system prompt.
The Model Context Protocol provides a standardized way to define, expose, and call tools. Adopting it means your tooling is compatible with any MCP-compatible model and orchestration layer, not just the one you built first.
The five core tool categories — research, communication, data, intelligence, and content — cover the capabilities that most production agent systems need. Start by mapping your agent's job to these categories and identifying which specific tools it requires.
Tool descriptions are read by the LLM, not just by humans. Write them accordingly. Invest the same care in tool description text that you invest in system prompts.
Allowlists are the practical mechanism for multi-agent security. In a system with multiple agents, every agent should have an explicit list of permitted tools. Default to the minimum necessary. Add tools when there is a concrete reason.
Validate inputs, return structured errors, and log every tool call. The agents will make mistakes. Good tooling makes those mistakes visible and recoverable instead of silent and compounding.
Build tools that make agents more capable without making the system harder to reason about. That is the discipline. The 52 tools in our system exist because each one earned its place by giving an agent a genuine capability it could not have otherwise. Design yours the same way.