Using Providers

Attach context providers to agents and configure them for your use case.

Basic Usage

Create a virtual environment using SDK setup, then install the model dependency and set your key:

uv pip install -U agno openai
export OPENAI_API_KEY="your-openai-api-key"
context_demo.py
import asyncio
from pathlib import Path

from agno.agent import Agent
from agno.context.fs import FilesystemContextProvider
from agno.models.openai import OpenAIResponses

root = Path(__file__).resolve().parent / "context-demo-docs"
root.mkdir(exist_ok=True)
policy = root / "refunds.md"
if not policy.exists():
    policy.write_text("# Refunds\nRefund requests are accepted within 30 days.\n")

fs = FilesystemContextProvider(
    id="docs", root=root, model=OpenAIResponses(id="gpt-5.4-mini")
)
agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=fs.get_tools(),
    instructions=fs.instructions(),
)

if __name__ == "__main__":
    asyncio.run(agent.aprint_response("What is the refund policy? Cite the file."))

Save as context_demo.py and run python context_demo.py. The agent gets query_docs; its sub-agent searches the prepared directory.

Adding Instructions

Providers can generate usage hints. Include them in your agent's instructions:

agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=fs.get_tools(),
    instructions=fs.instructions(),
)

For multiple providers, combine their tool lists and usage hints after configuring each source. See composition.

Read/Write Control

The read and write flags select the outer tools on providers that implement the default two-tool surface. This configuration fragment requires Gmail setup:

from agno.context.gmail import GmailContextProvider

gmail = GmailContextProvider(write=False)  # query_gmail only
gmail = GmailContextProvider(read=False, write=True)  # update_gmail only

The second configuration hides query_gmail, but the write sub-agent can still search and read mail to compose a reply. These flags do not authorize the caller, restrict direct query/update method calls, or determine every mode’s behavior. ContextMode.agent exposes a query tool even with read=False. Enforce resource permissions through source credentials and your application.

Choosing a Mode

The mode parameter controls how the provider exposes itself:

The following are Slack configuration fragments. Complete Slack setup before using them; the local filesystem dependencies above do not install Slack’s SDK.

The provider defines its default exposure. Most read/write providers expose query_<id> + update_<id>.

from agno.context.slack import SlackContextProvider

slack = SlackContextProvider(id="slack")
# Agent sees: query_slack, update_slack

Sub-agent Model

Override the model used by the provider’s internal sub-agent. This continues the local example:

fs = FilesystemContextProvider(
    id="docs", root=root, model=OpenAIResponses(id="gpt-5.4-mini")
)
agent = Agent(model=OpenAIResponses(id="gpt-5.4"), tools=fs.get_tools())

Model choice changes cost, latency and answer quality; measure the complete run, including sub-agent calls.

Query deadlines

A positive query_timeout (seconds, Python 3.11+) bounds each query_<id> tool call, including acquiring its sub-agent and streaming the answer. Expiry yields an error chunk. It does not bound direct query()/aquery(), raw tools in ContextMode.tools, or update_<id> calls. stream_sub_agent_events=False returns the sub-agent’s final answer instead of forwarding its events.

The base ContextProvider also accepts query_tool_name and update_tool_name overrides. Built-in constructors do not all expose those parameters.

Lifecycle Management

Bracket resource-owning providers with asetup() and aclose() in the same async lifecycle. The MCP guide has a complete runnable example with credentials, a connection check and finally cleanup.

  • MCP and MCP-backed web providers hold sessions. MCP asetup() logs connection failures rather than raising them; use await provider.astatus() to check connectivity before proceeding.
  • Wiki providers need explicit await wiki.asetup() before their query tools are exposed. Call await wiki.sync() to refresh Git/Notion content; Notion needs this before its first read.
  • Filesystem, Workspace and Database do not require async session setup. Google/Slack authenticate lazily; provision their credentials before first use.

Use async calls for MCP; its synchronous query() is not implemented. Direct async calls are also preferable when already running inside an event loop.

RunContext Propagation

When a provider runs a sub-agent, it forwards nonempty user_id, session_id, metadata and dependencies from the caller:

Calling Agent
  ↓ tool call with run_context
Provider._query_tool()
  ↓ extracts user_id, session_id, metadata, dependencies
Sub-agent.arun(question, user_id=..., session_id=..., ...)

The fields are context, not a universal authentication mechanism. Provider credentials, filesystem roots and SQL engines are configured on provider instances. Two different caller IDs can still use the same source credentials and data. Your application or custom provider must select and authorize caller-scoped resources when needed. Slack has a specific path for framework-injected action_token metadata.

Outer message history and session_state are not forwarded by this helper.

Next