Context Providers give agents clean access to external systems without tool sprawl.
Context Providers solve three problems that appear when agents integrate with multiple external systems:
Tool sprawl. Slack alone is 8-12 tools. Add Drive, GitHub, your CRM, and you’re at 50 tools before adding anything custom. Past 20, models start hallucinating tools or picking the wrong one.
Name collisions.search in one toolkit collides with search in another. send_message could be Slack, email, or your CRM. No naming convention fixes it.
System-prompt bloat. Using Slack well requires Slack-specific guidance: look up user IDs before DMing, resolve channel names, prefer conversations.history for channels. Multiply by every API. The system prompt becomes the union of every source’s quirks.
A ContextProvider wraps an external system and exposes it as one or two tools:
Agent ↔ ContextProvider ↔ Tools
The calling agent sees query_<id> (for reads) and update_<id> (for writes). Behind the tool is a sub-agent scoped to that one source.
The agent sees five tools: query_slack, update_slack, query_gdrive, query_database, update_database. Each provider exposes one read tool plus an optional write tool.
The sub-agent does the tool work; the calling agent does the reasoning. On most workloads this is cheaper and faster than putting every source’s tools on one big agent.
When to use: Most cases. You get clean read/write separation with privilege isolation. The read sub-agent cannot call write tools.How it works: Two sub-agents handle the underlying toolkit. Reads go through the read sub-agent (search, history). Writes go through the write sub-agent (send_message + lookups for channel resolution).
Single query_<id> tool. Read-only access through one sub-agent.
from agno.context.mode import ContextModeslack = SlackContextProvider(mode=ContextMode.agent)# Agent sees: query_slack only
When to use: Read-only access, or when you want maximum abstraction. Your agent just asks questions; the sub-agent figures out which tools to call.How it works: All requests route through the read sub-agent. No write access. The sub-agent orchestrates reads internally.
Bypass sub-agents entirely. Your agent sees the raw toolkit methods.
from agno.context.mode import ContextModeslack = SlackContextProvider(mode=ContextMode.tools)# Agent sees: search_messages, get_channel_history, get_thread, list_channels, etc.
When to use: Building a source-specific agent, or when you need fine-grained control over individual API calls.How it works: No sub-agent wrapping. Your agent directly calls read tools like search_messages, get_thread, list_channels. Write tools require using mode=default.