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

# Google ADK

> Connect a Google ADK agent to Civic's MCP Hub using streamable HTTP transport

Connect a [Google Agent Development Kit (ADK)](https://google.github.io/adk-docs/) agent to Civic using streamable HTTP transport. Reference implementations are available in Python (Claude), TypeScript (Gemini), and Go (Gemini).

## Architecture

```
User Message
    |
    v
  Runner  -->  LlmAgent  -->  LLM (Claude / Gemini)
    |              |
    |              v
    |         MCPToolset  --(StreamableHTTP)-->  Civic MCP Hub
    |              |                                  |
    v              v                                  v
  Session     Tool Discovery              Guardrails / Audit / Revocation
              + Invocation
```

| Component          | Purpose                                                  |
| ------------------ | -------------------------------------------------------- |
| **LlmAgent**       | Wraps an LLM with instructions and tools                 |
| **MCPToolset**     | Connects to Civic's MCP Hub, discovers and invokes tools |
| **Runner**         | Orchestrates agent execution and streams response events |
| **SessionService** | Manages conversation state                               |

## Prerequisites

* A Civic account at [app.civic.com](https://app.civic.com) with a configured toolkit
* A Civic token ([how to get one](/civic/quickstart/credentials))

<Card title="Get Your Credentials" icon="key" href="/civic/quickstart/credentials">
  How to generate a Civic token and configure toolkit URL parameters
</Card>

## Environment Variables

All implementations require:

```bash theme={null}
CIVIC_URL=https://app.civic.com/hub/mcp?profile=your-toolkit
CIVIC_TOKEN=your-civic-token
```

Plus an LLM API key depending on the language — see each tab below.

<Tabs>
  <Tab title="Python (Claude)">
    **Requirements:** Python 3.10+, [uv](https://docs.astral.sh/uv/) (recommended) or pip, an [Anthropic API key](https://console.anthropic.com)

    ### Installation

    ```bash theme={null}
    pip install google-adk python-dotenv
    ```

    ### Additional env var

    ```bash theme={null}
    ANTHROPIC_API_KEY=your-anthropic-key
    ```

    ### Connecting to Civic

    ADK has native Anthropic model support via `google.adk.models.anthropic_llm.Claude` — no LiteLlm dependency needed. Register `Claude` with the model registry and reference the model by string:

    ```python theme={null}
    import os
    from dotenv import load_dotenv
    from google.adk.agents import Agent
    from google.adk.tools.mcp_tool import McpToolset
    from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
    from google.adk.models.anthropic_llm import Claude
    from google.adk.models.registry import LLMRegistry

    load_dotenv()

    # Register Claude for native Anthropic model support
    LLMRegistry.register(Claude)

    root_agent = Agent(
        model="claude-sonnet-4-6",
        name="civic_assistant",
        instruction="You are a helpful assistant with access to external tools through Civic.",
        tools=[
            McpToolset(
                connection_params=StreamableHTTPConnectionParams(
                    url=os.environ["CIVIC_URL"],
                    headers={"Authorization": f"Bearer {os.environ['CIVIC_TOKEN']}"},
                ),
            )
        ],
    )
    ```

    ### Running the Agent

    **Option A: ADK web console**

    ADK ships with a built-in development UI:

    ```bash theme={null}
    uv run adk web
    ```

    Open [http://localhost:8000](http://localhost:8000) and select `civic_agent` from the dropdown.

    **Option B: Programmatic runner**

    ```python theme={null}
    import asyncio
    from google.adk.runners import Runner
    from google.adk.sessions import InMemorySessionService
    from google.genai import types

    async def main():
        session_service = InMemorySessionService()
        runner = Runner(
            agent=root_agent,
            app_name="my-app",
            session_service=session_service,
        )
        await session_service.create_session(
            app_name="my-app", user_id="user-1", session_id="session-1"
        )

        message = types.Content(
            role="user",
            parts=[types.Part(text="What events do I have today?")],
        )
        async for event in runner.run_async(
            user_id="user-1", session_id="session-1", new_message=message
        ):
            if event.is_final_response():
                for part in event.content.parts:
                    if part.text:
                        print(part.text)

    asyncio.run(main())
    ```

    <Note>
      Use `types.Part(text=...)` — not `types.Part.from_text(...)`. The `from_text` class method was removed in recent versions of the Google Gen AI SDK.
    </Note>
  </Tab>

  <Tab title="TypeScript (Gemini)">
    **Requirements:** Node.js v18+, a [Google Gemini API key](https://aistudio.google.com/apikey)

    ### Installation

    ```bash theme={null}
    npm install @google/adk dotenv
    ```

    ### Additional env var

    ```bash theme={null}
    GOOGLE_GENAI_API_KEY=your-google-genai-api-key
    ```

    ### Connecting to Civic

    The TypeScript ADK uses `MCPToolset` with `StreamableHTTPConnectionParams`. Gemini is configured automatically via the `GOOGLE_GENAI_API_KEY` env var:

    ```typescript theme={null}
    import 'dotenv/config';
    import {
      LlmAgent,
      Runner,
      InMemorySessionService,
      MCPToolset,
      isFinalResponse,
      stringifyContent,
    } from '@google/adk';
    import type { Content } from '@google/genai';

    const civicUrl = process.env.CIVIC_URL!;
    const civicToken = process.env.CIVIC_TOKEN!;

    const mcpToolset = new MCPToolset({
      type: 'StreamableHTTPConnectionParams',
      url: civicUrl,
      transportOptions: {
        requestInit: {
          headers: { Authorization: `Bearer ${civicToken}` },
        },
      },
    });

    const agent = new LlmAgent({
      model: 'gemini-2.5-flash',
      name: 'civic_assistant',
      instruction: 'You are a helpful assistant. Use the available tools when they can help.',
      tools: [mcpToolset],
    });
    ```

    ### Running the Agent

    ```typescript theme={null}
    async function main() {
      const sessionService = new InMemorySessionService();
      const runner = new Runner({
        appName: 'civic-adk-ts',
        agent,
        sessionService,
      });
      const session = await sessionService.createSession({
        appName: 'civic-adk-ts',
        userId: 'user-1',
      });

      const message: Content = {
        role: 'user',
        parts: [{ text: 'What tools do you have?' }],
      };

      for await (const event of runner.runAsync({
        userId: 'user-1',
        sessionId: session.id,
        newMessage: message,
      })) {
        if (isFinalResponse(event)) {
          const text = stringifyContent(event);
          if (text) console.log(text);
        }
      }
    }

    main();
    ```
  </Tab>

  <Tab title="Go (Gemini)">
    **Requirements:** Go 1.23+, a [Google API key](https://aistudio.google.com/apikey)

    ### Additional env var

    ```bash theme={null}
    GOOGLE_API_KEY=your-google-api-key
    ```

    ### Connecting to Civic

    The Go ADK uses a custom `http.RoundTripper` to inject the Civic Bearer token into every outbound MCP request:

    ```go theme={null}
    package main

    import (
        "context"
        "net/http"
        "os"

        mcp "github.com/modelcontextprotocol/go-sdk/mcp"
        "google.golang.org/adk/agent/llmagent"
        "google.golang.org/adk/model/gemini"
        "google.golang.org/adk/runner"
        "google.golang.org/adk/session"
        "google.golang.org/adk/tool"
        "google.golang.org/adk/tool/mcptoolset"
        "google.golang.org/genai"
    )

    // bearerTransport injects Authorization into every request.
    type bearerTransport struct {
        token string
        base  http.RoundTripper
    }

    func (t *bearerTransport) RoundTrip(req *http.Request) (*http.Response, error) {
        req = req.Clone(req.Context())
        req.Header.Set("Authorization", "Bearer "+t.token)
        return t.base.RoundTrip(req)
    }
    ```

    ### Running the Agent

    ```go theme={null}
    func main() {
        ctx := context.Background()
        civicURL := os.Getenv("CIVIC_URL")
        civicToken := os.Getenv("CIVIC_TOKEN")

        llm, _ := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
            APIKey: os.Getenv("GOOGLE_API_KEY"),
        })

        httpClient := &http.Client{
            Transport: &bearerTransport{token: civicToken, base: http.DefaultTransport},
        }

        transport := &mcp.StreamableClientTransport{
            Endpoint:             civicURL,
            HTTPClient:           httpClient,
            DisableStandaloneSSE: true,
        }

        mcpTools, _ := mcptoolset.New(mcptoolset.Config{Transport: transport})

        root, _ := llmagent.New(llmagent.Config{
            Name:        "civic_assistant",
            Instruction: "You are a helpful assistant. Use the available tools when they can help.",
            Model:       llm,
            Toolsets:    []tool.Toolset{mcpTools},
        })

        sessionSvc := session.InMemoryService()
        r, _ := runner.New(runner.Config{
            AppName:        "civic-adk-go",
            Agent:          root,
            SessionService: sessionSvc,
        })

        sess, _ := sessionSvc.Create(ctx, &session.CreateRequest{
            AppName: "civic-adk-go",
            UserID:  "user-1",
        })

        userContent := &genai.Content{
            Role:  "user",
            Parts: []*genai.Part{{Text: "What tools do you have?"}},
        }

        for event, err := range r.Run(ctx, "user-1", sess.Session.ID(), userContent, nil) {
            if err != nil || event == nil || event.Content == nil {
                continue
            }
            for _, part := range event.Content.Parts {
                if part.Text != "" {
                    fmt.Print(part.Text)
                }
            }
        }
    }
    ```
  </Tab>
</Tabs>

## Production Configuration

Lock to a specific toolkit using the `profile` URL parameter:

```bash theme={null}
CIVIC_URL=https://app.civic.com/hub/mcp?profile=your-production-toolkit
```

## Reference Implementation

<Card title="google-adk-reference-implementation-civic" icon="github" href="https://github.com/civicteam/google-adk-reference-implementation-civic">
  Complete implementations in Python, TypeScript, and Go with deployment guides
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Agent Deployment" icon="robot" href="/civic/quickstart/clients/agents">
    Production deployment guide: profile locking, URL params, authentication
  </Card>

  <Card title="Guardrails" icon="shield" href="/civic/concepts/guardrails">
    Constrain what tools your agent can call
  </Card>

  <Card title="Audit Trail" icon="list-check" href="/civic/concepts/audit">
    Query what your agent did via Civic Chat
  </Card>

  <Card title="Get Credentials" icon="key" href="/civic/quickstart/credentials">
    Token generation and URL parameter reference
  </Card>
</CardGroup>
