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

# Claude Agent SDK

> Give Claude agents a Notte cloud browser through MCP.

<Tip>
  Read [the Notte skill](https://notte.cc/skill.md) and follow its setup instructions when setting up Notte or building browser automation. This is the shared source for CLI setup, authentication, and the browser-to-code workflow.
</Tip>

Connect the [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview) to Notte over MCP. Your application owns the browser session; Claude navigates and reads the page through Notte tools.

## Install

For Python 3.11+, run `pip install notte-sdk claude-agent-sdk==0.2.168`.

For Node.js 24+, run `npm install notte-sdk @anthropic-ai/claude-agent-sdk@0.3.301` and set `"type": "module"` in `package.json`. The SDK includes its Claude runtime; no local browser installation is needed.

Set `NOTTE_API_KEY` to your [Notte API key](https://console.notte.cc/apikeys) and `ANTHROPIC_API_KEY` to your [Anthropic API key](https://console.anthropic.com/settings/keys).

## Read a page

Save the example as `notte_claude_agent.py` or `notte_claude_agent.ts`. Run `python notte_claude_agent.py` or `node --experimental-strip-types notte_claude_agent.ts`.

<CodeGroup>
  ```python notte_claude_agent.py theme={null}
  import asyncio
  import os

  from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, query
  from notte_sdk import NotteClient


  async def main() -> dict[str, str]:
      with NotteClient().Session(max_duration_minutes=3) as session:
          options = ClaudeAgentOptions(
              model="claude-haiku-5-5",
              tools=[],
              setting_sources=[],
              strict_mcp_config=True,
              permission_mode="dontAsk",
              allowed_tools=[f"mcp__notte__{name}" for name in ("browser_action", "browser_observe", "browser_scrape")],
              mcp_servers={
                  "notte": {
                      "type": "http",
                      "url": (os.environ.get("NOTTE_API_URL") or "https://api.notte.cc").rstrip("/") + "/mcp",
                      "headers": {"Authorization": "Bearer ${NOTTE_API_KEY}"},
                  }
              },
              max_turns=8,
              output_format={
                  "type": "json_schema",
                  "schema": {"type": "object", "properties": {"title": {"type": "string"}}, "required": ["title"]},
              },
          )
          title: str | None = None
          try:
              async for message in query(
                  prompt=f"Use Notte tools with browser_id {session.session_id}. Visit https://example.com and read its page title.",
                  options=options,
              ):
                  if isinstance(message, ResultMessage) and not message.is_error:
                      if isinstance(message.structured_output, dict):
                          title = message.structured_output.get("title")
              if not isinstance(title, str):
                  raise RuntimeError("The Claude agent returned no page title")
          except Exception:
              raise RuntimeError(f"Claude agent failed (session {session.session_id})") from None
          print(title)
          return {"title": title, "session_id": session.session_id}


  with asyncio.Runner() as runner:
      result = runner.run(main())
  ```

  ```typescript notte_claude_agent.ts theme={null}
  import { query } from '@anthropic-ai/claude-agent-sdk';
  import { NotteClient } from 'notte-sdk';

  export const result = await new NotteClient().Session({ max_duration_minutes: 3 }).use(async (session) => {
    let title: unknown;
    try {
      for await (const message of query({
        prompt: `Use Notte tools with browser_id ${session.getId()!}. Visit https://example.com and read its page title.`,
        options: {
          model: 'claude-haiku-5-5',
          tools: [],
          settingSources: [],
          strictMcpConfig: true,
          permissionMode: 'dontAsk',
          allowedTools: ['browser_action', 'browser_observe', 'browser_scrape'].map(name => `mcp__notte__${name}`),
          mcpServers: {
            notte: {
              type: 'http',
              url: `${(process.env.NOTTE_API_URL || 'https://api.notte.cc').replace(/\/+$/, '')}/mcp`,
              headers: { Authorization: 'Bearer ${NOTTE_API_KEY}' },
            },
          },
          maxTurns: 8,
          outputFormat: {
            type: 'json_schema',
            schema: { type: 'object', properties: { title: { type: 'string' } }, required: ['title'] },
          },
        },
      })) {
        if (message.type === 'result' && message.subtype === 'success') {
          title = (message.structured_output as { title?: unknown } | undefined)?.title;
        }
      }
      if (typeof title !== 'string') throw new Error('The Claude agent returned no page title');
    } catch {
      throw new Error(`Claude agent failed (session ${session.getId()!})`);
    }
    console.log(title);
    return { title, session_id: session.getId()! };
  });
  ```
</CodeGroup>

Both examples print `Example Domain` and close the browser on success or failure. They use a fixed set of Notte tools, disable built-in tools and filesystem settings, and wait for the complete query stream before closing the session.

See [Claude MCP configuration](https://code.claude.com/docs/en/agent-sdk/mcp) and [Notte session lifecycle](/features/sessions/lifecycle).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.