DEVELOPER.md
September 10, 2026 · View on GitHub
This document provides instructions for setting up your development environment and contributing to the Toolbox project.
Prerequisites
Before you begin, ensure you have the following:
-
Databases: Set up the necessary databases for your development environment.
-
Go: Install the latest version of Go.
-
Dependencies: Download and manage project dependencies:
go get go mod tidy
Developing Toolbox
Running from Local Source
-
Configuration: Create a
tools.yamlfile to configure your sources, tools, prompts, resources, and groups. See the Configuration section in the README for details. -
CLI Flags: List available command-line flags for the Toolbox server:
go run . --help -
Running the Server: Start the Toolbox server with optional flags. The server listens on port 5000 by default.
go run . -
Testing the Endpoint: Verify the server is running by sending a request to the endpoint:
curl http://127.0.0.1:5000
Cross Compiling For Windows
Most developers work in a Unix or Unix-like environment.
Compiling for Windows requires the download of zig to provide a C and C++ compiler. These instructions are for cross compiling from Linux x86 but should work for macOS with small changes.
-
Download zig for your platform.
cd $HOME curl -fL "https://ziglang.org/download/0.15.2/zig-x86_64-linux-0.15.2.tar.xz" -o zig.tar.xz tar xf zig.tar.xzThis will create the directory $HOME/zig-x86_64-linux-0.15.2. You only need to do this once.
If you are on macOS curl from https://ziglang.org/download/0.15.2/zig-x86_64-macos-0.15.2.tar.xz or https://ziglang.org/download/0.15.2/zig-aarch64-macos-0.15.2.tar.xz.
-
Change to your MCP Toolbox directory and run the following:
GOOS=windows \ GOARCH=amd64 \ CGO_ENABLED=1 \ CC="$HOME/zig-x86_64-linux-0.15.2/zig cc -target x86_64-windows-gnu" \ CXX="$HOME/zig-x86_64-linux-0.15.2/zig c++ -target x86_64-windows-gnu" \ go build -o toolbox.exeIf you are on macOS alter the path
zig-x86_64-linux-0.15.2to the proper path for your zig installation.
Now the toolbox.exe file is ready to use. Transfer it to your windows machine and test it.
Compiling on Windows
-
Download and install the zig 0.15.2 package for windows.
-
Make sure that zig is in your path by typing
zigat the command line. You should get help data. -
Run the following commands from your mcp-toolbox folder in PowerShell.
$env:GOOS="windows" $env:GOARCH="amd64" $env:CGO_ENABLED=1 $env:CC="zig cc -target x86_64-windows-gnu" $env:CXX="zig c++ -target x86_64-windows-gnu" go build -o toolbox.exe
Tool Naming Conventions
This section details the purpose and conventions for MCP Toolbox's tools naming properties, tool name and tool type.
kind: tool
name: cancel_hotel <- tool name
type: postgres-sql <- tool type
source: my_pg_source
Tool Name
Tool name is the identifier used by a Large Language Model (LLM) to invoke a specific tool.
- Custom tools: The user can define any name they want. The below guidelines do not apply.
- Pre-built tools: The tool name is predefined and cannot be changed. It should follow the guidelines.
The following guidelines apply to tool names:
- Should use underscores over hyphens (e.g.,
list_collectionsinstead oflist-collections). - Should not have the product name in the name (e.g.,
list_collectionsinstead offirestore_list_collections). - Superficial changes are NOT considered as breaking (e.g., changing tool name).
- Non-superficial changes MAY be considered breaking (e.g. adding new parameters to a function) until they can be validated through extensive testing to ensure they do not negatively impact agent's performances.
Tool Type
Tool type serves as a category or type that a user can assign to a tool.
The following guidelines apply to tool types:
- Should use hyphens over underscores (e.g.
firestore-list-collectionsorfirestore_list_colelctions). - Should use product name in name (e.g.
firestore-list-collectionsoverlist-collections). - Changes to tool type are breaking changes and should be avoided.
Tool Invocation & Error Handling
To align with the Model Context Protocol (MCP) and ensure robust agentic workflows, Toolbox distinguishes between errors the agent can fix and errors that require developer intervention.
Error Categorization
When implementing Invoke() or ParseParams(), you must return the appropriate error type from internal/util/errors.go. This allows the LLM to attempt a "self-correct" for Agent Errors while signaling a hard stop for Server Errors.
| Category | Description | HTTP Status | MCP Result |
|---|---|---|---|
Agent Error (AgentError) | Input/Execution logic errors (e.g., SQL syntax, missing records, invalid params). The agent can fix this. | 200 OK | isError: true |
Server Error (ClientServerError) | Infrastructure failures (e.g., DB down, auth failure, network failure). The agent cannot fix this. | 500 Internal Error | JSON-RPC Error |
Implementation Guidelines
Use Typed Errors: Refactor or implement the Tool interface methods to return util.ToolboxError.
In Invoke():
- Agent Error: Wrap database driver errors (syntax, constraint violations) in
AgentError. - Server Error: Wrap connection failures or internal logic crashes in
ClientServerError.
In ParseParams():
- Return
ToolboxErrorfor missing required parameters or wrong types. - Return
ClientServerErrorfor failures in resolving authenticated parameters (e.g., invalid tokens).
Example:
func (t *MyTool) Invoke(ctx context.Context, sp tools.SourceProvider, params parameters.ParamValues, token tools.AccessToken) (any, util.ToolboxError) { res, err := t.db.Exec(ctx, params.SQL) if err != nil { // Driver error is likely a syntax issue the LLM can fix return nil, util.NewAgentError("error executing SQL query", err) } return res, nil }
Implementation Guides
Adding a New Database Source or Tool
Please create an issue before implementation to ensure we can accept the contribution and no duplicated work. This issue should include an overview of the API design. If you have any questions, reach out on our Discord to chat directly with the team.
Note
New tools can be added for pre-existing data sources. However, any new database source should also include at least one new tool type.
Important
A new source is not accepted when the database is wire-compatible with a source Toolbox already supports, since every subsequent fix would have to be re-applied to each copy. Where an existing source can be configured to connect instead, do that; new packages for protocol-compatible databases have been removed after merge on these grounds. Raise this in the issue above before implementing.
Adding a New Database Source
We recommend looking at an example source implementation.
- Create a new directory under
internal/sourcesfor your database type (e.g.,internal/sources/newdb). - Define a configuration struct for your data source in a file named
newdb.go. Create aConfigstruct to include all the necessary parameters for connecting to the database (e.g., host, port, username, password, database name) and aSourcestruct to store necessary parameters for tools (e.g., Name, Type, connection object, additional config). - Implement the
SourceConfiginterface. This interface requires two methods:SourceConfigType() string: Returns a unique string identifier for your data source (e.g.,"newdb").Initialize(ctx context.Context, tracer trace.Tracer) (Source, error): Creates a new instance of your data source and establishes a connection to the database.
- Implement the
Sourceinterface. This interface requires one method:SourceType() string: Returns the same string identifier asSourceConfigType().
- Implement
init()to register the new Source. - Implement Unit Tests in a file named
newdb_test.go.
Adding a New Tool
Note
Please follow the tool naming convention detailed here.
We recommend looking at an example tool implementation.
Remember to keep your PRs small. For example, if you are contributing a new Source, only include one or two core Tools within the same PR, the rest of the Tools can come in subsequent PRs.
-
Create a new directory under
internal/toolsfor your tool type (e.g.,internal/tools/newdb/newdbtool). -
Define a
Configstruct for your tool in a file namednewdbtool.go. Embedtools.ConfigBasewithyaml:",inline"so your tool inherits the sharedname,description,authRequired, andscopesRequiredfields (and their getters) for free. Add only the fields specific to your tool (e.g.,Type,Source,Statement,Parameters,Annotations). Do not redeclare the shared fields. -
Define a
Toolstruct that embedstools.BaseTool[Config].BaseToolprovides default implementations of most of theToolinterface —GetName,GetDescription,GetAuthRequired,GetScopesRequired,GetAnnotations,Manifest,GetParameters,Authorized,RequiresClientAuthorization,GetAuthTokenHeaderName, andEmbedParams. Do not re-declare these — eliminating that boilerplate is the entire point of embeddingBaseTool.Override an inherited method only when behavior differs from the default. For example, override
EmbedParamsto inject a vector formatter (see Vector Search below), or overrideRequiresClientAuthorization/GetAuthTokenHeaderNamefor tools that use client-side OAuth. -
Implement the
ToolConfiginterface:ToolConfigType() string: Returns a unique string identifier for your tool (e.g.,"newdb-tool").Initialize(srcs map[string]sources.Source) (tools.Tool, error): Validates the config, processes parameters, and returns yourToolconstructed viatools.NewBaseTool(cfg, annotations, manifest, staticParameters).
-
Implement only the two methods
BaseTooldoes not provide:Invoke(ctx context.Context, sp tools.SourceProvider, params parameters.ParamValues, token tools.AccessToken) (any, util.ToolboxError): Executes the operation. Return typed errors (see Error Categorization).ToConfig() tools.ToolConfig: Returns the embeddedCfg.
-
Implement
init()to register the new Tool. -
Implement Unit Tests in a file named
newdbtool_test.go. -
Implement Vector Search if your new tool supports it. You must:
- Validate that the vector embedding format can be injected successfully into your Tool's statement. If not, update
Tool.EmbedParams()to pass in a vector formatter intoparameters.EmbedParams. - Feel free to reuse existing vector formatters or create new ones.
- Add tests and documentation for vector injection and vector search. See the BigQuery SQL tool for an example.
- Validate that the vector embedding format can be injected successfully into your Tool's statement. If not, update
Adding Integration Tests
-
Add a test file under a new directory
tests/newdb. -
Add pre-defined integration test suites in the
/tests/newdb/newdb_integration_test.gothat are required to be run as long as your code contains related features. Please check each test suites for the config defaults, if your source require test suites config updates, please refer to config option:-
RunToolGetTest: tests for the
GETendpoint that returns the tool's manifest. -
RunToolInvokeTest: tests for tool calling through the native Toolbox endpoints.
-
RunMCPToolCallMethod: tests tool calling through the MCP endpoints.
-
(Optional) RunExecuteSqlToolInvokeTest: tests an
execute-sqltool for any source. Only run this test if you are adding anexecute-sqltool. -
(Optional) RunToolInvokeWithTemplateParameters: tests for template parameters. Only run this test if template parameters apply to your tool.
-
-
Add additional tests for the tools that are not covered by the predefined tests. Every tool must be tested!
-
Add the new database to the integration test workflow in integration.cloudbuild.yaml.
Adding Documentation
When updating documentation, you must adhere to the structural constraints enforced by our Diátaxis-based layout and internal linters:
- Adding a New Data Source:
- Create a new folder for your integration in the
docs/en/integrations/directory (e.g.,docs/en/integrations/newdb/). - Create an empty
_index.mdfile. This acts purely as a structural folder wrapper for Hugo. Do not add body content here. - Create a
source.mdfile. This is the definitive guide. Add all connection details, authentication, and YAML configurations here. Ensure you include the{{< list-tools >}}shortcode to dynamically display tools.
- Create a new folder for your integration in the
- Adding a New Native Tool:
- Create a nested
tools/directory inside your source (e.g.,docs/en/integrations/newdb/tools/). - Create an empty
_index.mdfile inside thetools/directory. It must contain only frontmatter and absolutely no markdown body text. - Add the tool details in a
<tool_name>.mdfile in this newtools/folder. Ensure you include the{{< compatible-sources >}}shortcode.
- Create a nested
- Adding Inherited/Shared Tools (e.g., Managed Databases):
- If a new database inherits tools from a base integration (like Cloud SQL inheriting Postgres tools), create the
tools/directory with an_index.mdfile. - Map the inherited tools dynamically by adding the
shared_toolsYAML array to the frontmatter of thistools/_index.mdfile. This file must strictly contain only frontmatter.
- If a new database inherits tools from a base integration (like Cloud SQL inheriting Postgres tools), create the
- Adding a New Resource:
- Add resource documentation in a subfolder with an
_index.mdfile withindocs/en/documentation/configuration/resources/(e.g.,docs/en/documentation/configuration/resources/<resource_type>/_index.md).
- Add resource documentation in a subfolder with an
- Adding Samples:
- Physical Location:
- Quickstarts:
docs/en/documentation/getting-started/quickstart/. - Integration-Specific:
docs/en/integrations/<db>/samples/. Must include an_index.mdwith strictly only frontmatter. - General:
docs/en/samples/.
- Quickstarts:
- Frontmatter Requirements (Maintenance): To ensure samples appear correctly in the Samples Section, you must provide the following tags:
is_sample: true- Required for indexing.- Filtering (
sample_filters): Always includesample_filtersin the frontmatter. You MUST use strict enums for filtering.- Source of Truth: Always refer to
.hugo/data/filters.yamlfor the permitted list of Data Sources, Languages, Frameworks, and Categories. All tags are validated via CI (.ci/lint-docs-sample-filters.sh). - Adding New Filters: If your sample requires a new filter that is not currently listed, add it directly to
.hugo/data/filters.yaml. You must use Title Case (capitalize the first letter of every word, with words separated by spaces). Never use snake_case or lowercase.
- Source of Truth: Always refer to
- Physical Location:
- Adding Top-Level Sections: If you add a completely new top-level documentation directory (e.g., a new section alongside
integrations,documentation), you must update the AI documentation layout files located at.hugo/layouts/index.llms.txtand.hugo/layouts/index.llms-full.txt. Specifically, update the "Diátaxis Narrative Framework" preamble so AI models understand the purpose of your new section.
Adding Prebuilt Tools
You can provide developers with a set of "build-time" tools to aid common software development user journeys like viewing and creating tables/collections and data.
- Create a set of prebuilt tools by defining a new
tools.yamland adding it tointernal/tools. Make sure the file name matches the source (i.e. for source "alloydb-postgres" create a file named "alloydb-postgres.yaml"). - Update
cmd/root.goto add new source to theprebuiltflag. - Add tests in internal/prebuiltconfigs/prebuiltconfigs_test.go and cmd/root_test.go.
Adding Prebuilt Config Evals
Integration tests check that a tool works when called directly. Evals check something different: that an agent handed the prebuilt config can pick the right tools and complete a realistic task. Because the agent and model are pinned, what a run measures is the config — its tool set, and how well each tool and parameter description reads as a prompt.
Runs are orchestrated by EvalBench,
which launches a coding agent that starts Toolbox as an MCP server over stdio.
Contributions live under evals/:
evalsets/<prebuilt>.json— the scenarios for one prebuilt config: a prompt, and theexpected_trajectoryof tool names it should produce. Multi-turn scenarios are played out by a simulated user model. Trajectory names are canonicalized astoolbox__<tool_name>, so one evalset serves every harness.model_configs/<harness>.yaml— one per agent (e.g.claude_cli,gemini_cli), describing how to launch it and how it starts Toolbox. Credentials are read from the environment, never written into these files.
To cover a new prebuilt config:
- Add an evalset at
evals/evalsets/<prebuilt>.json. Prefer tasks that need more than one tool call, and check every name inexpected_trajectoryagainst the prebuilt config ininternal/prebuiltconfigs/tools/. - Add a step to evals.cloudbuild.yaml with the
config's
TOOLBOX_PREBUILT,EVAL_DATASET, and connection settings.EVAL_ENV_PREFIXnames the prefix those settings share, which is how run_evals.sh knows which ones to require. SetEVAL_HARNESSESto run more than the default harness, andallowFailure: trueso the step's failure does not cancel the other databases. On a pull request the step runs when its evalset or its prebuilt config changed; both paths are derived from the settings above, so there is nothing else to configure.
Evals call real models against live infrastructure, so they are neither free nor
deterministic, and they are not part of the pull request gate. Like integration
tests, they need credentials a contributor's pull request cannot supply, so a
maintainer runs them by applying the evals: run label and commenting
/gcbrun; an evalset that has not been run is not a blocker.
To run them yourself, follow EvalBench's own setup, then copy evals/ into your
EvalBench checkout and start the run from there — it resolves the paths in
evals/run_configs/toolbox.yaml against its own working directory. The
environment that config expects is the one
evals.cloudbuild.yaml builds for each step.
Deprecating an Existing Primitive
A primitive (e.g., sources, tools, auth services) will only be removed after it has been marked as deprecated for at least one major version, or four minor versions (approximately two months, given our biweekly release cadence).
To mark a primitive as deprecated, you must add our deprecation helper function to the initialization of the primitive.
During the next major version release, any primitive that meets these deprecation timeframe requirements will be permanently removed.
Testing
Infrastructure
Toolbox uses both GitHub Actions and Cloud Build to run test workflows. Cloud Build is used when Google credentials are required. Cloud Build uses test project "toolbox-testing-438616".
Evals for the prebuilt configs run separately from the test workflows, on their own Cloud Build config. See Adding Prebuilt Config Evals.
Linting
Code Linting
Run the lint check to ensure code quality:
golangci-lint run --fix
Documentation Structure Linting
To ensure consistency, we enforce a standardized structure for integration Source and Tool pages.
Before pushing changes to integration pages:
Run the source page linter to validate:
# From the repository root
./.ci/lint-docs-source-page.sh
Run the tool page linter to validate:
# From the repository root
./.ci/lint-docs-tool-page.sh
Run the sample filters linter to validate frontmatter tags:
# From the repository root
bash .ci/lint-docs-sample-filters.sh
### Unit Tests
Execute unit tests locally:
```bash
go test -race -v ./cmd/... ./internal/...
Integration Tests
Running Locally
-
Environment Variables: Set the required environment variables. Refer to the Cloud Build testing configuration for a complete list of variables for each source.
SERVICE_ACCOUNT_EMAIL: Use your own GCP email.CLIENT_ID: Use the Google Cloud SDK application Client ID. Contact Toolbox maintainers if you don't have it.
-
Running Tests: Run the integration test for your target source. Specify the required Go build tags at the top of each integration test file.
go test -race -v ./tests/<YOUR_TEST_DIR>For example, to run the AlloyDB integration test:
go test -race -v ./tests/alloydbpg -
Timeout: The integration test should have a timeout on the server. Look for code like this:
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...) if err != nil { t.Fatalf("command initialization returned an error: %s", err) } defer cleanup()Be sure to set the timeout to a reasonable value for your tests.
Running on Pull Requests
- Internal Contributors: Testing workflows should trigger automatically.
- External Contributors: Request Toolbox maintainers to trigger the testing
workflows on your PR.
- Maintainers can comment
/gcbrunto execute the integration tests. - Maintainers can add the label
tests:runto execute the unit tests. - Maintainers can add the label
docs: deploy-previewto run the PR Preview workflow.
- Maintainers can comment
Test Resources
The following databases have been added as test resources. To add a new database to test against, please contact the Toolbox maintainer team via an issue or PR. Refer to the Cloud Build testing configuration for a complete list of variables for each source.
- AlloyDB - setup in the test project
- AI Natural Language (setup
instructions)
has been configured for
alloydb-ai-nltool tests - The Cloud Build service account is a user
- AI Natural Language (setup
instructions)
has been configured for
- Bigtable - setup in the test project
- The Cloud Build service account is a user
- BigQuery - setup in the test project
- The Cloud Build service account is a user
- Cloud SQL Postgres - setup in the test project
- The Cloud Build service account is a user
- Cloud SQL MySQL - setup in the test project
- The Cloud Build service account is a user
- Cloud SQL SQL Server - setup in the test project
- The Cloud Build service account is a user
- Couchbase - setup in the test project via the Marketplace
- DGraph - using the public dgraph interface https://play.dgraph.io for testing
- Looker
- The Cloud Build service account is a user for conversational analytics
- The Looker instance runs under google.com:looker-sandbox.
- Memorystore Redis - setup in the test project using a Memorystore for Redis
standalone instance
- Memorystore Redis Cluster, Memorystore Valkey standalone, and Memorystore Valkey Cluster instances all require PSC connections, which requires extra security setup to connect from Cloud Build. Memorystore Redis standalone is the only one allowing PSA connection.
- The Cloud Build service account is a user
- Memorystore Valkey - setup in the test project using a Memorystore for Redis
standalone instance
- The Cloud Build service account is a user
- MySQL - setup in the test project using a Cloud SQL instance
- Neo4j - setup in the test project on a GCE VM
- Postgres - setup in the test project using an AlloyDB instance
- Spanner - setup in the test project
- The Cloud Build service account is a user
- SQL Server - setup in the test project using a Cloud SQL instance
- SQLite - setup in the integration test, where we create a temporary database file
Link Checking and Fixing with Lychee
We use lychee for repository link checks.
- To run the checker locally, see the command-line usage guide.
Fixing Broken Links
-
Update the Link: Correct the broken URL or update the content where it is used.
-
Ignore the Link: If you can't fix the link (e.g., due to external rate-limits or if it's a local-only URL), tell Lychee to ignore it.
- List regular expressions or direct links in the .lycheeignore file, one entry per line.
- Always add a comment explaining why the link is being skipped to prevent link rot. Example
.lycheeignore:# These are email addresses, not standard web URLs, and usually cause check failures. ^mailto:.*
Note
To avoid build failures in GitHub Actions, follow the linking pattern demonstrated here:
Avoid: (Works in Hugo, breaks Link Checker): [Read more](docs/setup) or [Read more](docs/setup/)
Reason: The link checker cannot find a file named "setup" or a directory with that name containing an index.
Preferred: [Read more](docs/setup.md)
Reason: The GitHub Action finds the physical file. Hugo then uses its internal logic (or render hooks) to resolve this to the correct /docs/setup/ web URL.
Other GitHub Checks
- License header check (
.github/header-checker-lint.yml) - Ensures files have the appropriate license - CLA/google - Ensures the developer has signed the CLA: https://cla.developers.google.com/
- conventionalcommits.org - Ensures the commit messages are in the correct format. This repository uses tool Release Please to create GitHub releases. It does so by parsing your git history, looking for Conventional Commit messages, and creating release PRs. Learn more by reading How should I write my commits?
Developing Documentation
Documentation Standards & CI Checks
To maintain consistency and prevent repository bloat, all pull requests must pass the automated documentation linters.
Source Page Structure (integrations/**/source.md)
When adding or updating a Source page, your markdown file must strictly adhere to the following architectural rules:
- File Name: The configuration guide must be named
source.md. (Note:_index.mdfiles are purely structural folder wrappers. Do not add body content to them). - LinkTitle: The linkTitle has to be set to the string
Sourcealways. - Frontmatter: The
titlefield must end with the word "Source" (e.g.,title: "Firestore Source"). - No H1 Headings: Do not use H1 (
#) tags in the markdown body. The page title is automatically generated from the frontmatter. - H2 Heading Hierarchy: You must use H2 (
##) headings in a strict, specific order.- Required Headings:
About,Example,Reference - Allowed Optional Headings:
Available Tools,Requirements,Advanced Usage,Troubleshooting,Additional Resources
- Required Headings:
- Available Tools Shortcode: If you include the
## Available Toolsheading, you must place the list-tools shortcode (e.g.,{{< list-tools >}}) directly beneath it.
Tool Page Structure (integrations/**/tools/*.md)
When adding or updating a Tool page, your markdown file must strictly adhere to the following architectural rules:
- Location: Native tools must be placed inside a nested
tools/directory. - No H1 Headings: Do not use H1 (
#) tags in the markdown body. The page title is automatically generated from the frontmatter. - H2 Heading Hierarchy: You must use H2 (
##) headings in a strict, specific order.- Required Headings:
About,Example - Allowed Optional Headings:
Compatible Sources,Requirements,Parameters,Output Format,Reference,Advanced Usage,Troubleshooting,Additional Resources
- Required Headings:
- Compatible Sources Shortcode: If you include the
## Compatible Sourcesheading, you must place the compatible-sources shortcode (e.g.,{{< compatible-sources >}}) directly beneath it.
Prebuilt Configuration Structure (integrations/**/prebuilt-configs/*.md)
To ensure new prebuilt configurations are automatically indexed by the {{< list-prebuilt-configs >}} shortcode on the main Prebuilt Configs page, follow these rules:
- Location: Always place documentation for prebuilt configurations in a nested directory named
prebuilt-configs/inside the database folder (e.g.,docs/en/integrations/alloydb/prebuilt-configs/). - Index Wrapper: Every
prebuilt-configs/directory must contain an_index.mdfile. This file acts as the anchor for the directory and must contain thetitleanddescriptionused in the automated lists. - Architecture-Based Mapping: Map configurations to database folders based on the
kinddefined in the tool's YAML file (ininternal/prebuiltconfigs/tools/). For example, any tool using thepostgreskind should live in thepostgres/integration directory.
Frontend Assets & Layouts
If you need to modify the visual appearance, navigation, or behavior of the documentation website itself, all frontend assets are isolated within the .hugo/ directory.
Repository Asset Limits
- Max File Size: No individual file within the
docs/directory may exceed 24MB. This prevents repository bloat and ensures fast clone times. If you need to include large assets (like high-resolution videos or massive PDFs), host them externally and link to them in the markdown.
Running a Local Hugo Server
Follow these steps to preview documentation changes locally using a Hugo server:
-
Install Hugo: Ensure you have Hugo extended edition version 0.146.0 or later installed.
-
Navigate to the Hugo Directory:
cd .hugo -
Install Dependencies:
npm ci -
Generate Search Index & Start the Server: Because the Pagefind search engine requires physical files to build its index,
hugo server(which runs purely in memory) will not display search results by default. To test the search bar locally, build the physical site once (using the development environment to avoid triggering production analytics), generate the index into the static folder, and then start the server:hugo --environment development npx pagefind --site public --output-path static/pagefind hugo server(Note: The
static/pagefind/directory is git-ignored to prevent committing local search indexes).
Previewing Documentation on Pull Requests
Documentation preview links are automatically generated and commented on your pull request when working from a branch within the main repository.
For external contributors (forks): For security reasons, automated deployment previews are disabled for pull requests originating from external forks for the cloudflare deployments. To review your documentation changes, please follow the Running a Local Hugo Server instructions to build and view the site on your local machine before requesting a review.
Document Versioning Setup
The documentation uses a dynamic versioning system that outputs standard HTML sites alongside AI-optimized plain text files (llms.txt and llms-full.txt).
Search Indexing: All deployment workflows automatically execute npx pagefind --site public to generate a version-scoped search index specific to that deployment's base URL.
There are 3 GHA workflows we use to achieve document versioning:
-
Deploy In-development docs: This workflow is run on every commit merged into the main branch. It deploys the built site to the
/dev/subdirectory for the in-development documentation. -
Deploy Versioned Docs: When a new GitHub Release is published, it performs two deployments based on the new release tag. One to the new version subdirectory and one to the root directory of the cloudflare-pages branch.
Note: Adding the new version to
hugo.tomlbefore merging the release PR is a maintainer release step — see the Maintainer Playbook. -
Deploy Previous Version Docs: This is a manual workflow, started from the GitHub Actions UI. To rebuild and redeploy documentation for an already released version that were released before this new system was in place. This workflow can be started on the UI by providing the git version tag which you want to create the documentation for. The specific versioned subdirectory and the root docs are updated on the cloudflare-pages branch.
Contributors
Request a repo owner to run the preview deployment workflow on your PR. A preview link will be automatically added as a comment to your PR.
Maintainers
Deploying a documentation preview is a maintainer action — see Deploying Documentation Previews in the Maintainer Playbook.
Shortcodes
This repository includes custom shortcodes to help with documentation consistency and maintenance. For more information on how they work, see the Hugo Shortcodes documentation and the guide to creating custom shortcodes.
include Shortcode
The include shortcode reads a file and optionally fences it with a language.
Syntax:
{{< include "path/to/file" "language" >}}
Example:
{{< include "static/headers/license_header.txt" >}}
{{< include "samples/program.js" "javascript" >}}
Source: .hugo/layouts/shortcodes/include.html
regionInclude Shortcode
The regionInclude shortcode reads a file, extracts content between [START region_name] and [END region_name], and optionally fences it.
Syntax:
{{< regionInclude "path/to/file" "region_name" "language" >}}
Example Markdown:
{{< regionInclude "samples/program.js" "program_setup" "javascript" >}}
Example Code Snippet (samples/program.js):
// [START program_setup]
import { Toolbox } from '@googleapis/mcp-toolbox';
const toolbox = new Toolbox();
// [END program_setup]
Source: .hugo/layouts/shortcodes/regionInclude.html
Building Toolbox
Building the Binary
-
Build Command: Compile the Toolbox binary:
go build -o toolbox -
Running the Binary: Execute the compiled binary with optional flags. The server listens on port 5000 by default:
./toolbox -
Testing the Endpoint: Verify the server is running by sending a request to the endpoint:
curl http://127.0.0.1:5000
Building Container Images
-
Build Command: Build the Toolbox container image:
docker build -t toolbox:dev . -
View Image: List available Docker images to confirm the build:
docker images -
Run Container: Run the Toolbox container image using Docker:
docker run -d toolbox:dev
Developing Toolbox SDKs
Refer to the SDK developer guide for instructions on developing Toolbox SDKs.
Maintainer Information
Maintainer processes — the team/CODEOWNERS setup, issue triage and SLOs, releasing (versioned, continuous, npm/PyPI), CI/test automation, and repo setup — are documented in the Maintainer Playbook.