> ## Documentation Index
> Fetch the complete documentation index at: https://stockcontext.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Build an equity agent

> Wire the tools into a function-calling loop over plain HTTP, trace one question end to end, and cite provenance in the answer.

If your agent supports MCP, use the hosted endpoint at `https://stockcontext.com/mcp` ([setup](/docs/mcp/overview)). This page shows the plain HTTP function-calling pattern for agents or frameworks where you register tools yourself: expose each tool as a function that `POST`s to `/v1/tools/{name}` and returns the parsed JSON.

## The tool-selection policy

Start narrow. For a "tell me about X" question the first call is almost always `stock_overview` — it carries the latest financials, valuation, and growth in one payload. Add exactly one more call per dimension the question opens, and stop when it is answered. See [Choose a tool](/docs/guides/choose-endpoints) for the full map.

## Tool functions

Each tool is one function. The key lives in the `X-API-Key` header, server-side — never in a prompt or a client bundle.

<Tabs>
  <Tab title="Python">
    ```python title="agent_tools.py" theme={null}
    import os
    import httpx

    BASE = "https://api.stockcontext.com"
    KEY = os.environ["STOCKCONTEXT_API_KEY"]


    async def tool(name: str, **body) -> dict:
        """One agent tool per API tool. Returns parsed JSON."""
        async with httpx.AsyncClient(timeout=15) as client:
            res = await client.post(
                f"{BASE}/v1/tools/{name}",
                json=body,
                headers={"X-API-Key": KEY},
            )
        res.raise_for_status()
        return res.json()


    # Expose these to the model:
    async def stock_search(q: str) -> dict:
        return await tool("stock_search", q=q)

    async def stock_overview(symbol: str) -> dict:
        return await tool("stock_overview", symbol=symbol)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```ts title="agentTools.ts" theme={null}
    const BASE = "https://api.stockcontext.com";
    const KEY = process.env.STOCKCONTEXT_API_KEY!;

    async function tool(name: string, body: Record<string, unknown>) {
      const res = await fetch(`${BASE}/v1/tools/${name}`, {
        method: "POST",
        headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
        body: JSON.stringify(body),
        signal: AbortSignal.timeout(15_000),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return res.json();
    }

    // Expose these to the model:
    export const stockSearch = (query: string) => tool("stock_search", { query });
    export const stockOverview = (symbol: string) => tool("stock_overview", { symbol });
    ```
  </Tab>
</Tabs>

Register these as function-calling tools with your model provider, with the same argument names the API uses.

## A worked trace

**User:** Is Apple growing, and how is it priced?

**Call 1, `stock_search`** — resolve the ticker and confirm coverage.

```json title="stock_search q=AAPL (trimmed)" theme={null}
{
  "data": {
    "matches": [
      { "ticker": "AAPL", "coverage": { "financials": true, "prices": true },
        "entity": { "cik": "0000320193", "name": "Apple Inc.", "shape": "operating_company" } }
    ]
  },
  "meta": { "schema_version": "2" }
}
```

`coverage.financials: true`, so fundamentals are served. The agent proceeds.

**Call 2, `stock_overview`** — one call covers growth and valuation.

```json title="stock_overview symbol=AAPL (trimmed)" theme={null}
{
  "data": {
    "growth": {
      "revenue": { "yoy_pct": 6.43 },
      "net_income": { "yoy_pct": 19.5 }
    },
    "valuation": {
      "price_to_earnings": 39.46,
      "fcf_yield_pct": { "value": 2.27, "basis": "FY2025_annual" }
    }
  },
  "meta": { "schema_version": "2", "as_of": { "sec": "2026-06-26", "market": "2026-07-02" } }
}
```

Two dimensions, one call. The agent has enough to answer.

**Final answer.** Answer first, then the facts, then the provenance and clocks it stood on:

> Apple grew revenue about 6.4% and net income about 19.5% year over year, and it trades at a trailing P/E of roughly 39.5 with a free-cash-flow yield near 2.3%.
>
> The growth figures come from SEC-filed financials (`as_of.sec` 2026-06-26). The P/E and FCF yield are `computed_from_prices` — a fundamentals input times a market close on 2026-07-01 — so they move with the price, not the filings. Calls used: stock\_search, stock\_overview. This is context, not advice.

That last paragraph is not optional. The instruction that produces it — answer first, cite provenance and the clock, never give buy/sell advice, never invent data the API refused — is in [Agent instructions](/docs/agents/instructions). Paste that block into your system prompt.

## Where agents go wrong

* **Reading a refusal as a value.** A field with `unavailable` has no value. Never substitute `0` or `null`; report the token (and look it up in the `refusal_tokens` catalog if needed).
* **Parsing magnitudes as floats.** Exact values are decimal strings — use a decimal type so precision survives.
* **Blending the two clocks.** A `computed_from_prices` multiple mixes an SEC-filed input with a market close. Do not present it as "the filing says," and cite the price date.
* **Treating 13F as total ownership.** `stock_ownership` is a tracked subset with `exhaustive: false`. Say "among tracked managers."
* **Retrying non-retryable failures.** `invalid_api_key` (401) and a `422` validation error do not change on retry — fix the cause. See [Errors and retries](/docs/guides/errors-and-retries).

<Card title="Agent instructions" icon="bot" href="/docs/agents/instructions">
  The operating rules to paste into your system prompt.
</Card>
