# What are Context Providers? (/context-providers/overview)



A context provider gives an agent a small tool surface for a data source. Most built-in providers expose `query_<id>` and, where supported, `update_<id>`. A source-specific sub-agent chooses the underlying tools; custom providers can answer directly.

```
Agent ↔ ContextProvider ↔ Source tools
```

This keeps source-specific tool descriptions and instructions out of the calling agent’s tool list. Each provider still needs the dependencies, credentials and resources required by its source.

Create a virtual environment using [SDK setup](/sdk/setup), then install the model dependency and set your key:

```bash
uv pip install -U agno openai
export OPENAI_API_KEY="your-openai-api-key"
```

```python title="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.

## How it Works [#how-it-works]

### Sub-agent Architecture [#sub-agent-architecture]

Most built-in providers run an internal sub-agent. Configure its model independently of the calling agent. This fragment continues the local example:

```python
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())
```

A smaller sub-agent can reduce per-call cost, but the extra model calls also add work. Measure cost, latency and answer quality for your workload.

### Read/Write Separation [#readwrite-separation]

Providers such as Database and Slack separate read and write workflows:

| Provider | Read sub-agent                                               | Write sub-agent          |
| -------- | ------------------------------------------------------------ | ------------------------ |
| Database | Uses `readonly_engine`                                       | Uses `sql_engine`        |
| Slack    | History, thread, and lookup tools (search with a user token) | `send_message` + lookups |

Slack’s default read sub-agent has no send/upload tools. Database access is enforced by the database permissions of the credentials behind each engine; naming an engine `readonly_engine` does not make it read-only. MCP providers can expose server write tools through their query wrapper. Consult each provider’s access contract.

### Mode [#mode]

The following are Slack configuration fragments. Complete [Slack setup](/context-providers/providers/slack#setup) before using them; the local filesystem dependencies above do not install Slack’s SDK.

<Tabs>
  <Tab title="default">
    Provider's default exposure. For Slack, this means `query_<id>` + `update_<id>` with separate sub-agents.

    ```python
    from agno.context.slack import SlackContextProvider

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

    **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 (history, threads, lookups, plus search when a user token or Slack-interface token is configured). Writes go through the write sub-agent (send\_message + lookups for channel resolution).
  </Tab>

  <Tab title="agent">
    Single `query_<id>` tool. For Slack, this routes to the read sub-agent.

    ```python
    from agno.context.mode import ContextMode

    from agno.context.slack import SlackContextProvider

    slack = SlackContextProvider(mode=ContextMode.agent)
    # Agent sees: query_slack only
    ```

    **When to use:** A single source-level tool. Verify that provider’s underlying capabilities. 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.
  </Tab>

  <Tab title="tools">
    Bypass sub-agents entirely. Your agent sees the raw toolkit methods.

    ```python
    from agno.context.mode import ContextMode

    from agno.context.slack import SlackContextProvider

    slack = SlackContextProvider(mode=ContextMode.tools)
    # Agent sees: get_channel_history, get_thread, list_channels, get_user_info, 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 `get_channel_history`, `get_thread`, `list_channels`. Write tools require using `mode=default`.
  </Tab>
</Tabs>

## Multi-Provider Composition [#multi-provider-composition]

Use distinct provider IDs when combining sources. This fragment continues the local example, exposing the same prepared directory through two separately named tools:

```python
policies = FilesystemContextProvider(id="policies", root=root)
archive = FilesystemContextProvider(id="archive", root=root)
agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=[*policies.get_tools(), *archive.get_tools()],
    instructions="\n".join([policies.instructions(), archive.instructions()]),
)
```

The tools are `query_policies` and `query_archive`. IDs are normalized to lowercase letters, digits and underscores, so `my-source` and `my_source` collide. Raw tool mode exposes backend names directly and needs its own collision checks. See each provider guide before adding external sources.

## Guides [#guides]

<CardGroup cols="3">
  <Card title="Using Providers" icon="plug" iconType="duotone" href="/context-providers/using-providers">
    Attach providers to agents and configure them.
  </Card>

  <Card title="Custom Providers" icon="code" iconType="duotone" href="/context-providers/custom-providers">
    Create your own provider for any data source.
  </Card>

  <Card title="Provider Catalog" icon="box-open" iconType="duotone" href="/context-providers/providers/overview">
    Browse all built-in providers.
  </Card>
</CardGroup>

## Resources [#resources]

<CardGroup cols="1">
  <Card title="Cookbook Examples" icon="book" href="https://github.com/agno-agi/agno/tree/main/cookbook/12_context">
    Working examples for every provider
  </Card>
</CardGroup>
