Build a GitHub agent using Google ADK and OpenAPI Integration
A Step-by-Step Guide using ADK, OpenAPI Spec v3, and Gemini 2.5 Pro
Introduction
The Agent Development Kit(ADK) supports a wide range of tool integrations for building agents, including Function tools, Built-in tools, third-party tools, Google Cloud Tools, MCP Tools, and OpenAPI tools with authentication support. This article will focus on integrating REST APIs using the OpenAPI specification, eliminating the need to manually define individual function tools for each API endpoint to have a fully functional GitHub conversational assistant.
What is a Tool in ADK?
In ADK, a tool refers to the distinct capability that allows agents to interact with external systems and perform real-world actions beyond basic language generation, such as fetching data, calling APIs, triggering workflows, or even invoking other agents.
Tools are what separate LLMs from capable, action-driven agents.
A tool in ADK is typically a:
- Python function
- Class method
- OpenAPI-defined endpoint
- Third-party or built-in service
- Another agent
Tools are exposed to agents as callable actions based on the schema, enabling LLMs (Function Calling ) to understand the tool's purpose, when and how to call it, and how to interpret the tool's response.
What are OpenAPI Tools in ADK?
OpenAPI Tools in ADK allow us to convert an entire REST API, described in an OpenAPI Specification (v3), into a set of function-callable tools that an AI agent can understand and use.
Instead of manually writing a function for every API endpoint, we point ADK to the OpenAPI spec file (JSON or YAML), and it auto-generates tools with:
- Proper input parameters
- Request/response formatting
- Authentication support
Key Components of OpenAPI Integration in ADK
- OpenAPIToolset — Main entry point for working with OpenAPI specs in ADK. It takes an OpenAPI v3 specification as input, parses it, and automatically generates a set of callable tools.
Example: Below is the output from GitHub OpenAPI v3 during OpenAPIToolset parsing
Each line represents a unique GitHub API endpoint converted into a callable RestApiTool that our agent can invoke based on user input.
INFO - openapi_toolset.py:142 - Parsed tool: reactions_create_for_release
INFO - openapi_toolset.py:142 - Parsed tool: reactions_delete_for_release
INFO - openapi_toolset.py:142 - Parsed tool: repos_get_branch_rules
INFO - openapi_toolset.py:142 - Parsed tool: repos_get_repo_rulesets
INFO - openapi_toolset.py:142 - Parsed tool: repos_create_repo_ruleset
INFO - openapi_toolset.py:142 - Parsed tool: repos_get_repo_rule_suites
INFO - openapi_toolset.py:142 - Parsed tool: repos_get_repo_ruleset
INFO - openapi_toolset.py:142 - Parsed tool: repos_update_repo_ruleset
INFO - openapi_toolset.py:142 - Parsed tool: repos_delete_repo_ruleset
2. RestApiTool — Each API operation (e.g., GET /users/{username} or POST /repos) is represented as a RestApiTool instance. The OpenAPIToolset creates one RestApiTool per operation defined in our OpenAPI spec, making it easy for the agent to invoke them contextually.
The example below is an individual API that uses a single function call as ‘projects_add_collaborator’
projects/add-collaborator
Path: PUT /projects/{project_id}/collaborators/{username}
How OpenAPI Toolset work in ADK?
The process involves these main steps when we use OpenAPIToolset
:
1. Initialization & Parsing
- We load our OpenAPI spec (JSON/YAML or Python dict).
- ADK parses the spec and resolves internal references like $ref to understand all API endpoints.
2. Operation Discovery
- Scans the spec to find all valid API operations like GET, POST, PUT, and DELETE.
3. Tool Generation
For each API operation:
- A RestApiTool is created automatically.
- The tool name comes from the operationId in the spec (converted to snake_case).
- Description is taken from the operation’s summary or description.
- The tool includes all HTTP details: method, path, parameters, request body, etc.
4. LLM Schema + Execution
Each RestApiTool:
- Dynamically generates a function schema so the LLM knows what parameters to pass.
- Builds and sends the HTTP request with all arguments and authentication.
- Returns the response (usually JSON) back to the agent.
5. Authentication Support
- We can configure API keys or OAuth during setup.
- ADK will automatically apply it to all generated tools.
Architecture
The project below will leverage ADK’s OpenAPI Tools and Authentication modules to dynamically generate tools from GitHub’s OpenAPI Spec v3 to create a conversational GitHub agent.
Core Components
- ADK Framework — Provides the agent infrastructure (Agent class from google.adk.agents)
- OpenAPI Specification — GitHub’s v3 API is defined in JSON format
- Authentication Handler — Manages GitHub private access tokens
- Gemini 2.5 Pro LLM — Powers the natural language understanding
- OpenAPIToolset — Dynamically generates API tools from the spec
User Flow
- Query Input: User enters a natural language request (e.g., “show my repositories”)
- Initial Processing:
- The query is routed to the GitHub agent.
- ADK prepares the context, including the API spec and auth token
3. LLM Processing:
- Gemini 2.5 Pro interprets the user’s intent.
- The query is mapped to potential GitHub API operations
4. Tool Discovery:
- OpenAPIToolset identifies relevant API endpoints.
- Parameters are extracted or requested if missing
5. API Execution:
- The selected GitHub API is called with proper authentication.
- The operation executes against GitHub’s servers
6. Response Handling:
- API response is formatted for readability
- Results are presented back to the user
Implementation
Let us build an agent using ADK and OpenAPI Spec by breaking down into key implementation steps.
Pre-Requisites
- Python 3.11+ installed
- Google Gemini Generative AI access via API key
- GitHub account and personal access token (for setup)
- GitHub OpenAPI Spec: https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json
Project Structure
/adk-github-agent
├── api.github.com.json # GitHub OpenAPI spec
├── api.github.com.fixed.json # Fixed API spec copy -removed incorrect JSON schema
├── .venv/ # Python virtual environment
└── github-agent/
├── agent.py # Focused agent implementation
├── __init__.py # Module initialization
Step 1: Set up a virtual environment
# Setup virtual environment (Mac or Unix )
python -m venv venv && source venv/bin/active
Step 2: Install dependencies
# Install agent development kit
pip install google-adk
Step 3: Obtain a GitHub API token
- Go to GitHub → Settings → Developer settings → Personal access tokens
- Generate a new token with appropriate permissions.
- Save the token securely for use in our application
Step 4: Import ADK Python module
- Agent — Agent class is the core building block of Google’s Agent Development Kit (ADK). Provides LLM Integration, Conversation Management, Tool Orchestration, and Prompt Management.
2. OpenAPIToolset — Transforms API specifications into executable tools
- Spec Parsing: Reads and interprets GitHub’s OpenAPI specification JSON.
- Tool Generation: Automatically creates tools for each API endpoint (over 1000+ GitHub operations)
- Parameter Handling: Manages required/optional parameters for API calls
- Response Processing: Formats API responses for user consumption
This eliminates the need to code each GitHub API endpoint as a separate function manually
3.token_to_scheme_credential — Function handles authentication
- Token Formatting: Converts raw GitHub token to proper authorization format
- Authentication Scheme: Configures as header-based API key authentication
- Credential Management: Creates a credentials object used by the OpenAPIToolset.
- Security: Properly formats token with “token” prefix required by GitHub
from google.adk.agents import Agent
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
from google.adk.tools.openapi_tool.auth.auth_helpers import token_to_scheme_credential
Step 5: Load OpenAPI Spec with Credential Auth
Loads the API spec using the helper function
def load_api_spec(path):
try:
with open(path, "r") as f:
return json.load(f)
except Exception as e:
logger.error(f"Error loading API spec: {e}")
return None
def create_github_agent(api_spec_path="api.github.com.fixed.json", token_env_var="GITHUB_TOKEN", auth_prefix="token"):
token = os.getenv(token_env_var)
if not token:
logger.error(f"GitHub token missing from environment variable: {token_env_var}")
return None
if not os.path.exists(api_spec_path):
logger.error(f"GitHub API spec file not found: {api_spec_path}")
return None
spec = load_api_spec(api_spec_path)
Step 6: GitHub Auth Credential formatting
Uses ADK’s helper to format GitHub authentication, Configures as an API key in the Authorization header, Formats with the GitHub-required prefix (“token {YOUR_TOKEN}”)
auth_scheme, auth_credential = token_to_scheme_credential(
"apikey", "header", "Authorization", f"{auth_prefix} {token}"
)
Step 7: OpenAPI Toolset Creation
toolset = OpenAPIToolset(
spec_str=json.dumps(spec),
spec_str_type="json",
auth_scheme=auth_scheme,
auth_credential=auth_credential
)
tools = toolset.get_tools()
- Creates an OpenAPIToolset with:
- The GitHub API specification (converted back to a JSON string)
- JSON format indicator
- Authentication scheme and credentials
2. Extracts the generated tools from the API specification
Step 8: Create LLM Agent using Gemini 2.5 Pro
Creates a GitHub agent that understands natural language requests about GitHub, Maps these to appropriate GitHub API calls, handles authentication correctly, and finally formats responses in a user-friendly way.
Note: No Hardcoding of Function calling is used in Agent Instruction, and also, a generic instruction is given to Gemini-2.5 Pro
return Agent(
name="github_agent",
description="GitHub API Agent",
instruction="""
You are a GitHub API agent that interacts with GitHub's REST API.
When working with the GitHub API:
- Use parameters provided by the user
- Ask for clarification if required parameters are missing
- Format responses clearly for the user
- Handle errors gracefully and explain issues in simple terms
For content creation operations:
- Use names and identifiers exactly as specified by the user
- Add helpful descriptions when allowed by the API
- Apply sensible defaults for optional parameters when not specified
Always inform the user about the actions you're taking and the results received.
""",
model="gemini-2.5-pro-preview-03-25",
tools=tools
)
Step 9: Demo using ADK in a programmatic way
Creating a GitHub repo with Private visibility in debug mode
python agent-github-debug.py
Note: GitHub OpenAPI spec v3 has 1024 REST API operations, which are converted into Function tools as seen below, without any hardcoding
Step 10: Demo using ADK Web
Creating a repo and a listing of repos
adk web
GitHub Repository:
You can access all the code used in this tutorial on my GitHub:
Troubleshooting
There were four main types of issues in OpenAPI Github V3, one was that Gemini 2.5 pro was throwing an empty key value during the OpenAPIToolSet function declaration based on empty parameters or schema invalidation.
- Complex Schema Types (oneOf/anyOf/allOf): The most common problems affecting operations are users/delete-email-for-authenticated-user and issues/add-labels. These complex schemas with multiple variants are complicated for the ADK’s OpenAPIToolset.
- Schema-Example Mismatches: Cases where the schema type (e.g., “string”) doesn’t match the provided example (e.g., an object), found in operations like markdown/render-raw and actions/re-run-workflow.
- Non-JSON Content Types: Operations using content types other than application/json, like markdown/render-raw (uses text/plain and text/x-markdown) and repos/upload-release-asset.
- Parameter Schema Issues: Problems with parameter definitions using complex schema types, affecting operations like security-advisories/list-global-advisories.
Detailed description of problematic GitHub OpenSpecAPI operation listed in github_openapi_problemtic_operations.md.
Resolution
I had to remove all these 46 operations from the openAPI Spec and use the api.github.com.fixed.json
❯ python fix_github_api.py --remove-problematic 73 378 387 447 504 505 506 514 515 516 699 700 798 903 925 926
Removing problematic operations with indices: 73, 378, 387, 447, 504, 505, 506, 514, 515, 516, 699, 700, 798, 903, 925, 926
Loading GitHub API spec from: api.github.com.json
Successfully loaded API spec
Removed problematic operation: users/delete-email-for-authenticated-user (DELETE /user/emails)
Removed problematic operation: users/add-email-for-authenticated-user (POST /user/emails)
Removed problematic operation: codespaces/create-for-authenticated-user (POST /user/codespaces)
Removed problematic operation: repos/upload-release-asset (POST /repos/{owner}/{repo}/releases/{release_id}/assets)
Removed problematic operation: issues/set-labels (PUT /repos/{owner}/{repo}/issues/{issue_number}/labels)
Removed problematic operation: issues/add-labels (POST /repos/{owner}/{repo}/issues/{issue_number}/labels)
Removed problematic operation: repos/remove-team-access-restrictions (DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
Removed problematic operation: repos/set-team-access-restrictions (PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
Removed problematic operation: repos/add-team-access-restrictions (POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
Removed problematic operation: repos/remove-status-check-contexts (DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
Removed problematic operation: repos/set-status-check-contexts (PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
Removed problematic operation: repos/add-status-check-contexts (POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
Removed problematic operation: actions/review-custom-gates-for-run (POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule)
Removed problematic operation: projects/create-card (POST /projects/columns/{column_id}/cards)
Removed problematic operation: orgs/enable-or-disable-security-product-on-all-org-repos (POST /orgs/{org}/{security_product}/{enablement})
Removed problematic operation: markdown/render-raw (POST /markdown/raw)
Successfully saved modified API spec to: api.github.com.fixed.json
Removed 16 problematic operations
- users/delete-email-for-authenticated-user (DELETE /user/emails)
- users/add-email-for-authenticated-user (POST /user/emails)
- codespaces/create-for-authenticated-user (POST /user/codespaces)
- repos/upload-release-asset (POST /repos/{owner}/{repo}/releases/{release_id}/assets)
- issues/set-labels (PUT /repos/{owner}/{repo}/issues/{issue_number}/labels)
- issues/add-labels (POST /repos/{owner}/{repo}/issues/{issue_number}/labels)
- repos/remove-team-access-restrictions (DELETE /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
- repos/set-team-access-restrictions (PUT /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
- repos/add-team-access-restrictions (POST /repos/{owner}/{repo}/branches/{branch}/protection/restrictions/teams)
- repos/remove-status-check-contexts (DELETE /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
- repos/set-status-check-contexts (PUT /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
- repos/add-status-check-contexts (POST /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks/contexts)
- actions/review-custom-gates-for-run (POST /repos/{owner}/{repo}/actions/runs/{run_id}/deployment_protection_rule)
- projects/create-card (POST /projects/columns/{column_id}/cards)
- orgs/enable-or-disable-security-product-on-all-org-repos (POST /orgs/{org}/{security_product}/{enablement})
- markdown/render-raw (POST /markdown/raw)
Conclusion
In this article, we’ve demonstrated how to build a GitHub agent using Google’s Agent Development Kit (ADK) and OpenAPI Tools. By leveraging the OpenAPIToolset, we’ve transformed GitHub’s comprehensive REST API specification into thousands of callable tools without manually writing a single function definition. We can extend the same with Kubernetes OpenAPI spec and use it as Kubernetes Devops Assistant using local .kube config for cluster authentication.