#
tokens: 46615/50000 10/816 files (page 26/48)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 26 of 48. Use http://codebase.md/googleapis/genai-toolbox?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .ci
│   ├── continuous.release.cloudbuild.yaml
│   ├── generate_release_table.sh
│   ├── integration.cloudbuild.yaml
│   ├── quickstart_test
│   │   ├── go.integration.cloudbuild.yaml
│   │   ├── js.integration.cloudbuild.yaml
│   │   ├── py.integration.cloudbuild.yaml
│   │   ├── run_go_tests.sh
│   │   ├── run_js_tests.sh
│   │   ├── run_py_tests.sh
│   │   └── setup_hotels_sample.sql
│   ├── test_with_coverage.sh
│   └── versioned.release.cloudbuild.yaml
├── .github
│   ├── auto-label.yaml
│   ├── blunderbuss.yml
│   ├── CODEOWNERS
│   ├── header-checker-lint.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   ├── feature_request.yml
│   │   └── question.yml
│   ├── label-sync.yml
│   ├── labels.yaml
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── release-please.yml
│   ├── renovate.json5
│   ├── sync-repo-settings.yaml
│   └── workflows
│       ├── cloud_build_failure_reporter.yml
│       ├── deploy_dev_docs.yaml
│       ├── deploy_previous_version_docs.yaml
│       ├── deploy_versioned_docs.yaml
│       ├── docs_deploy.yaml
│       ├── docs_preview_clean.yaml
│       ├── docs_preview_deploy.yaml
│       ├── lint.yaml
│       ├── schedule_reporter.yml
│       ├── sync-labels.yaml
│       └── tests.yaml
├── .gitignore
├── .gitmodules
├── .golangci.yaml
├── .hugo
│   ├── archetypes
│   │   └── default.md
│   ├── assets
│   │   ├── icons
│   │   │   └── logo.svg
│   │   └── scss
│   │       ├── _styles_project.scss
│   │       └── _variables_project.scss
│   ├── go.mod
│   ├── go.sum
│   ├── hugo.toml
│   ├── layouts
│   │   ├── _default
│   │   │   └── home.releases.releases
│   │   ├── index.llms-full.txt
│   │   ├── index.llms.txt
│   │   ├── partials
│   │   │   ├── hooks
│   │   │   │   └── head-end.html
│   │   │   ├── navbar-version-selector.html
│   │   │   ├── page-meta-links.html
│   │   │   └── td
│   │   │       └── render-heading.html
│   │   ├── robot.txt
│   │   └── shortcodes
│   │       ├── include.html
│   │       ├── ipynb.html
│   │       └── regionInclude.html
│   ├── package-lock.json
│   ├── package.json
│   └── static
│       ├── favicons
│       │   ├── android-chrome-192x192.png
│       │   ├── android-chrome-512x512.png
│       │   ├── apple-touch-icon.png
│       │   ├── favicon-16x16.png
│       │   ├── favicon-32x32.png
│       │   └── favicon.ico
│       └── js
│           └── w3.js
├── CHANGELOG.md
├── cmd
│   ├── options_test.go
│   ├── options.go
│   ├── root_test.go
│   ├── root.go
│   └── version.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DEVELOPER.md
├── Dockerfile
├── docs
│   └── en
│       ├── _index.md
│       ├── about
│       │   ├── _index.md
│       │   └── faq.md
│       ├── concepts
│       │   ├── _index.md
│       │   └── telemetry
│       │       ├── index.md
│       │       ├── telemetry_flow.png
│       │       └── telemetry_traces.png
│       ├── getting-started
│       │   ├── _index.md
│       │   ├── colab_quickstart.ipynb
│       │   ├── configure.md
│       │   ├── introduction
│       │   │   ├── _index.md
│       │   │   └── architecture.png
│       │   ├── local_quickstart_go.md
│       │   ├── local_quickstart_js.md
│       │   ├── local_quickstart.md
│       │   ├── mcp_quickstart
│       │   │   ├── _index.md
│       │   │   ├── inspector_tools.png
│       │   │   └── inspector.png
│       │   └── quickstart
│       │       ├── go
│       │       │   ├── genAI
│       │       │   │   ├── go.mod
│       │       │   │   ├── go.sum
│       │       │   │   └── quickstart.go
│       │       │   ├── genkit
│       │       │   │   ├── go.mod
│       │       │   │   ├── go.sum
│       │       │   │   └── quickstart.go
│       │       │   ├── langchain
│       │       │   │   ├── go.mod
│       │       │   │   ├── go.sum
│       │       │   │   └── quickstart.go
│       │       │   ├── openAI
│       │       │   │   ├── go.mod
│       │       │   │   ├── go.sum
│       │       │   │   └── quickstart.go
│       │       │   └── quickstart_test.go
│       │       ├── golden.txt
│       │       ├── js
│       │       │   ├── genAI
│       │       │   │   ├── package-lock.json
│       │       │   │   ├── package.json
│       │       │   │   └── quickstart.js
│       │       │   ├── genkit
│       │       │   │   ├── package-lock.json
│       │       │   │   ├── package.json
│       │       │   │   └── quickstart.js
│       │       │   ├── langchain
│       │       │   │   ├── package-lock.json
│       │       │   │   ├── package.json
│       │       │   │   └── quickstart.js
│       │       │   ├── llamaindex
│       │       │   │   ├── package-lock.json
│       │       │   │   ├── package.json
│       │       │   │   └── quickstart.js
│       │       │   └── quickstart.test.js
│       │       ├── python
│       │       │   ├── __init__.py
│       │       │   ├── adk
│       │       │   │   ├── quickstart.py
│       │       │   │   └── requirements.txt
│       │       │   ├── core
│       │       │   │   ├── quickstart.py
│       │       │   │   └── requirements.txt
│       │       │   ├── langchain
│       │       │   │   ├── quickstart.py
│       │       │   │   └── requirements.txt
│       │       │   ├── llamaindex
│       │       │   │   ├── quickstart.py
│       │       │   │   └── requirements.txt
│       │       │   └── quickstart_test.py
│       │       └── shared
│       │           ├── cloud_setup.md
│       │           ├── configure_toolbox.md
│       │           └── database_setup.md
│       ├── how-to
│       │   ├── _index.md
│       │   ├── connect_via_geminicli.md
│       │   ├── connect_via_mcp.md
│       │   ├── connect-ide
│       │   │   ├── _index.md
│       │   │   ├── alloydb_pg_admin_mcp.md
│       │   │   ├── alloydb_pg_mcp.md
│       │   │   ├── bigquery_mcp.md
│       │   │   ├── cloud_sql_mssql_admin_mcp.md
│       │   │   ├── cloud_sql_mssql_mcp.md
│       │   │   ├── cloud_sql_mysql_admin_mcp.md
│       │   │   ├── cloud_sql_mysql_mcp.md
│       │   │   ├── cloud_sql_pg_admin_mcp.md
│       │   │   ├── cloud_sql_pg_mcp.md
│       │   │   ├── firestore_mcp.md
│       │   │   ├── looker_mcp.md
│       │   │   ├── mssql_mcp.md
│       │   │   ├── mysql_mcp.md
│       │   │   ├── neo4j_mcp.md
│       │   │   ├── postgres_mcp.md
│       │   │   ├── spanner_mcp.md
│       │   │   └── sqlite_mcp.md
│       │   ├── deploy_docker.md
│       │   ├── deploy_gke.md
│       │   ├── deploy_toolbox.md
│       │   ├── export_telemetry.md
│       │   └── toolbox-ui
│       │       ├── edit-headers.gif
│       │       ├── edit-headers.png
│       │       ├── index.md
│       │       ├── optional-param-checked.png
│       │       ├── optional-param-unchecked.png
│       │       ├── run-tool.gif
│       │       ├── tools.png
│       │       └── toolsets.png
│       ├── reference
│       │   ├── _index.md
│       │   ├── cli.md
│       │   └── prebuilt-tools.md
│       ├── resources
│       │   ├── _index.md
│       │   ├── authServices
│       │   │   ├── _index.md
│       │   │   └── google.md
│       │   ├── sources
│       │   │   ├── _index.md
│       │   │   ├── alloydb-admin.md
│       │   │   ├── alloydb-pg.md
│       │   │   ├── bigquery.md
│       │   │   ├── bigtable.md
│       │   │   ├── cassandra.md
│       │   │   ├── clickhouse.md
│       │   │   ├── cloud-monitoring.md
│       │   │   ├── cloud-sql-admin.md
│       │   │   ├── cloud-sql-mssql.md
│       │   │   ├── cloud-sql-mysql.md
│       │   │   ├── cloud-sql-pg.md
│       │   │   ├── couchbase.md
│       │   │   ├── dataplex.md
│       │   │   ├── dgraph.md
│       │   │   ├── firebird.md
│       │   │   ├── firestore.md
│       │   │   ├── http.md
│       │   │   ├── looker.md
│       │   │   ├── mongodb.md
│       │   │   ├── mssql.md
│       │   │   ├── mysql.md
│       │   │   ├── neo4j.md
│       │   │   ├── oceanbase.md
│       │   │   ├── oracle.md
│       │   │   ├── postgres.md
│       │   │   ├── redis.md
│       │   │   ├── serverless-spark.md
│       │   │   ├── spanner.md
│       │   │   ├── sqlite.md
│       │   │   ├── tidb.md
│       │   │   ├── trino.md
│       │   │   ├── valkey.md
│       │   │   └── yugabytedb.md
│       │   └── tools
│       │       ├── _index.md
│       │       ├── alloydb
│       │       │   ├── _index.md
│       │       │   ├── alloydb-create-cluster.md
│       │       │   ├── alloydb-create-instance.md
│       │       │   ├── alloydb-create-user.md
│       │       │   ├── alloydb-get-cluster.md
│       │       │   ├── alloydb-get-instance.md
│       │       │   ├── alloydb-get-user.md
│       │       │   ├── alloydb-list-clusters.md
│       │       │   ├── alloydb-list-instances.md
│       │       │   ├── alloydb-list-users.md
│       │       │   └── alloydb-wait-for-operation.md
│       │       ├── alloydbainl
│       │       │   ├── _index.md
│       │       │   └── alloydb-ai-nl.md
│       │       ├── bigquery
│       │       │   ├── _index.md
│       │       │   ├── bigquery-analyze-contribution.md
│       │       │   ├── bigquery-conversational-analytics.md
│       │       │   ├── bigquery-execute-sql.md
│       │       │   ├── bigquery-forecast.md
│       │       │   ├── bigquery-get-dataset-info.md
│       │       │   ├── bigquery-get-table-info.md
│       │       │   ├── bigquery-list-dataset-ids.md
│       │       │   ├── bigquery-list-table-ids.md
│       │       │   ├── bigquery-search-catalog.md
│       │       │   └── bigquery-sql.md
│       │       ├── bigtable
│       │       │   ├── _index.md
│       │       │   └── bigtable-sql.md
│       │       ├── cassandra
│       │       │   ├── _index.md
│       │       │   └── cassandra-cql.md
│       │       ├── clickhouse
│       │       │   ├── _index.md
│       │       │   ├── clickhouse-execute-sql.md
│       │       │   ├── clickhouse-list-databases.md
│       │       │   ├── clickhouse-list-tables.md
│       │       │   └── clickhouse-sql.md
│       │       ├── cloudmonitoring
│       │       │   ├── _index.md
│       │       │   └── cloud-monitoring-query-prometheus.md
│       │       ├── cloudsql
│       │       │   ├── _index.md
│       │       │   ├── cloudsqlcreatedatabase.md
│       │       │   ├── cloudsqlcreateusers.md
│       │       │   ├── cloudsqlgetinstances.md
│       │       │   ├── cloudsqllistdatabases.md
│       │       │   ├── cloudsqllistinstances.md
│       │       │   ├── cloudsqlmssqlcreateinstance.md
│       │       │   ├── cloudsqlmysqlcreateinstance.md
│       │       │   ├── cloudsqlpgcreateinstances.md
│       │       │   └── cloudsqlwaitforoperation.md
│       │       ├── couchbase
│       │       │   ├── _index.md
│       │       │   └── couchbase-sql.md
│       │       ├── dataform
│       │       │   ├── _index.md
│       │       │   └── dataform-compile-local.md
│       │       ├── dataplex
│       │       │   ├── _index.md
│       │       │   ├── dataplex-lookup-entry.md
│       │       │   ├── dataplex-search-aspect-types.md
│       │       │   └── dataplex-search-entries.md
│       │       ├── dgraph
│       │       │   ├── _index.md
│       │       │   └── dgraph-dql.md
│       │       ├── firebird
│       │       │   ├── _index.md
│       │       │   ├── firebird-execute-sql.md
│       │       │   └── firebird-sql.md
│       │       ├── firestore
│       │       │   ├── _index.md
│       │       │   ├── firestore-add-documents.md
│       │       │   ├── firestore-delete-documents.md
│       │       │   ├── firestore-get-documents.md
│       │       │   ├── firestore-get-rules.md
│       │       │   ├── firestore-list-collections.md
│       │       │   ├── firestore-query-collection.md
│       │       │   ├── firestore-query.md
│       │       │   ├── firestore-update-document.md
│       │       │   └── firestore-validate-rules.md
│       │       ├── http
│       │       │   ├── _index.md
│       │       │   └── http.md
│       │       ├── looker
│       │       │   ├── _index.md
│       │       │   ├── looker-add-dashboard-element.md
│       │       │   ├── looker-conversational-analytics.md
│       │       │   ├── looker-create-project-file.md
│       │       │   ├── looker-delete-project-file.md
│       │       │   ├── looker-dev-mode.md
│       │       │   ├── looker-get-dashboards.md
│       │       │   ├── looker-get-dimensions.md
│       │       │   ├── looker-get-explores.md
│       │       │   ├── looker-get-filters.md
│       │       │   ├── looker-get-looks.md
│       │       │   ├── looker-get-measures.md
│       │       │   ├── looker-get-models.md
│       │       │   ├── looker-get-parameters.md
│       │       │   ├── looker-get-project-file.md
│       │       │   ├── looker-get-project-files.md
│       │       │   ├── looker-get-projects.md
│       │       │   ├── looker-health-analyze.md
│       │       │   ├── looker-health-pulse.md
│       │       │   ├── looker-health-vacuum.md
│       │       │   ├── looker-make-dashboard.md
│       │       │   ├── looker-make-look.md
│       │       │   ├── looker-query-sql.md
│       │       │   ├── looker-query-url.md
│       │       │   ├── looker-query.md
│       │       │   ├── looker-run-look.md
│       │       │   └── looker-update-project-file.md
│       │       ├── mongodb
│       │       │   ├── _index.md
│       │       │   ├── mongodb-aggregate.md
│       │       │   ├── mongodb-delete-many.md
│       │       │   ├── mongodb-delete-one.md
│       │       │   ├── mongodb-find-one.md
│       │       │   ├── mongodb-find.md
│       │       │   ├── mongodb-insert-many.md
│       │       │   ├── mongodb-insert-one.md
│       │       │   ├── mongodb-update-many.md
│       │       │   └── mongodb-update-one.md
│       │       ├── mssql
│       │       │   ├── _index.md
│       │       │   ├── mssql-execute-sql.md
│       │       │   ├── mssql-list-tables.md
│       │       │   └── mssql-sql.md
│       │       ├── mysql
│       │       │   ├── _index.md
│       │       │   ├── mysql-execute-sql.md
│       │       │   ├── mysql-list-active-queries.md
│       │       │   ├── mysql-list-table-fragmentation.md
│       │       │   ├── mysql-list-tables-missing-unique-indexes.md
│       │       │   ├── mysql-list-tables.md
│       │       │   └── mysql-sql.md
│       │       ├── neo4j
│       │       │   ├── _index.md
│       │       │   ├── neo4j-cypher.md
│       │       │   ├── neo4j-execute-cypher.md
│       │       │   └── neo4j-schema.md
│       │       ├── oceanbase
│       │       │   ├── _index.md
│       │       │   ├── oceanbase-execute-sql.md
│       │       │   └── oceanbase-sql.md
│       │       ├── oracle
│       │       │   ├── _index.md
│       │       │   ├── oracle-execute-sql.md
│       │       │   └── oracle-sql.md
│       │       ├── postgres
│       │       │   ├── _index.md
│       │       │   ├── postgres-execute-sql.md
│       │       │   ├── postgres-list-active-queries.md
│       │       │   ├── postgres-list-available-extensions.md
│       │       │   ├── postgres-list-installed-extensions.md
│       │       │   ├── postgres-list-tables.md
│       │       │   └── postgres-sql.md
│       │       ├── redis
│       │       │   ├── _index.md
│       │       │   └── redis.md
│       │       ├── serverless-spark
│       │       │   ├── _index.md
│       │       │   └── serverless-spark-list-batches.md
│       │       ├── spanner
│       │       │   ├── _index.md
│       │       │   ├── spanner-execute-sql.md
│       │       │   ├── spanner-list-tables.md
│       │       │   └── spanner-sql.md
│       │       ├── sqlite
│       │       │   ├── _index.md
│       │       │   ├── sqlite-execute-sql.md
│       │       │   └── sqlite-sql.md
│       │       ├── tidb
│       │       │   ├── _index.md
│       │       │   ├── tidb-execute-sql.md
│       │       │   └── tidb-sql.md
│       │       ├── trino
│       │       │   ├── _index.md
│       │       │   ├── trino-execute-sql.md
│       │       │   └── trino-sql.md
│       │       ├── utility
│       │       │   ├── _index.md
│       │       │   └── wait.md
│       │       ├── valkey
│       │       │   ├── _index.md
│       │       │   └── valkey.md
│       │       └── yuagbytedb
│       │           ├── _index.md
│       │           └── yugabytedb-sql.md
│       ├── samples
│       │   ├── _index.md
│       │   ├── alloydb
│       │   │   ├── _index.md
│       │   │   ├── ai-nl
│       │   │   │   ├── alloydb_ai_nl.ipynb
│       │   │   │   └── index.md
│       │   │   └── mcp_quickstart.md
│       │   ├── bigquery
│       │   │   ├── _index.md
│       │   │   ├── colab_quickstart_bigquery.ipynb
│       │   │   ├── local_quickstart.md
│       │   │   └── mcp_quickstart
│       │   │       ├── _index.md
│       │   │       ├── inspector_tools.png
│       │   │       └── inspector.png
│       │   └── looker
│       │       ├── _index.md
│       │       ├── looker_gemini_oauth
│       │       │   ├── _index.md
│       │       │   ├── authenticated.png
│       │       │   ├── authorize.png
│       │       │   └── registration.png
│       │       ├── looker_gemini.md
│       │       └── looker_mcp_inspector
│       │           ├── _index.md
│       │           ├── inspector_tools.png
│       │           └── inspector.png
│       └── sdks
│           ├── _index.md
│           ├── go-sdk.md
│           ├── js-sdk.md
│           └── python-sdk.md
├── gemini-extension.json
├── go.mod
├── go.sum
├── internal
│   ├── auth
│   │   ├── auth.go
│   │   └── google
│   │       └── google.go
│   ├── log
│   │   ├── handler.go
│   │   ├── log_test.go
│   │   ├── log.go
│   │   └── logger.go
│   ├── prebuiltconfigs
│   │   ├── prebuiltconfigs_test.go
│   │   ├── prebuiltconfigs.go
│   │   └── tools
│   │       ├── alloydb-postgres-admin.yaml
│   │       ├── alloydb-postgres-observability.yaml
│   │       ├── alloydb-postgres.yaml
│   │       ├── bigquery.yaml
│   │       ├── clickhouse.yaml
│   │       ├── cloud-sql-mssql-admin.yaml
│   │       ├── cloud-sql-mssql-observability.yaml
│   │       ├── cloud-sql-mssql.yaml
│   │       ├── cloud-sql-mysql-admin.yaml
│   │       ├── cloud-sql-mysql-observability.yaml
│   │       ├── cloud-sql-mysql.yaml
│   │       ├── cloud-sql-postgres-admin.yaml
│   │       ├── cloud-sql-postgres-observability.yaml
│   │       ├── cloud-sql-postgres.yaml
│   │       ├── dataplex.yaml
│   │       ├── firestore.yaml
│   │       ├── looker-conversational-analytics.yaml
│   │       ├── looker.yaml
│   │       ├── mssql.yaml
│   │       ├── mysql.yaml
│   │       ├── neo4j.yaml
│   │       ├── oceanbase.yaml
│   │       ├── postgres.yaml
│   │       ├── serverless-spark.yaml
│   │       ├── spanner-postgres.yaml
│   │       ├── spanner.yaml
│   │       └── sqlite.yaml
│   ├── server
│   │   ├── api_test.go
│   │   ├── api.go
│   │   ├── common_test.go
│   │   ├── config.go
│   │   ├── mcp
│   │   │   ├── jsonrpc
│   │   │   │   ├── jsonrpc_test.go
│   │   │   │   └── jsonrpc.go
│   │   │   ├── mcp.go
│   │   │   ├── util
│   │   │   │   └── lifecycle.go
│   │   │   ├── v20241105
│   │   │   │   ├── method.go
│   │   │   │   └── types.go
│   │   │   ├── v20250326
│   │   │   │   ├── method.go
│   │   │   │   └── types.go
│   │   │   └── v20250618
│   │   │       ├── method.go
│   │   │       └── types.go
│   │   ├── mcp_test.go
│   │   ├── mcp.go
│   │   ├── server_test.go
│   │   ├── server.go
│   │   ├── static
│   │   │   ├── assets
│   │   │   │   └── mcptoolboxlogo.png
│   │   │   ├── css
│   │   │   │   └── style.css
│   │   │   ├── index.html
│   │   │   ├── js
│   │   │   │   ├── auth.js
│   │   │   │   ├── loadTools.js
│   │   │   │   ├── mainContent.js
│   │   │   │   ├── navbar.js
│   │   │   │   ├── runTool.js
│   │   │   │   ├── toolDisplay.js
│   │   │   │   ├── tools.js
│   │   │   │   └── toolsets.js
│   │   │   ├── tools.html
│   │   │   └── toolsets.html
│   │   ├── web_test.go
│   │   └── web.go
│   ├── sources
│   │   ├── alloydbadmin
│   │   │   ├── alloydbadmin_test.go
│   │   │   └── alloydbadmin.go
│   │   ├── alloydbpg
│   │   │   ├── alloydb_pg_test.go
│   │   │   └── alloydb_pg.go
│   │   ├── bigquery
│   │   │   ├── bigquery_test.go
│   │   │   └── bigquery.go
│   │   ├── bigtable
│   │   │   ├── bigtable_test.go
│   │   │   └── bigtable.go
│   │   ├── cassandra
│   │   │   ├── cassandra_test.go
│   │   │   └── cassandra.go
│   │   ├── clickhouse
│   │   │   ├── clickhouse_test.go
│   │   │   └── clickhouse.go
│   │   ├── cloudmonitoring
│   │   │   ├── cloud_monitoring_test.go
│   │   │   └── cloud_monitoring.go
│   │   ├── cloudsqladmin
│   │   │   ├── cloud_sql_admin_test.go
│   │   │   └── cloud_sql_admin.go
│   │   ├── cloudsqlmssql
│   │   │   ├── cloud_sql_mssql_test.go
│   │   │   └── cloud_sql_mssql.go
│   │   ├── cloudsqlmysql
│   │   │   ├── cloud_sql_mysql_test.go
│   │   │   └── cloud_sql_mysql.go
│   │   ├── cloudsqlpg
│   │   │   ├── cloud_sql_pg_test.go
│   │   │   └── cloud_sql_pg.go
│   │   ├── couchbase
│   │   │   ├── couchbase_test.go
│   │   │   └── couchbase.go
│   │   ├── dataplex
│   │   │   ├── dataplex_test.go
│   │   │   └── dataplex.go
│   │   ├── dgraph
│   │   │   ├── dgraph_test.go
│   │   │   └── dgraph.go
│   │   ├── dialect.go
│   │   ├── firebird
│   │   │   ├── firebird_test.go
│   │   │   └── firebird.go
│   │   ├── firestore
│   │   │   ├── firestore_test.go
│   │   │   └── firestore.go
│   │   ├── http
│   │   │   ├── http_test.go
│   │   │   └── http.go
│   │   ├── ip_type.go
│   │   ├── looker
│   │   │   ├── looker_test.go
│   │   │   └── looker.go
│   │   ├── mongodb
│   │   │   ├── mongodb_test.go
│   │   │   └── mongodb.go
│   │   ├── mssql
│   │   │   ├── mssql_test.go
│   │   │   └── mssql.go
│   │   ├── mysql
│   │   │   ├── mysql_test.go
│   │   │   └── mysql.go
│   │   ├── neo4j
│   │   │   ├── neo4j_test.go
│   │   │   └── neo4j.go
│   │   ├── oceanbase
│   │   │   ├── oceanbase_test.go
│   │   │   └── oceanbase.go
│   │   ├── oracle
│   │   │   └── oracle.go
│   │   ├── postgres
│   │   │   ├── postgres_test.go
│   │   │   └── postgres.go
│   │   ├── redis
│   │   │   ├── redis_test.go
│   │   │   └── redis.go
│   │   ├── serverlessspark
│   │   │   ├── serverlessspark_test.go
│   │   │   └── serverlessspark.go
│   │   ├── sources.go
│   │   ├── spanner
│   │   │   ├── spanner_test.go
│   │   │   └── spanner.go
│   │   ├── sqlite
│   │   │   ├── sqlite_test.go
│   │   │   └── sqlite.go
│   │   ├── tidb
│   │   │   ├── tidb_test.go
│   │   │   └── tidb.go
│   │   ├── trino
│   │   │   ├── trino_test.go
│   │   │   └── trino.go
│   │   ├── util.go
│   │   ├── valkey
│   │   │   ├── valkey_test.go
│   │   │   └── valkey.go
│   │   └── yugabytedb
│   │       ├── yugabytedb_test.go
│   │       └── yugabytedb.go
│   ├── telemetry
│   │   ├── instrumentation.go
│   │   └── telemetry.go
│   ├── testutils
│   │   └── testutils.go
│   ├── tools
│   │   ├── alloydb
│   │   │   ├── alloydbcreatecluster
│   │   │   │   ├── alloydbcreatecluster_test.go
│   │   │   │   └── alloydbcreatecluster.go
│   │   │   ├── alloydbcreateinstance
│   │   │   │   ├── alloydbcreateinstance_test.go
│   │   │   │   └── alloydbcreateinstance.go
│   │   │   ├── alloydbcreateuser
│   │   │   │   ├── alloydbcreateuser_test.go
│   │   │   │   └── alloydbcreateuser.go
│   │   │   ├── alloydbgetcluster
│   │   │   │   ├── alloydbgetcluster_test.go
│   │   │   │   └── alloydbgetcluster.go
│   │   │   ├── alloydbgetinstance
│   │   │   │   ├── alloydbgetinstance_test.go
│   │   │   │   └── alloydbgetinstance.go
│   │   │   ├── alloydbgetuser
│   │   │   │   ├── alloydbgetuser_test.go
│   │   │   │   └── alloydbgetuser.go
│   │   │   ├── alloydblistclusters
│   │   │   │   ├── alloydblistclusters_test.go
│   │   │   │   └── alloydblistclusters.go
│   │   │   ├── alloydblistinstances
│   │   │   │   ├── alloydblistinstances_test.go
│   │   │   │   └── alloydblistinstances.go
│   │   │   ├── alloydblistusers
│   │   │   │   ├── alloydblistusers_test.go
│   │   │   │   └── alloydblistusers.go
│   │   │   └── alloydbwaitforoperation
│   │   │       ├── alloydbwaitforoperation_test.go
│   │   │       └── alloydbwaitforoperation.go
│   │   ├── alloydbainl
│   │   │   ├── alloydbainl_test.go
│   │   │   └── alloydbainl.go
│   │   ├── bigquery
│   │   │   ├── bigqueryanalyzecontribution
│   │   │   │   ├── bigqueryanalyzecontribution_test.go
│   │   │   │   └── bigqueryanalyzecontribution.go
│   │   │   ├── bigquerycommon
│   │   │   │   ├── table_name_parser_test.go
│   │   │   │   ├── table_name_parser.go
│   │   │   │   └── util.go
│   │   │   ├── bigqueryconversationalanalytics
│   │   │   │   ├── bigqueryconversationalanalytics_test.go
│   │   │   │   └── bigqueryconversationalanalytics.go
│   │   │   ├── bigqueryexecutesql
│   │   │   │   ├── bigqueryexecutesql_test.go
│   │   │   │   └── bigqueryexecutesql.go
│   │   │   ├── bigqueryforecast
│   │   │   │   ├── bigqueryforecast_test.go
│   │   │   │   └── bigqueryforecast.go
│   │   │   ├── bigquerygetdatasetinfo
│   │   │   │   ├── bigquerygetdatasetinfo_test.go
│   │   │   │   └── bigquerygetdatasetinfo.go
│   │   │   ├── bigquerygettableinfo
│   │   │   │   ├── bigquerygettableinfo_test.go
│   │   │   │   └── bigquerygettableinfo.go
│   │   │   ├── bigquerylistdatasetids
│   │   │   │   ├── bigquerylistdatasetids_test.go
│   │   │   │   └── bigquerylistdatasetids.go
│   │   │   ├── bigquerylisttableids
│   │   │   │   ├── bigquerylisttableids_test.go
│   │   │   │   └── bigquerylisttableids.go
│   │   │   ├── bigquerysearchcatalog
│   │   │   │   ├── bigquerysearchcatalog_test.go
│   │   │   │   └── bigquerysearchcatalog.go
│   │   │   └── bigquerysql
│   │   │       ├── bigquerysql_test.go
│   │   │       └── bigquerysql.go
│   │   ├── bigtable
│   │   │   ├── bigtable_test.go
│   │   │   └── bigtable.go
│   │   ├── cassandra
│   │   │   └── cassandracql
│   │   │       ├── cassandracql_test.go
│   │   │       └── cassandracql.go
│   │   ├── clickhouse
│   │   │   ├── clickhouseexecutesql
│   │   │   │   ├── clickhouseexecutesql_test.go
│   │   │   │   └── clickhouseexecutesql.go
│   │   │   ├── clickhouselistdatabases
│   │   │   │   ├── clickhouselistdatabases_test.go
│   │   │   │   └── clickhouselistdatabases.go
│   │   │   ├── clickhouselisttables
│   │   │   │   ├── clickhouselisttables_test.go
│   │   │   │   └── clickhouselisttables.go
│   │   │   └── clickhousesql
│   │   │       ├── clickhousesql_test.go
│   │   │       └── clickhousesql.go
│   │   ├── cloudmonitoring
│   │   │   ├── cloudmonitoring_test.go
│   │   │   └── cloudmonitoring.go
│   │   ├── cloudsql
│   │   │   ├── cloudsqlcreatedatabase
│   │   │   │   ├── cloudsqlcreatedatabase_test.go
│   │   │   │   └── cloudsqlcreatedatabase.go
│   │   │   ├── cloudsqlcreateusers
│   │   │   │   ├── cloudsqlcreateusers_test.go
│   │   │   │   └── cloudsqlcreateusers.go
│   │   │   ├── cloudsqlgetinstances
│   │   │   │   ├── cloudsqlgetinstances_test.go
│   │   │   │   └── cloudsqlgetinstances.go
│   │   │   ├── cloudsqllistdatabases
│   │   │   │   ├── cloudsqllistdatabases_test.go
│   │   │   │   └── cloudsqllistdatabases.go
│   │   │   ├── cloudsqllistinstances
│   │   │   │   ├── cloudsqllistinstances_test.go
│   │   │   │   └── cloudsqllistinstances.go
│   │   │   └── cloudsqlwaitforoperation
│   │   │       ├── cloudsqlwaitforoperation_test.go
│   │   │       └── cloudsqlwaitforoperation.go
│   │   ├── cloudsqlmssql
│   │   │   └── cloudsqlmssqlcreateinstance
│   │   │       ├── cloudsqlmssqlcreateinstance_test.go
│   │   │       └── cloudsqlmssqlcreateinstance.go
│   │   ├── cloudsqlmysql
│   │   │   └── cloudsqlmysqlcreateinstance
│   │   │       ├── cloudsqlmysqlcreateinstance_test.go
│   │   │       └── cloudsqlmysqlcreateinstance.go
│   │   ├── cloudsqlpg
│   │   │   └── cloudsqlpgcreateinstances
│   │   │       ├── cloudsqlpgcreateinstances_test.go
│   │   │       └── cloudsqlpgcreateinstances.go
│   │   ├── common_test.go
│   │   ├── common.go
│   │   ├── couchbase
│   │   │   ├── couchbase_test.go
│   │   │   └── couchbase.go
│   │   ├── dataform
│   │   │   └── dataformcompilelocal
│   │   │       ├── dataformcompilelocal_test.go
│   │   │       └── dataformcompilelocal.go
│   │   ├── dataplex
│   │   │   ├── dataplexlookupentry
│   │   │   │   ├── dataplexlookupentry_test.go
│   │   │   │   └── dataplexlookupentry.go
│   │   │   ├── dataplexsearchaspecttypes
│   │   │   │   ├── dataplexsearchaspecttypes_test.go
│   │   │   │   └── dataplexsearchaspecttypes.go
│   │   │   └── dataplexsearchentries
│   │   │       ├── dataplexsearchentries_test.go
│   │   │       └── dataplexsearchentries.go
│   │   ├── dgraph
│   │   │   ├── dgraph_test.go
│   │   │   └── dgraph.go
│   │   ├── firebird
│   │   │   ├── firebirdexecutesql
│   │   │   │   ├── firebirdexecutesql_test.go
│   │   │   │   └── firebirdexecutesql.go
│   │   │   └── firebirdsql
│   │   │       ├── firebirdsql_test.go
│   │   │       └── firebirdsql.go
│   │   ├── firestore
│   │   │   ├── firestoreadddocuments
│   │   │   │   ├── firestoreadddocuments_test.go
│   │   │   │   └── firestoreadddocuments.go
│   │   │   ├── firestoredeletedocuments
│   │   │   │   ├── firestoredeletedocuments_test.go
│   │   │   │   └── firestoredeletedocuments.go
│   │   │   ├── firestoregetdocuments
│   │   │   │   ├── firestoregetdocuments_test.go
│   │   │   │   └── firestoregetdocuments.go
│   │   │   ├── firestoregetrules
│   │   │   │   ├── firestoregetrules_test.go
│   │   │   │   └── firestoregetrules.go
│   │   │   ├── firestorelistcollections
│   │   │   │   ├── firestorelistcollections_test.go
│   │   │   │   └── firestorelistcollections.go
│   │   │   ├── firestorequery
│   │   │   │   ├── firestorequery_test.go
│   │   │   │   └── firestorequery.go
│   │   │   ├── firestorequerycollection
│   │   │   │   ├── firestorequerycollection_test.go
│   │   │   │   └── firestorequerycollection.go
│   │   │   ├── firestoreupdatedocument
│   │   │   │   ├── firestoreupdatedocument_test.go
│   │   │   │   └── firestoreupdatedocument.go
│   │   │   ├── firestorevalidaterules
│   │   │   │   ├── firestorevalidaterules_test.go
│   │   │   │   └── firestorevalidaterules.go
│   │   │   └── util
│   │   │       ├── converter_test.go
│   │   │       ├── converter.go
│   │   │       ├── validator_test.go
│   │   │       └── validator.go
│   │   ├── http
│   │   │   ├── http_test.go
│   │   │   └── http.go
│   │   ├── http_method.go
│   │   ├── looker
│   │   │   ├── lookeradddashboardelement
│   │   │   │   ├── lookeradddashboardelement_test.go
│   │   │   │   └── lookeradddashboardelement.go
│   │   │   ├── lookercommon
│   │   │   │   ├── lookercommon_test.go
│   │   │   │   └── lookercommon.go
│   │   │   ├── lookerconversationalanalytics
│   │   │   │   ├── lookerconversationalanalytics_test.go
│   │   │   │   └── lookerconversationalanalytics.go
│   │   │   ├── lookercreateprojectfile
│   │   │   │   ├── lookercreateprojectfile_test.go
│   │   │   │   └── lookercreateprojectfile.go
│   │   │   ├── lookerdeleteprojectfile
│   │   │   │   ├── lookerdeleteprojectfile_test.go
│   │   │   │   └── lookerdeleteprojectfile.go
│   │   │   ├── lookerdevmode
│   │   │   │   ├── lookerdevmode_test.go
│   │   │   │   └── lookerdevmode.go
│   │   │   ├── lookergetdashboards
│   │   │   │   ├── lookergetdashboards_test.go
│   │   │   │   └── lookergetdashboards.go
│   │   │   ├── lookergetdimensions
│   │   │   │   ├── lookergetdimensions_test.go
│   │   │   │   └── lookergetdimensions.go
│   │   │   ├── lookergetexplores
│   │   │   │   ├── lookergetexplores_test.go
│   │   │   │   └── lookergetexplores.go
│   │   │   ├── lookergetfilters
│   │   │   │   ├── lookergetfilters_test.go
│   │   │   │   └── lookergetfilters.go
│   │   │   ├── lookergetlooks
│   │   │   │   ├── lookergetlooks_test.go
│   │   │   │   └── lookergetlooks.go
│   │   │   ├── lookergetmeasures
│   │   │   │   ├── lookergetmeasures_test.go
│   │   │   │   └── lookergetmeasures.go
│   │   │   ├── lookergetmodels
│   │   │   │   ├── lookergetmodels_test.go
│   │   │   │   └── lookergetmodels.go
│   │   │   ├── lookergetparameters
│   │   │   │   ├── lookergetparameters_test.go
│   │   │   │   └── lookergetparameters.go
│   │   │   ├── lookergetprojectfile
│   │   │   │   ├── lookergetprojectfile_test.go
│   │   │   │   └── lookergetprojectfile.go
│   │   │   ├── lookergetprojectfiles
│   │   │   │   ├── lookergetprojectfiles_test.go
│   │   │   │   └── lookergetprojectfiles.go
│   │   │   ├── lookergetprojects
│   │   │   │   ├── lookergetprojects_test.go
│   │   │   │   └── lookergetprojects.go
│   │   │   ├── lookerhealthanalyze
│   │   │   │   ├── lookerhealthanalyze_test.go
│   │   │   │   └── lookerhealthanalyze.go
│   │   │   ├── lookerhealthpulse
│   │   │   │   ├── lookerhealthpulse_test.go
│   │   │   │   └── lookerhealthpulse.go
│   │   │   ├── lookerhealthvacuum
│   │   │   │   ├── lookerhealthvacuum_test.go
│   │   │   │   └── lookerhealthvacuum.go
│   │   │   ├── lookermakedashboard
│   │   │   │   ├── lookermakedashboard_test.go
│   │   │   │   └── lookermakedashboard.go
│   │   │   ├── lookermakelook
│   │   │   │   ├── lookermakelook_test.go
│   │   │   │   └── lookermakelook.go
│   │   │   ├── lookerquery
│   │   │   │   ├── lookerquery_test.go
│   │   │   │   └── lookerquery.go
│   │   │   ├── lookerquerysql
│   │   │   │   ├── lookerquerysql_test.go
│   │   │   │   └── lookerquerysql.go
│   │   │   ├── lookerqueryurl
│   │   │   │   ├── lookerqueryurl_test.go
│   │   │   │   └── lookerqueryurl.go
│   │   │   ├── lookerrunlook
│   │   │   │   ├── lookerrunlook_test.go
│   │   │   │   └── lookerrunlook.go
│   │   │   └── lookerupdateprojectfile
│   │   │       ├── lookerupdateprojectfile_test.go
│   │   │       └── lookerupdateprojectfile.go
│   │   ├── mongodb
│   │   │   ├── mongodbaggregate
│   │   │   │   ├── mongodbaggregate_test.go
│   │   │   │   └── mongodbaggregate.go
│   │   │   ├── mongodbdeletemany
│   │   │   │   ├── mongodbdeletemany_test.go
│   │   │   │   └── mongodbdeletemany.go
│   │   │   ├── mongodbdeleteone
│   │   │   │   ├── mongodbdeleteone_test.go
│   │   │   │   └── mongodbdeleteone.go
│   │   │   ├── mongodbfind
│   │   │   │   ├── mongodbfind_test.go
│   │   │   │   └── mongodbfind.go
│   │   │   ├── mongodbfindone
│   │   │   │   ├── mongodbfindone_test.go
│   │   │   │   └── mongodbfindone.go
│   │   │   ├── mongodbinsertmany
│   │   │   │   ├── mongodbinsertmany_test.go
│   │   │   │   └── mongodbinsertmany.go
│   │   │   ├── mongodbinsertone
│   │   │   │   ├── mongodbinsertone_test.go
│   │   │   │   └── mongodbinsertone.go
│   │   │   ├── mongodbupdatemany
│   │   │   │   ├── mongodbupdatemany_test.go
│   │   │   │   └── mongodbupdatemany.go
│   │   │   └── mongodbupdateone
│   │   │       ├── mongodbupdateone_test.go
│   │   │       └── mongodbupdateone.go
│   │   ├── mssql
│   │   │   ├── mssqlexecutesql
│   │   │   │   ├── mssqlexecutesql_test.go
│   │   │   │   └── mssqlexecutesql.go
│   │   │   ├── mssqllisttables
│   │   │   │   ├── mssqllisttables_test.go
│   │   │   │   └── mssqllisttables.go
│   │   │   └── mssqlsql
│   │   │       ├── mssqlsql_test.go
│   │   │       └── mssqlsql.go
│   │   ├── mysql
│   │   │   ├── mysqlcommon
│   │   │   │   └── mysqlcommon.go
│   │   │   ├── mysqlexecutesql
│   │   │   │   ├── mysqlexecutesql_test.go
│   │   │   │   └── mysqlexecutesql.go
│   │   │   ├── mysqllistactivequeries
│   │   │   │   ├── mysqllistactivequeries_test.go
│   │   │   │   └── mysqllistactivequeries.go
│   │   │   ├── mysqllisttablefragmentation
│   │   │   │   ├── mysqllisttablefragmentation_test.go
│   │   │   │   └── mysqllisttablefragmentation.go
│   │   │   ├── mysqllisttables
│   │   │   │   ├── mysqllisttables_test.go
│   │   │   │   └── mysqllisttables.go
│   │   │   ├── mysqllisttablesmissinguniqueindexes
│   │   │   │   ├── mysqllisttablesmissinguniqueindexes_test.go
│   │   │   │   └── mysqllisttablesmissinguniqueindexes.go
│   │   │   └── mysqlsql
│   │   │       ├── mysqlsql_test.go
│   │   │       └── mysqlsql.go
│   │   ├── neo4j
│   │   │   ├── neo4jcypher
│   │   │   │   ├── neo4jcypher_test.go
│   │   │   │   └── neo4jcypher.go
│   │   │   ├── neo4jexecutecypher
│   │   │   │   ├── classifier
│   │   │   │   │   ├── classifier_test.go
│   │   │   │   │   └── classifier.go
│   │   │   │   ├── neo4jexecutecypher_test.go
│   │   │   │   └── neo4jexecutecypher.go
│   │   │   └── neo4jschema
│   │   │       ├── cache
│   │   │       │   ├── cache_test.go
│   │   │       │   └── cache.go
│   │   │       ├── helpers
│   │   │       │   ├── helpers_test.go
│   │   │       │   └── helpers.go
│   │   │       ├── neo4jschema_test.go
│   │   │       ├── neo4jschema.go
│   │   │       └── types
│   │   │           └── types.go
│   │   ├── oceanbase
│   │   │   ├── oceanbaseexecutesql
│   │   │   │   ├── oceanbaseexecutesql_test.go
│   │   │   │   └── oceanbaseexecutesql.go
│   │   │   └── oceanbasesql
│   │   │       ├── oceanbasesql_test.go
│   │   │       └── oceanbasesql.go
│   │   ├── oracle
│   │   │   ├── oracleexecutesql
│   │   │   │   └── oracleexecutesql.go
│   │   │   └── oraclesql
│   │   │       └── oraclesql.go
│   │   ├── parameters_test.go
│   │   ├── parameters.go
│   │   ├── postgres
│   │   │   ├── postgresexecutesql
│   │   │   │   ├── postgresexecutesql_test.go
│   │   │   │   └── postgresexecutesql.go
│   │   │   ├── postgreslistactivequeries
│   │   │   │   ├── postgreslistactivequeries_test.go
│   │   │   │   └── postgreslistactivequeries.go
│   │   │   ├── postgreslistavailableextensions
│   │   │   │   ├── postgreslistavailableextensions_test.go
│   │   │   │   └── postgreslistavailableextensions.go
│   │   │   ├── postgreslistinstalledextensions
│   │   │   │   ├── postgreslistinstalledextensions_test.go
│   │   │   │   └── postgreslistinstalledextensions.go
│   │   │   ├── postgreslisttables
│   │   │   │   ├── postgreslisttables_test.go
│   │   │   │   └── postgreslisttables.go
│   │   │   └── postgressql
│   │   │       ├── postgressql_test.go
│   │   │       └── postgressql.go
│   │   ├── redis
│   │   │   ├── redis_test.go
│   │   │   └── redis.go
│   │   ├── serverlessspark
│   │   │   └── serverlesssparklistbatches
│   │   │       ├── serverlesssparklistbatches_test.go
│   │   │       └── serverlesssparklistbatches.go
│   │   ├── spanner
│   │   │   ├── spannerexecutesql
│   │   │   │   ├── spannerexecutesql_test.go
│   │   │   │   └── spannerexecutesql.go
│   │   │   ├── spannerlisttables
│   │   │   │   ├── spannerlisttables_test.go
│   │   │   │   └── spannerlisttables.go
│   │   │   └── spannersql
│   │   │       ├── spanner_test.go
│   │   │       └── spannersql.go
│   │   ├── sqlite
│   │   │   ├── sqliteexecutesql
│   │   │   │   ├── sqliteexecutesql_test.go
│   │   │   │   └── sqliteexecutesql.go
│   │   │   └── sqlitesql
│   │   │       ├── sqlitesql_test.go
│   │   │       └── sqlitesql.go
│   │   ├── tidb
│   │   │   ├── tidbexecutesql
│   │   │   │   ├── tidbexecutesql_test.go
│   │   │   │   └── tidbexecutesql.go
│   │   │   └── tidbsql
│   │   │       ├── tidbsql_test.go
│   │   │       └── tidbsql.go
│   │   ├── tools_test.go
│   │   ├── tools.go
│   │   ├── toolsets.go
│   │   ├── trino
│   │   │   ├── trinoexecutesql
│   │   │   │   ├── trinoexecutesql_test.go
│   │   │   │   └── trinoexecutesql.go
│   │   │   └── trinosql
│   │   │       ├── trinosql_test.go
│   │   │       └── trinosql.go
│   │   ├── utility
│   │   │   └── wait
│   │   │       ├── wait_test.go
│   │   │       └── wait.go
│   │   ├── valkey
│   │   │   ├── valkey_test.go
│   │   │   └── valkey.go
│   │   └── yugabytedbsql
│   │       ├── yugabytedbsql_test.go
│   │       └── yugabytedbsql.go
│   └── util
│       └── util.go
├── LICENSE
├── logo.png
├── main.go
├── MCP-TOOLBOX-EXTENSION.md
├── README.md
└── tests
    ├── alloydb
    │   ├── alloydb_integration_test.go
    │   └── alloydb_wait_for_operation_test.go
    ├── alloydbainl
    │   └── alloydb_ai_nl_integration_test.go
    ├── alloydbpg
    │   └── alloydb_pg_integration_test.go
    ├── auth.go
    ├── bigquery
    │   └── bigquery_integration_test.go
    ├── bigtable
    │   └── bigtable_integration_test.go
    ├── cassandra
    │   └── cassandra_integration_test.go
    ├── clickhouse
    │   └── clickhouse_integration_test.go
    ├── cloudmonitoring
    │   └── cloud_monitoring_integration_test.go
    ├── cloudsql
    │   ├── cloud_sql_create_database_test.go
    │   ├── cloud_sql_create_users_test.go
    │   ├── cloud_sql_get_instances_test.go
    │   ├── cloud_sql_list_databases_test.go
    │   ├── cloudsql_list_instances_test.go
    │   └── cloudsql_wait_for_operation_test.go
    ├── cloudsqlmssql
    │   ├── cloud_sql_mssql_create_instance_integration_test.go
    │   └── cloud_sql_mssql_integration_test.go
    ├── cloudsqlmysql
    │   ├── cloud_sql_mysql_create_instance_integration_test.go
    │   └── cloud_sql_mysql_integration_test.go
    ├── cloudsqlpg
    │   ├── cloud_sql_pg_create_instances_test.go
    │   └── cloud_sql_pg_integration_test.go
    ├── common.go
    ├── couchbase
    │   └── couchbase_integration_test.go
    ├── dataform
    │   └── dataform_integration_test.go
    ├── dataplex
    │   └── dataplex_integration_test.go
    ├── dgraph
    │   └── dgraph_integration_test.go
    ├── firebird
    │   └── firebird_integration_test.go
    ├── firestore
    │   └── firestore_integration_test.go
    ├── http
    │   └── http_integration_test.go
    ├── looker
    │   └── looker_integration_test.go
    ├── mongodb
    │   └── mongodb_integration_test.go
    ├── mssql
    │   └── mssql_integration_test.go
    ├── mysql
    │   └── mysql_integration_test.go
    ├── neo4j
    │   └── neo4j_integration_test.go
    ├── oceanbase
    │   └── oceanbase_integration_test.go
    ├── option.go
    ├── oracle
    │   └── oracle_integration_test.go
    ├── postgres
    │   └── postgres_integration_test.go
    ├── redis
    │   └── redis_test.go
    ├── server.go
    ├── serverlessspark
    │   └── serverless_spark_integration_test.go
    ├── source.go
    ├── spanner
    │   └── spanner_integration_test.go
    ├── sqlite
    │   └── sqlite_integration_test.go
    ├── tidb
    │   └── tidb_integration_test.go
    ├── tool.go
    ├── trino
    │   └── trino_integration_test.go
    ├── utility
    │   └── wait_integration_test.go
    ├── valkey
    │   └── valkey_test.go
    └── yugabytedb
        └── yugabytedb_integration_test.go
```

# Files

--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/cloud_sql_pg_admin_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "Cloud SQL for PostgreSQL Admin using MCP"
  3 | type: docs
  4 | weight: 3
  5 | description: >
  6 |   Create and manage Cloud SQL for PostgreSQL (Admin) using Toolbox.
  7 | ---
  8 | 
  9 | This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your
 10 | developer assistant tools to create and manage Cloud SQL for PostgreSQL
 11 | instance, database and users:
 12 | 
 13 | * [Cursor][cursor]
 14 | * [Windsurf][windsurf] (Codium)
 15 | * [Visual Studio Code][vscode] (Copilot)
 16 | * [Cline][cline]  (VS Code extension)
 17 | * [Claude desktop][claudedesktop]
 18 | * [Claude code][claudecode]
 19 | * [Gemini CLI][geminicli]
 20 | * [Gemini Code Assist][geminicodeassist]
 21 | 
 22 | [toolbox]: https://github.com/googleapis/genai-toolbox
 23 | [cursor]: #configure-your-mcp-client
 24 | [windsurf]: #configure-your-mcp-client
 25 | [vscode]: #configure-your-mcp-client
 26 | [cline]: #configure-your-mcp-client
 27 | [claudedesktop]: #configure-your-mcp-client
 28 | [claudecode]: #configure-your-mcp-client
 29 | [geminicli]: #configure-your-mcp-client
 30 | [geminicodeassist]: #configure-your-mcp-client
 31 | 
 32 | ## Before you begin
 33 | 
 34 | 1. In the Google Cloud console, on the [project selector
 35 |    page](https://console.cloud.google.com/projectselector2/home/dashboard),
 36 |    select or create a Google Cloud project.
 37 | 
 38 | 1. [Make sure that billing is enabled for your Google Cloud
 39 |    project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
 40 | 
 41 | 1. Grant the necessary IAM roles to the user that will be running the MCP
 42 |    server. The tools available will depend on the roles granted:
 43 |     * `roles/cloudsql.viewer`: Provides read-only access to resources.
 44 |         * `get_instance`
 45 |         * `list_instances`
 46 |         * `list_databases`
 47 |         * `wait_for_operation`
 48 |     * `roles/cloudsql.editor`: Provides permissions to manage existing resources.
 49 |         * All `viewer` tools
 50 |         * `create_database`
 51 |     * `roles/cloudsql.admin`: Provides full control over all resources.
 52 |         * All `editor` and `viewer` tools
 53 |         * `create_instance`
 54 |         * `create_user`
 55 | 
 56 | ## Install MCP Toolbox
 57 | 
 58 | 1. Download the latest version of Toolbox as a binary. Select the [correct
 59 |    binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
 60 |    to your OS and CPU architecture. You are required to use Toolbox version
 61 |    V0.15.0+:
 62 | 
 63 |    <!-- {x-release-please-start-version} -->
 64 |    {{< tabpane persist=header >}}
 65 | {{< tab header="linux/amd64" lang="bash" >}}
 66 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/linux/amd64/toolbox
 67 | {{< /tab >}}
 68 | 
 69 | {{< tab header="darwin/arm64" lang="bash" >}}
 70 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/arm64/toolbox
 71 | {{< /tab >}}
 72 | 
 73 | {{< tab header="darwin/amd64" lang="bash" >}}
 74 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/amd64/toolbox
 75 | {{< /tab >}}
 76 | 
 77 | {{< tab header="windows/amd64" lang="bash" >}}
 78 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/windows/amd64/toolbox.exe
 79 | {{< /tab >}}
 80 | {{< /tabpane >}}
 81 |     <!-- {x-release-please-end} -->
 82 | 
 83 | 1. Make the binary executable:
 84 | 
 85 |     ```bash
 86 |     chmod +x toolbox
 87 |     ```
 88 | 
 89 | 1. Verify the installation:
 90 | 
 91 |     ```bash
 92 |     ./toolbox --version
 93 |     ```
 94 | 
 95 | ## Configure your MCP Client
 96 | 
 97 | {{< tabpane text=true >}}
 98 | {{% tab header="Claude code" lang="en" %}}
 99 | 
100 | 1. Install [Claude
101 |    Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
102 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
103 | 1. Add the following configuration and save:
104 | 
105 |     ```json
106 |     {
107 |       "mcpServers": {
108 |         "cloud-sql-postgres-admin": {
109 |           "command": "./PATH/TO/toolbox",
110 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
111 |           "env": {
112 |           }
113 |         }
114 |       }
115 |     }
116 |     ```
117 | 
118 | 1. Restart Claude code to apply the new configuration.
119 | {{% /tab %}}
120 | 
121 | {{% tab header="Claude desktop" lang="en" %}}
122 | 
123 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
124 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
125 | 1. Add the following configuration and save:
126 | 
127 |     ```json
128 |     {
129 |       "mcpServers": {
130 |         "cloud-sql-postgres-admin": {
131 |           "command": "./PATH/TO/toolbox",
132 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
133 |           "env": {
134 |           }
135 |         }
136 |       }
137 |     }
138 |     ```
139 | 
140 | 1. Restart Claude desktop.
141 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
142 |    new MCP server available.
143 | {{% /tab %}}
144 | 
145 | {{% tab header="Cline" lang="en" %}}
146 | 
147 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap
148 |    the **MCP Servers** icon.
149 | 1. Tap Configure MCP Servers to open the configuration file.
150 | 1. Add the following configuration and save:
151 | 
152 |     ```json
153 |     {
154 |       "mcpServers": {
155 |         "cloud-sql-postgres-admin": {
156 |           "command": "./PATH/TO/toolbox",
157 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
158 |           "env": {
159 |           }
160 |         }
161 |       }
162 |     }
163 |     ```
164 | 
165 | 1. You should see a green active status after the server is successfully
166 |    connected.
167 | {{% /tab %}}
168 | 
169 | {{% tab header="Cursor" lang="en" %}}
170 | 
171 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
172 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
173 | 1. Add the following configuration and save:
174 | 
175 |     ```json
176 |     {
177 |       "mcpServers": {
178 |         "cloud-sql-postgres-admin": {
179 |           "command": "./PATH/TO/toolbox",
180 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
181 |           "env": {
182 |           }
183 |         }
184 |       }
185 |     }
186 |     ```
187 | 
188 | 1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
189 |    Settings > MCP**. You should see a green active status after the server is
190 |    successfully connected.
191 | {{% /tab %}}
192 | 
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 | 
195 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 |    create a `.vscode` directory in your project root if it doesn't exist.
197 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1. Add the following configuration and save:
199 | 
200 |     ```json
201 |     {
202 |       "servers": {
203 |         "cloud-sql-postgres-admin": {
204 |           "command": "./PATH/TO/toolbox",
205 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
206 |           "env": {
207 |           }
208 |         }
209 |       }
210 |     }
211 |     ```
212 | 
213 | {{% /tab %}}
214 | 
215 | {{% tab header="Windsurf" lang="en" %}}
216 | 
217 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 |    Cascade assistant.
219 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1. Add the following configuration and save:
221 | 
222 |     ```json
223 |     {
224 |       "mcpServers": {
225 |         "cloud-sql-postgres-admin": {
226 |           "command": "./PATH/TO/toolbox",
227 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
228 |           "env": {
229 |           }
230 |         }
231 |       }
232 |     }
233 |     ```
234 | 
235 | {{% /tab %}}
236 | 
237 | {{% tab header="Gemini CLI" lang="en" %}}
238 | 
239 | 1.  Install the [Gemini
240 |     CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
241 | 1.  In your working directory, create a folder named `.gemini`. Within it,
242 |     create a `settings.json` file.
243 | 1.  Add the following configuration and save:
244 | 
245 |     ```json
246 |     {
247 |       "mcpServers": {
248 |         "cloud-sql-postgres-admin": {
249 |           "command": "./PATH/TO/toolbox",
250 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
251 |           "env": {
252 |           }
253 |         }
254 |       }
255 |     }
256 |     ```
257 | {{% /tab %}}
258 | 
259 | {{% tab header="Gemini Code Assist" lang="en" %}}
260 | 
261 | 1.  Install the [Gemini Code
262 |     Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
263 |     extension in Visual Studio Code.
264 | 1.  Enable Agent Mode in Gemini Code Assist chat.
265 | 1.  In your working directory, create a folder named `.gemini`. Within it,
266 |     create a `settings.json` file.
267 | 1.  Add the following configuration and save:
268 | 
269 |     ```json
270 |     {
271 |       "mcpServers": {
272 |         "cloud-sql-postgres-admin": {
273 |           "command": "./PATH/TO/toolbox",
274 |           "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
275 |           "env": {
276 |           }
277 |         }
278 |       }
279 |     }
280 |     ```
281 | {{% /tab %}}
282 | {{< /tabpane >}}
283 | 
284 | ## Use Tools
285 | 
286 | Your AI tool is now connected to Cloud SQL for PostgreSQL using MCP.
287 | 
288 | The `cloud-sql-postgres-admin` server provides tools for managing your Cloud SQL
289 | instances and interacting with your database:
290 | * **create_instance**: Creates a new Cloud SQL for PostgreSQL instance.
291 | * **get_instance**: Gets information about a Cloud SQL instance.
292 | * **list_instances**: Lists Cloud SQL instances in a project.
293 | * **create_database**: Creates a new database in a Cloud SQL instance.
294 | * **list_databases**: Lists all databases for a Cloud SQL instance.
295 | * **create_user**: Creates a new user in a Cloud SQL instance.
296 | * **wait_for_operation**: Waits for a Cloud SQL operation to complete.
297 | 
298 | {{< notice note >}}
299 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
300 | will adapt to the tools available, so this shouldn't affect most users.
301 | {{< /notice >}}
302 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/authServices/_index.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "AuthServices"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   AuthServices represent services that handle authentication and authorization.
  7 | ---
  8 | 
  9 | AuthServices represent services that handle authentication and authorization. It
 10 | can primarily be used by [Tools](../tools/) in two different ways:
 11 | 
 12 | - [**Authorized Invocation**][auth-invoke] is when a tool
 13 |   is validated by the auth service before the call can be invoked. Toolbox
 14 |   will reject any calls that fail to validate or have an invalid token.
 15 | - [**Authenticated Parameters**][auth-params] replace the value of a parameter
 16 |   with a field from an [OIDC][openid-claims] claim. Toolbox will automatically
 17 |   resolve the ID token provided by the client and replace the parameter in the
 18 |   tool call.
 19 | 
 20 | [openid-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
 21 | [auth-invoke]: ../tools/#authorized-invocations
 22 | [auth-params]: ../tools/#authenticated-parameters
 23 | 
 24 | ## Example
 25 | 
 26 | The following configurations are placed at the top level of a `tools.yaml` file.
 27 | 
 28 | {{< notice tip >}}
 29 | If you are accessing Toolbox with multiple applications, each
 30 |  application should register their own Client ID even if they use the same
 31 |  "kind" of auth provider.
 32 | {{< /notice >}}
 33 | 
 34 | ```yaml
 35 | authServices:
 36 |   my_auth_app_1:
 37 |     kind: google
 38 |     clientId: ${YOUR_CLIENT_ID_1}
 39 |   my_auth_app_2:
 40 |     kind: google
 41 |     clientId: ${YOUR_CLIENT_ID_2}
 42 | ```
 43 | 
 44 | {{< notice tip >}}
 45 | Use environment variable replacement with the format ${ENV_NAME}
 46 | instead of hardcoding your secrets into the configuration file.
 47 | {{< /notice >}}
 48 | 
 49 | After you've configured an `authService` you'll, need to reference it in the
 50 | configuration for each tool that should use it:
 51 | 
 52 | - **Authorized Invocations** for authorizing a tool call, [use the
 53 |   `authRequired` field in a tool config][auth-invoke]
 54 | - **Authenticated Parameters** for using the value from a OIDC claim, [use the
 55 |   `authServices` field in a parameter config][auth-params]
 56 | 
 57 | ## Specifying ID Tokens from Clients
 58 | 
 59 | After [configuring](#example) your `authServices` section, use a Toolbox SDK to
 60 | add your ID tokens to the header of a Tool invocation request. When specifying a
 61 | token you will provide a function (that returns an id). This function is called
 62 | when the tool is invoked. This allows you to cache and refresh the ID token as
 63 | needed.
 64 | 
 65 | The primary method for providing these getters is via the `auth_token_getters`
 66 | parameter when loading tools, or the `add_auth_token_getter`() /
 67 | `add_auth_token_getters()` methods on a loaded tool object.
 68 | 
 69 | ### Specifying tokens during load
 70 | 
 71 | #### Python
 72 | 
 73 | Use the [Python SDK](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main).
 74 | 
 75 | {{< tabpane persist=header >}}
 76 | {{< tab header="Core" lang="Python" >}}
 77 | import asyncio
 78 | from toolbox_core import ToolboxClient
 79 | 
 80 | async def get_auth_token():
 81 |     # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
 82 |     # This example just returns a placeholder. Replace with your actual token retrieval.
 83 |     return "YOUR_ID_TOKEN" # Placeholder
 84 | 
 85 | async def main():
 86 |     async with ToolboxClient("<http://127.0.0.1:5000>") as toolbox:
 87 |         auth_tool = await toolbox.load_tool(
 88 |             "get_sensitive_data",
 89 |             auth_token_getters={"my_auth_app_1": get_auth_token}
 90 |         )
 91 |         result = await auth_tool(param="value")
 92 |         print(result)
 93 | 
 94 | if **name** == "**main**":
 95 |     asyncio.run(main())
 96 | {{< /tab >}}
 97 | {{< tab header="LangChain" lang="Python" >}}
 98 | import asyncio
 99 | from toolbox_langchain import ToolboxClient
100 | 
101 | async def get_auth_token():
102 |     # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
103 |     # This example just returns a placeholder. Replace with your actual token retrieval.
104 |     return "YOUR_ID_TOKEN" # Placeholder
105 | 
106 | async def main():
107 |     toolbox = ToolboxClient("<http://127.0.0.1:5000>")
108 | 
109 |     auth_tool = await toolbox.aload_tool(
110 |         "get_sensitive_data",
111 |         auth_token_getters={"my_auth_app_1": get_auth_token}
112 |     )
113 |     result = await auth_tool.ainvoke({"param": "value"})
114 |     print(result)
115 | 
116 | if **name** == "**main**":
117 |     asyncio.run(main())
118 | {{< /tab >}}
119 | {{< tab header="Llamaindex" lang="Python" >}}
120 | import asyncio
121 | from toolbox_llamaindex import ToolboxClient
122 | 
123 | async def get_auth_token():
124 |     # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
125 |     # This example just returns a placeholder. Replace with your actual token retrieval.
126 |     return "YOUR_ID_TOKEN" # Placeholder
127 | 
128 | async def main():
129 |     toolbox = ToolboxClient("<http://127.0.0.1:5000>")
130 | 
131 |     auth_tool = await toolbox.aload_tool(
132 |         "get_sensitive_data",
133 |         auth_token_getters={"my_auth_app_1": get_auth_token}
134 |     )
135 |     # result = await auth_tool.acall(param="value")
136 |     # print(result.content)
137 | 
138 | if **name** == "**main**":
139 |     asyncio.run(main()){{< /tab >}}
140 | {{< /tabpane >}}
141 | 
142 | #### Javascript/Typescript
143 | 
144 | Use the [JS SDK](https://github.com/googleapis/mcp-toolbox-sdk-js/tree/main).
145 | 
146 | ```javascript
147 | import { ToolboxClient } from '@toolbox-sdk/core';
148 | 
149 | async function getAuthToken() {
150 |     // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
151 |     // This example just returns a placeholder. Replace with your actual token retrieval.
152 |     return "YOUR_ID_TOKEN" // Placeholder
153 | }
154 | 
155 | const URL = 'http://127.0.0.1:5000';
156 | let client = new ToolboxClient(URL);
157 | const authTool = await client.loadTool("my-tool", {"my_auth_app_1": getAuthToken});
158 | const result = await authTool({param:"value"});
159 | console.log(result);
160 | print(result)
161 | ```
162 | 
163 | #### Go
164 | 
165 | Use the [Go SDK](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main).
166 | 
167 | ```go
168 | import "github.com/googleapis/mcp-toolbox-sdk-go/core"
169 | import "fmt"
170 | 
171 | func getAuthToken() string {
172 | 	// ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
173 | 	// This example just returns a placeholder. Replace with your actual token retrieval.
174 | 	return "YOUR_ID_TOKEN" // Placeholder
175 | }
176 | 
177 | func main() {
178 | 	URL := 'http://127.0.0.1:5000'
179 | 	client, err := core.NewToolboxClient(URL)
180 | 	if err != nil {
181 | 		log.Fatalf("Failed to create Toolbox client: %v", err)
182 |   	}
183 | 	dynamicTokenSource := core.NewCustomTokenSource(getAuthToken)
184 | 	authTool, err := client.LoadTool(
185 | 		"my-tool",
186 | 		ctx,
187 | 		core.WithAuthTokenSource("my_auth_app_1", dynamicTokenSource))
188 | 	if err != nil {
189 | 		log.Fatalf("Failed to load tool: %v", err)
190 | 	}
191 | 	inputs := map[string]any{"param": "value"}
192 | 	result, err := authTool.Invoke(ctx, inputs)
193 | 	if err != nil {
194 | 		log.Fatalf("Failed to invoke tool: %v", err)
195 | 	}
196 | 	fmt.Println(result)
197 | }
198 | ```
199 | 
200 | ### Specifying tokens for existing tools
201 | 
202 | #### Python
203 | 
204 | Use the [Python
205 | SDK](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main).
206 | 
207 | {{< tabpane persist=header >}}
208 | {{< tab header="Core" lang="Python" >}}
209 | tools = await toolbox.load_toolset()
210 | 
211 | # for a single token
212 | 
213 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
214 | 
215 | # OR, if multiple tokens are needed
216 | 
217 | authorized_tool = tools[0].add_auth_token_getters({
218 |   "my_auth1": get_auth1_token,
219 |   "my_auth2": get_auth2_token,
220 | })
221 | {{< /tab >}}
222 | {{< tab header="LangChain" lang="Python" >}}
223 | tools = toolbox.load_toolset()
224 | 
225 | # for a single token
226 | 
227 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
228 | 
229 | # OR, if multiple tokens are needed
230 | 
231 | authorized_tool = tools[0].add_auth_token_getters({
232 |   "my_auth1": get_auth1_token,
233 |   "my_auth2": get_auth2_token,
234 | })
235 | {{< /tab >}}
236 | {{< tab header="Llamaindex" lang="Python" >}}
237 | tools = toolbox.load_toolset()
238 | 
239 | # for a single token
240 | 
241 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
242 | 
243 | # OR, if multiple tokens are needed
244 | 
245 | authorized_tool = tools[0].add_auth_token_getters({
246 |   "my_auth1": get_auth1_token,
247 |   "my_auth2": get_auth2_token,
248 | })
249 | {{< /tab >}}
250 | {{< /tabpane >}}
251 | 
252 | #### Javascript/Typescript
253 | 
254 | Use the [JS SDK](https://github.com/googleapis/mcp-toolbox-sdk-js/tree/main).
255 | 
256 | ```javascript
257 | const URL = 'http://127.0.0.1:5000';
258 | let client = new ToolboxClient(URL);
259 | let tool = await client.loadTool("my-tool")
260 | 
261 | // for a single token
262 | const authorizedTool = tool.addAuthTokenGetter("my_auth", get_auth_token)
263 | 
264 | // OR, if multiple tokens are needed
265 | const multiAuthTool = tool.addAuthTokenGetters({
266 |     "my_auth_1": getAuthToken1,
267 |     "my_auth_2": getAuthToken2,
268 | })
269 | 
270 | ```
271 | 
272 | #### Go
273 | 
274 | Use the [Go SDK](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main).
275 | 
276 | ```go
277 | import "github.com/googleapis/mcp-toolbox-sdk-go/core"
278 | 
279 | func main() {
280 | 	URL := 'http://127.0.0.1:5000'
281 | 	client, err := core.NewToolboxClient(URL)
282 | 	if err != nil {
283 | 		log.Fatalf("Failed to create Toolbox client: %v", err)
284 | 	}
285 | 	tool, err := client.LoadTool("my-tool", ctx))
286 | 	if err != nil {
287 | 		log.Fatalf("Failed to load tool: %v", err)
288 | 	}
289 | 	dynamicTokenSource1 := core.NewCustomTokenSource(getAuthToken1)
290 | 	dynamicTokenSource2 := core.NewCustomTokenSource(getAuthToken1)
291 | 
292 | 	// For a single token
293 | 	authTool, err := tool.ToolFrom(
294 | 		core.WithAuthTokenSource("my-auth", dynamicTokenSource),
295 | 	)
296 | 
297 | 	// OR, if multiple tokens are needed
298 | 	authTool, err := tool.ToolFrom(
299 | 		core.WithAuthTokenSource("my-auth_1", dynamicTokenSource1),
300 | 		core.WithAuthTokenSource("my-auth_2", dynamicTokenSource2),
301 | 	)
302 | }
303 | ```
304 | 
305 | ## Kinds of Auth Services
306 | 
```

--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/neo4j_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: Neo4j using MCP
  3 | type: docs
  4 | weight: 2
  5 | description: "Connect your IDE to Neo4j using Toolbox."
  6 | ---
  7 | 
  8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
  9 | an open protocol for connecting Large Language Models (LLMs) to data sources
 10 | like Neo4j. This guide covers how to use [MCP Toolbox for Databases][toolbox] to
 11 | expose your developer assistant tools to a Neo4j instance:
 12 | 
 13 | * [Cursor][cursor]
 14 | * [Windsurf][windsurf] (Codium)
 15 | * [Visual Studio Code][vscode] (Copilot)
 16 | * [Cline][cline] (VS Code extension)
 17 | * [Claude desktop][claudedesktop]
 18 | * [Claude code][claudecode]
 19 | * [Gemini CLI][geminicli]
 20 | * [Gemini Code Assist][geminicodeassist]
 21 | 
 22 | [toolbox]: https://github.com/googleapis/genai-toolbox
 23 | [cursor]: #configure-your-mcp-client
 24 | [windsurf]: #configure-your-mcp-client
 25 | [vscode]: #configure-your-mcp-client
 26 | [cline]: #configure-your-mcp-client
 27 | [claudedesktop]: #configure-your-mcp-client
 28 | [claudecode]: #configure-your-mcp-client
 29 | [geminicli]: #configure-your-mcp-client
 30 | [geminicodeassist]: #configure-your-mcp-client
 31 | 
 32 | ## Set up the database
 33 | 
 34 | 1.  [Create or select a Neo4j
 35 |     instance.](https://neo4j.com/cloud/platform/aura-graph-database/)
 36 | 
 37 | ## Install MCP Toolbox
 38 | 
 39 | 1. Download the latest version of Toolbox as a binary. Select the [correct
 40 |    binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
 41 |    to your OS and CPU architecture. You are required to use Toolbox version
 42 |    v0.15.0+:
 43 | 
 44 |    <!-- {x-release-please-start-version} -->
 45 |    {{< tabpane persist=header >}}
 46 | {{< tab header="linux/amd64" lang="bash" >}}
 47 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
 48 | {{< /tab >}}
 49 | 
 50 | {{< tab header="darwin/arm64" lang="bash" >}}
 51 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
 52 | {{< /tab >}}
 53 | 
 54 | {{< tab header="darwin/amd64" lang="bash" >}}
 55 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
 56 | {{< /tab >}}
 57 | 
 58 | {{< tab header="windows/amd64" lang="bash" >}}
 59 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
 60 | {{< /tab >}}
 61 | {{< /tabpane >}}
 62 |     <!-- {x-release-please-end} -->
 63 | 
 64 | 1. Make the binary executable:
 65 | 
 66 |     ```bash
 67 |     chmod +x toolbox
 68 |     ```
 69 | 
 70 | 1. Verify the installation:
 71 | 
 72 |     ```bash
 73 |     ./toolbox --version
 74 |     ```
 75 | 
 76 | ## Configure your MCP Client
 77 | 
 78 | {{< tabpane text=true >}}
 79 | {{% tab header="Claude code" lang="en" %}}
 80 | 
 81 | 1.  Install [Claude
 82 |     Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview). 
 83 | 1.  Create a `.mcp.json` file in your project root if it doesn't exist.
 84 | 1.  Add the following configuration, replace the environment variables with your
 85 |     values, and save: 
 86 | 
 87 |     ```json
 88 |     {
 89 |       "mcpServers": {
 90 |         "neo4j": {
 91 |           "command": "./PATH/TO/toolbox",
 92 |           "args": ["--prebuilt","neo4j","--stdio"],
 93 |           "env": {
 94 |             "NEO4J_URI": "",
 95 |             "NEO4J_DATABASE": "",
 96 |             "NEO4J_USERNAME": "",
 97 |             "NEO4J_PASSWORD": ""
 98 |           }
 99 |         }
100 |       }
101 |     }
102 |     ```
103 | 
104 | 1.  Restart Claude code to apply the new configuration.
105 | {{% /tab %}}
106 | {{% tab header="Claude desktop" lang="en" %}}
107 | 
108 | 1.  Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
109 | 1.  Under the Developer tab, tap Edit Config to open the configuration file.
110 | 1.  Add the following configuration, replace the environment variables with your
111 |     values, and save: 
112 | 
113 |     ```json
114 |     {
115 |       "mcpServers": {
116 |         "neo4j": {
117 |           "command": "./PATH/TO/toolbox",
118 |           "args": ["--prebuilt","neo4j","--stdio"],
119 |           "env": {
120 |             "NEO4J_URI": "",
121 |             "NEO4J_DATABASE": "",
122 |             "NEO4J_USERNAME": "",
123 |             "NEO4J_PASSWORD": ""
124 |           }
125 |         }
126 |       }
127 |     }
128 |     ```
129 | 
130 | 1.  Restart Claude desktop.
131 | 1.  From the new chat screen, you should see a hammer (MCP) icon appear with the
132 |     new MCP server available. 
133 | {{% /tab %}}
134 | {{% tab header="Cline" lang="en" %}}
135 | 
136 | 1.  Open the [Cline](https://github.com/cline/cline) extension in VS Code and
137 |     tap the **MCP Servers** icon. 
138 | 1.  Tap Configure MCP Servers to open the configuration file.
139 | 1.  Add the following configuration, replace the environment variables with your
140 |     values, and save: 
141 | 
142 |     ```json
143 |     {
144 |       "mcpServers": {
145 |         "neo4j": {
146 |           "command": "./PATH/TO/toolbox",
147 |           "args": ["--prebuilt","neo4j","--stdio"],
148 |           "env": {
149 |             "NEO4J_URI": "",
150 |             "NEO4J_DATABASE": "",
151 |             "NEO4J_USERNAME": "",
152 |             "NEO4J_PASSWORD": ""
153 |           }
154 |         }
155 |       }
156 |     }
157 |     ```
158 | 
159 | 1.  You should see a green active status after the server is successfully connected.
160 | {{% /tab %}}
161 | {{% tab header="Cursor" lang="en" %}}
162 | 
163 | 1.  Create a `.cursor` directory in your project root if it doesn't exist.
164 | 1.  Create a `.cursor/mcp.json` file if it doesn't exist and open it.
165 | 1.  Add the following configuration, replace the environment variables with your values, and save:
166 | 
167 |     ```json
168 |     {
169 |       "mcpServers": {
170 |         "neo4j": {
171 |           "command": "./PATH/TO/toolbox",
172 |           "args": ["--prebuilt","neo4j","--stdio"],
173 |           "env": {
174 |             "NEO4J_URI": "",
175 |             "NEO4J_DATABASE": "",
176 |             "NEO4J_USERNAME": "",
177 |             "NEO4J_PASSWORD": ""
178 |           }
179 |         }
180 |       }
181 |     }
182 |     ```
183 | 
184 | 1.  Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
185 |     Settings > MCP**. You should see a green active status after the server is
186 |     successfully connected.
187 | {{% /tab %}}
188 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
189 | 
190 | 1.  Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
191 |     create a `.vscode` directory in your project root if it doesn't exist.
192 | 1.  Create a `.vscode/mcp.json` file if it doesn't exist and open it.
193 | 1.  Add the following configuration, replace the environment variables with your
194 |     values, and save:
195 | 
196 |     ```json
197 |     {
198 |     "mcp" : {
199 |         "servers": {
200 |         "neo4j": {
201 |             "command": "./PATH/TO/toolbox",
202 |             "args": ["--prebuilt","neo4j","--stdio"],
203 |             "env": {
204 |               "NEO4J_URI": "",
205 |               "NEO4J_DATABASE": "",
206 |               "NEO4J_USERNAME": "",
207 |               "NEO4J_PASSWORD": ""
208 |             }
209 |          }
210 |         }
211 |       }
212 |     }
213 |     ```
214 | {{% /tab %}}
215 | {{% tab header="Windsurf" lang="en" %}}
216 | 
217 | 1.  Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 |     Cascade assistant.
219 | 1.  Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1.  Add the following configuration, replace the environment variables with your
221 |     values, and save:
222 | 
223 |     ```json
224 |     {
225 |       "mcpServers": {
226 |         "neo4j": {
227 |           "command": "./PATH/TO/toolbox",
228 |           "args": ["--prebuilt","neo4j","--stdio"],
229 |           "env": {
230 |             "NEO4J_URI": "",
231 |             "NEO4J_DATABASE": "",
232 |             "NEO4J_USERNAME": "",
233 |             "NEO4J_PASSWORD": ""
234 |           }
235 |         }
236 |       }
237 |     }
238 |     ```
239 | {{% /tab %}}
240 | {{% tab header="Gemini CLI" lang="en" %}}
241 | 
242 | 1.  Install the [Gemini
243 |     CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
244 | 1.  In your working directory, create a folder named `.gemini`. Within it,
245 |     create a `settings.json` file.
246 | 1.  Add the following configuration, replace the environment variables with your
247 |     values, and then save:
248 | 
249 |     ```json
250 |     {
251 |       "mcpServers": {
252 |         "neo4j": {
253 |           "command": "./PATH/TO/toolbox",
254 |           "args": ["--prebuilt","neo4j","--stdio"],
255 |           "env": {
256 |             "NEO4J_URI": "",
257 |             "NEO4J_DATABASE": "",
258 |             "NEO4J_USERNAME": "",
259 |             "NEO4J_PASSWORD": ""
260 |           }
261 |         }
262 |       }
263 |     }
264 |     ```
265 | {{% /tab %}}
266 | {{% tab header="Gemini Code Assist" lang="en" %}}
267 | 
268 | 1.  Install the [Gemini Code
269 |     Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
270 |     extension in Visual Studio Code.
271 | 1.  Enable Agent Mode in Gemini Code Assist chat.
272 | 1.  In your working directory, create a folder named `.gemini`. Within it,
273 |     create a `settings.json` file.
274 | 1.  Add the following configuration, replace the environment variables with your
275 |     values, and then save:
276 | 
277 |     ```json
278 |     {
279 |       "mcpServers": {
280 |         "neo4j": {
281 |           "command": "./PATH/TO/toolbox",
282 |           "args": ["--prebuilt","neo4j","--stdio"],
283 |           "env": {
284 |             "NEO4J_URI": "",
285 |             "NEO4J_DATABASE": "",
286 |             "NEO4J_USERNAME": "",
287 |             "NEO4J_PASSWORD": ""
288 |           }
289 |         }
290 |       }
291 |     }
292 |     ```
293 | {{% /tab %}}
294 | {{< /tabpane >}}
295 | 
296 | ## Use Tools
297 | 
298 | Your AI tool is now connected to Neo4j using MCP. Try asking your AI assistant
299 | to get the graph schema or execute Cypher statements.
300 | 
301 | The following tools are available to the LLM:
302 | 
303 | 1.  **get_schema**: extracts the complete database schema, including details
304 |     about node labels, relationships, properties, constraints, and indexes.
305 | 1.  **execute_cypher**: executes any arbitrary Cypher statement.
306 | 
307 | {{< notice note >}}
308 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
309 | will adapt to the tools available, so this shouldn't affect most users.
310 | {{< /notice >}}
311 | 
```

--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/mysql_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: MySQL using MCP
  3 | type: docs
  4 | weight: 2
  5 | description: "Connect your IDE to MySQL using Toolbox."
  6 | ---
  7 | 
  8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
  9 | an open protocol for connecting Large Language Models (LLMs) to data sources
 10 | like MySQL. This guide covers how to use [MCP Toolbox for Databases][toolbox] to
 11 | expose your developer assistant tools to a MySQL instance:
 12 | 
 13 | * [Cursor][cursor]
 14 | * [Windsurf][windsurf] (Codium)
 15 | * [Visual Studio Code][vscode] (Copilot)
 16 | * [Cline][cline] (VS Code extension)
 17 | * [Claude desktop][claudedesktop]
 18 | * [Claude code][claudecode]
 19 | * [Gemini CLI][geminicli]
 20 | * [Gemini Code Assist][geminicodeassist]
 21 | 
 22 | [toolbox]: https://github.com/googleapis/genai-toolbox
 23 | [cursor]: #configure-your-mcp-client
 24 | [windsurf]: #configure-your-mcp-client
 25 | [vscode]: #configure-your-mcp-client
 26 | [cline]: #configure-your-mcp-client
 27 | [claudedesktop]: #configure-your-mcp-client
 28 | [claudecode]: #configure-your-mcp-client
 29 | [geminicli]: #configure-your-mcp-client
 30 | [geminicodeassist]: #configure-your-mcp-client
 31 | 
 32 | ## Set up the database
 33 | 
 34 | 1.  [Create or select a MySQL instance.](https://dev.mysql.com/downloads/installer/)
 35 | 
 36 | ## Install MCP Toolbox
 37 | 
 38 | 1. Download the latest version of Toolbox as a binary. Select the [correct
 39 |    binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
 40 |    to your OS and CPU architecture. You are required to use Toolbox version
 41 |    V0.10.0+:
 42 | 
 43 |    <!-- {x-release-please-start-version} -->
 44 |    {{< tabpane persist=header >}}
 45 | {{< tab header="linux/amd64" lang="bash" >}}
 46 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
 47 | {{< /tab >}}
 48 | 
 49 | {{< tab header="darwin/arm64" lang="bash" >}}
 50 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
 51 | {{< /tab >}}
 52 | 
 53 | {{< tab header="darwin/amd64" lang="bash" >}}
 54 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
 55 | {{< /tab >}}
 56 | 
 57 | {{< tab header="windows/amd64" lang="bash" >}}
 58 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
 59 | {{< /tab >}}
 60 | {{< /tabpane >}}
 61 |     <!-- {x-release-please-end} -->
 62 | 
 63 | 1. Make the binary executable:
 64 | 
 65 |     ```bash
 66 |     chmod +x toolbox
 67 |     ```
 68 | 
 69 | 1. Verify the installation:
 70 | 
 71 |     ```bash
 72 |     ./toolbox --version
 73 |     ```
 74 | 
 75 | ## Configure your MCP Client
 76 | 
 77 | {{< tabpane text=true >}}
 78 | {{% tab header="Claude code" lang="en" %}}
 79 | 
 80 | 1.  Install [Claude
 81 |     Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
 82 | 1.  Create a `.mcp.json` file in your project root if it doesn't exist.
 83 | 1.  Add the following configuration, replace the environment variables with your
 84 |     values, and save:
 85 | 
 86 |     ```json
 87 |     {
 88 |       "mcpServers": {
 89 |         "mysql": {
 90 |           "command": "./PATH/TO/toolbox",
 91 |           "args": ["--prebuilt", "mysql", "--stdio"],
 92 |           "env": {
 93 |             "MYSQL_HOST": "",
 94 |             "MYSQL_PORT": "",
 95 |             "MYSQL_DATABASE": "",
 96 |             "MYSQL_USER": "",
 97 |             "MYSQL_PASSWORD": ""
 98 |           }
 99 |         }
100 |       }
101 |     }
102 |     ```
103 | 
104 | 1.  Restart Claude code to apply the new configuration.
105 | {{% /tab %}}
106 | {{% tab header="Claude desktop" lang="en" %}}
107 | 
108 | 1.  Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
109 | 1.  Under the Developer tab, tap Edit Config to open the configuration file.
110 | 1.  Add the following configuration, replace the environment variables with your
111 |     values, and save:
112 | 
113 |     ```json
114 |     {
115 |       "mcpServers": {
116 |         "mysql": {
117 |           "command": "./PATH/TO/toolbox",
118 |           "args": ["--prebuilt", "mysql", "--stdio"],
119 |           "env": {
120 |             "MYSQL_HOST": "",
121 |             "MYSQL_PORT": "",
122 |             "MYSQL_DATABASE": "",
123 |             "MYSQL_USER": "",
124 |             "MYSQL_PASSWORD": ""
125 |           }
126 |         }
127 |       }
128 |     }
129 |     ```
130 | 
131 | 1.  Restart Claude desktop.
132 | 1.  From the new chat screen, you should see a hammer (MCP) icon appear with the
133 |     new MCP server available.
134 | {{% /tab %}}
135 | {{% tab header="Cline" lang="en" %}}
136 | 
137 | 1.  Open the [Cline](https://github.com/cline/cline) extension in VS Code and
138 |     tap the **MCP Servers** icon.
139 | 1.  Tap Configure MCP Servers to open the configuration file.
140 | 1.  Add the following configuration, replace the environment variables with your
141 |     values, and save:
142 | 
143 |     ```json
144 |     {
145 |       "mcpServers": {
146 |         "mysql": {
147 |           "command": "./PATH/TO/toolbox",
148 |           "args": ["--prebuilt", "mysql", "--stdio"],
149 |           "env": {
150 |             "MYSQL_HOST": "",
151 |             "MYSQL_PORT": "",
152 |             "MYSQL_DATABASE": "",
153 |             "MYSQL_USER": "",
154 |             "MYSQL_PASSWORD": ""
155 |           }
156 |         }
157 |       }
158 |     }
159 |     ```
160 | 
161 | 1.  You should see a green active status after the server is successfully
162 |     connected.
163 | {{% /tab %}}
164 | {{% tab header="Cursor" lang="en" %}}
165 | 
166 | 1.  Create a `.cursor` directory in your project root if it doesn't exist.
167 | 1.  Create a `.cursor/mcp.json` file if it doesn't exist and open it.
168 | 1.  Add the following configuration, replace the environment variables with your
169 |     values, and save:
170 | 
171 |     ```json
172 |     {
173 |       "mcpServers": {
174 |         "mysql": {
175 |           "command": "./PATH/TO/toolbox",
176 |           "args": ["--prebuilt", "mysql", "--stdio"],
177 |           "env": {
178 |             "MYSQL_HOST": "",
179 |             "MYSQL_PORT": "",
180 |             "MYSQL_DATABASE": "",
181 |             "MYSQL_USER": "",
182 |             "MYSQL_PASSWORD": ""
183 |           }
184 |         }
185 |       }
186 |     }
187 |     ```
188 | 
189 | 1.  Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
190 |     Settings > MCP**. You should see a green active status after the server is
191 |     successfully connected.
192 | {{% /tab %}}
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 | 
195 | 1.  Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 |     create a `.vscode` directory in your project root if it doesn't exist.
197 | 1.  Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1.  Add the following configuration, replace the environment variables with your
199 |     values, and save:
200 | 
201 |     ```json
202 |     {
203 |       "servers": {
204 |         "mysql": {
205 |           "command": "./PATH/TO/toolbox",
206 |           "args": ["--prebuilt","mysql","--stdio"],
207 |           "env": {
208 |             "MYSQL_HOST": "",
209 |             "MYSQL_PORT": "",
210 |             "MYSQL_DATABASE": "",
211 |             "MYSQL_USER": "",
212 |             "MYSQL_PASSWORD": ""
213 |           }
214 |         }
215 |       }
216 |     }
217 |     ```
218 | {{% /tab %}}
219 | {{% tab header="Windsurf" lang="en" %}}
220 | 
221 | 1.  Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
222 |     Cascade assistant.
223 | 1.  Tap on the hammer (MCP) icon, then Configure to open the configuration file.
224 | 1.  Add the following configuration, replace the environment variables with your
225 |     values, and save:
226 | 
227 |     ```json
228 |     {
229 |       "mcpServers": {
230 |         "mysql": {
231 |           "command": "./PATH/TO/toolbox",
232 |           "args": ["--prebuilt","mysql","--stdio"],
233 |           "env": {
234 |             "MYSQL_HOST": "",
235 |             "MYSQL_PORT": "",
236 |             "MYSQL_DATABASE": "",
237 |             "MYSQL_USER": "",
238 |             "MYSQL_PASSWORD": ""
239 |           }
240 |         }
241 |       }
242 |     }
243 |     ```
244 | {{% /tab %}}
245 | {{% tab header="Gemini CLI" lang="en" %}}
246 | 
247 | 1.  Install the [Gemini
248 |     CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
249 | 1.  In your working directory, create a folder named `.gemini`. Within it,
250 |     create a `settings.json` file.
251 | 1.  Add the following configuration, replace the environment variables with your
252 |     values, and then save:
253 | 
254 |     ```json
255 |     {
256 |       "mcpServers": {
257 |         "mysql": {
258 |           "command": "./PATH/TO/toolbox",
259 |           "args": ["--prebuilt","mysql","--stdio"],
260 |           "env": {
261 |             "MYSQL_HOST": "",
262 |             "MYSQL_PORT": "",
263 |             "MYSQL_DATABASE": "",
264 |             "MYSQL_USER": "",
265 |             "MYSQL_PASSWORD": ""
266 |           }
267 |         }
268 |       }
269 |     }
270 |     ```
271 | {{% /tab %}}
272 | {{% tab header="Gemini Code Assist" lang="en" %}}
273 | 
274 | 1.  Install the [Gemini Code
275 |     Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
276 |     extension in Visual Studio Code.
277 | 1.  Enable Agent Mode in Gemini Code Assist chat.
278 | 1.  In your working directory, create a folder named `.gemini`. Within it,
279 |     create a `settings.json` file.
280 | 1.  Add the following configuration, replace the environment variables with your
281 |     values, and then save:
282 | 
283 |     ```json
284 |     {
285 |       "mcpServers": {
286 |         "mysql": {
287 |           "command": "./PATH/TO/toolbox",
288 |           "args": ["--prebuilt","mysql","--stdio"],
289 |           "env": {
290 |             "MYSQL_HOST": "",
291 |             "MYSQL_PORT": "",
292 |             "MYSQL_DATABASE": "",
293 |             "MYSQL_USER": "",
294 |             "MYSQL_PASSWORD": ""
295 |           }
296 |         }
297 |       }
298 |     }
299 |     ```
300 | {{% /tab %}}
301 | {{< /tabpane >}}
302 | 
303 | ## Use Tools
304 | 
305 | Your AI tool is now connected to MySQL using MCP. Try asking your AI assistant
306 | to list tables, create a table, or define and execute other SQL statements.
307 | 
308 | The following tools are available to the LLM:
309 | 
310 | 1.  **list_tables**: lists tables and descriptions
311 | 1.  **execute_sql**: execute any SQL statement
312 | 
313 | {{< notice note >}}
314 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
315 | will adapt to the tools available, so this shouldn't affect most users.
316 | {{< /notice >}}
317 | 
```

--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/mssql_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: SQL Server using MCP
  3 | type: docs
  4 | weight: 2
  5 | description: "Connect your IDE to SQL Server using Toolbox."
  6 | ---
  7 | 
  8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
  9 | an open protocol for connecting Large Language Models (LLMs) to data sources
 10 | like SQL Server. This guide covers how to use [MCP Toolbox for
 11 | Databases][toolbox] to expose your developer assistant tools to a SQL Server
 12 | instance:
 13 | 
 14 | * [Cursor][cursor]
 15 | * [Windsurf][windsurf] (Codium)
 16 | * [Visual Studio Code][vscode] (Copilot)
 17 | * [Cline][cline] (VS Code extension)
 18 | * [Claude desktop][claudedesktop]
 19 | * [Claude code][claudecode]
 20 | * [Gemini CLI][geminicli]
 21 | * [Gemini Code Assist][geminicodeassist]
 22 | 
 23 | [toolbox]: https://github.com/googleapis/genai-toolbox
 24 | [cursor]: #configure-your-mcp-client
 25 | [windsurf]: #configure-your-mcp-client
 26 | [vscode]: #configure-your-mcp-client
 27 | [cline]: #configure-your-mcp-client
 28 | [claudedesktop]: #configure-your-mcp-client
 29 | [claudecode]: #configure-your-mcp-client
 30 | [geminicli]: #configure-your-mcp-client
 31 | [geminicodeassist]: #configure-your-mcp-client
 32 | 
 33 | ## Set up the database
 34 | 
 35 | 1.  [Create or select a SQL Server
 36 |     instance.](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
 37 | 
 38 | ## Install MCP Toolbox
 39 | 
 40 | 1. Download the latest version of Toolbox as a binary. Select the [correct
 41 |    binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
 42 |    to your OS and CPU architecture. You are required to use Toolbox version
 43 |    V0.10.0+:
 44 | 
 45 |    <!-- {x-release-please-start-version} -->
 46 |    {{< tabpane persist=header >}}
 47 | {{< tab header="linux/amd64" lang="bash" >}}
 48 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
 49 | {{< /tab >}}
 50 | 
 51 | {{< tab header="darwin/arm64" lang="bash" >}}
 52 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
 53 | {{< /tab >}}
 54 | 
 55 | {{< tab header="darwin/amd64" lang="bash" >}}
 56 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
 57 | {{< /tab >}}
 58 | 
 59 | {{< tab header="windows/amd64" lang="bash" >}}
 60 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
 61 | {{< /tab >}}
 62 | {{< /tabpane >}}
 63 |     <!-- {x-release-please-end} -->
 64 | 
 65 | 1. Make the binary executable:
 66 | 
 67 |     ```bash
 68 |     chmod +x toolbox
 69 |     ```
 70 | 
 71 | 1. Verify the installation:
 72 | 
 73 |     ```bash
 74 |     ./toolbox --version
 75 |     ```
 76 | 
 77 | ## Configure your MCP Client
 78 | 
 79 | {{< tabpane text=true >}}
 80 | {{% tab header="Claude code" lang="en" %}}
 81 | 
 82 | 1.  Install [Claude
 83 |     Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
 84 | 1.  Create a `.mcp.json` file in your project root if it doesn't exist.
 85 | 1.  Add the following configuration, replace the environment variables with your
 86 |     values, and save:
 87 | 
 88 |     ```json
 89 |     {
 90 |       "mcpServers": {
 91 |         "sqlserver": {
 92 |           "command": "./PATH/TO/toolbox",
 93 |           "args": ["--prebuilt","mssql","--stdio"],
 94 |           "env": {
 95 |             "MSSQL_HOST": "",
 96 |             "MSSQL_PORT": "",
 97 |             "MSSQL_DATABASE": "",
 98 |             "MSSQL_USER": "",
 99 |             "MSSQL_PASSWORD": ""
100 |           }
101 |         }
102 |       }
103 |     }
104 |     ```
105 | 
106 | 1.  Restart Claude code to apply the new configuration.
107 | {{% /tab %}}
108 | {{% tab header="Claude desktop" lang="en" %}}
109 | 
110 | 1.  Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
111 | 1.  Under the Developer tab, tap Edit Config to open the configuration file.
112 | 1.  Add the following configuration, replace the environment variables with your
113 |     values, and save:
114 | 
115 |     ```json
116 |     {
117 |       "mcpServers": {
118 |         "sqlserver": {
119 |           "command": "./PATH/TO/toolbox",
120 |           "args": ["--prebuilt","mssql","--stdio"],
121 |           "env": {
122 |             "MSSQL_HOST": "",
123 |             "MSSQL_PORT": "",
124 |             "MSSQL_DATABASE": "",
125 |             "MSSQL_USER": "",
126 |             "MSSQL_PASSWORD": ""
127 |           }
128 |         }
129 |       }
130 |     }
131 |     ```
132 | 
133 | 1.  Restart Claude desktop.
134 | 1.  From the new chat screen, you should see a hammer (MCP) icon appear with the
135 |     new MCP server available.
136 | {{% /tab %}}
137 | {{% tab header="Cline" lang="en" %}}
138 | 
139 | 1.  Open the [Cline](https://github.com/cline/cline) extension in VS Code and
140 |     tap the **MCP Servers** icon.
141 | 1.  Tap Configure MCP Servers to open the configuration file.
142 | 1.  Add the following configuration, replace the environment variables with your
143 |     values, and save:
144 | 
145 |     ```json
146 |     {
147 |       "mcpServers": {
148 |         "sqlserver": {
149 |           "command": "./PATH/TO/toolbox",
150 |           "args": ["--prebuilt","mssql","--stdio"],
151 |           "env": {
152 |             "MSSQL_HOST": "",
153 |             "MSSQL_PORT": "",
154 |             "MSSQL_DATABASE": "",
155 |             "MSSQL_USER": "",
156 |             "MSSQL_PASSWORD": ""
157 |           }
158 |         }
159 |       }
160 |     }
161 |     ```
162 | 
163 | 1.  You should see a green active status after the server is successfully
164 |     connected.
165 | {{% /tab %}}
166 | {{% tab header="Cursor" lang="en" %}}
167 | 
168 | 1.  Create a `.cursor` directory in your project root if it doesn't exist.
169 | 1.  Create a `.cursor/mcp.json` file if it doesn't exist and open it.
170 | 1.  Add the following configuration, replace the environment variables with your
171 |     values, and save:
172 | 
173 |     ```json
174 |     {
175 |       "mcpServers": {
176 |         "sqlserver": {
177 |           "command": "./PATH/TO/toolbox",
178 |           "args": ["--prebuilt","mssql","--stdio"],
179 |           "env": {
180 |             "MSSQL_HOST": "",
181 |             "MSSQL_PORT": "",
182 |             "MSSQL_DATABASE": "",
183 |             "MSSQL_USER": "",
184 |             "MSSQL_PASSWORD": ""
185 |           }
186 |         }
187 |       }
188 |     }
189 |     ```
190 | 
191 | 1.  Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
192 |     Settings > MCP**. You should see a green active status after the server is
193 |     successfully connected.
194 | {{% /tab %}}
195 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
196 | 
197 | 1.  Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
198 |     create a `.vscode` directory in your project root if it doesn't exist.
199 | 1.  Create a `.vscode/mcp.json` file if it doesn't exist and open it.
200 | 1.  Add the following configuration, replace the environment variables with your
201 |     values, and save:
202 | 
203 |     ```json
204 |     {
205 |       "servers": {
206 |         "mssql": {
207 |           "command": "./PATH/TO/toolbox",
208 |           "args": ["--prebuilt","mssql","--stdio"],
209 |           "env": {
210 |             "MSSQL_HOST": "",
211 |             "MSSQL_PORT": "",
212 |             "MSSQL_DATABASE": "",
213 |             "MSSQL_USER": "",
214 |             "MSSQL_PASSWORD": ""
215 |           }
216 |         }
217 |       }
218 |     }
219 |     ```
220 | {{% /tab %}}
221 | {{% tab header="Windsurf" lang="en" %}}
222 | 
223 | 1.  Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
224 |     Cascade assistant.
225 | 1.  Tap on the hammer (MCP) icon, then Configure to open the configuration file.
226 | 1.  Add the following configuration, replace the environment variables with your
227 |     values, and save:
228 | 
229 |     ```json
230 |     {
231 |       "mcpServers": {
232 |         "sqlserver": {
233 |           "command": "./PATH/TO/toolbox",
234 |           "args": ["--prebuilt","mssql","--stdio"],
235 |           "env": {
236 |             "MSSQL_HOST": "",
237 |             "MSSQL_PORT": "",
238 |             "MSSQL_DATABASE": "",
239 |             "MSSQL_USER": "",
240 |             "MSSQL_PASSWORD": ""
241 |           }
242 |         }
243 |       }
244 |     }
245 |     ```
246 | {{% /tab %}}
247 | {{% tab header="Gemini CLI" lang="en" %}}
248 | 
249 | 1.  Install the [Gemini
250 |     CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
251 | 1.  In your working directory, create a folder named `.gemini`. Within it,
252 |     create a `settings.json` file.
253 | 1.  Add the following configuration, replace the environment variables with your
254 |     values, and then save:
255 | 
256 |     ```json
257 |     {
258 |       "mcpServers": {
259 |         "sqlserver": {
260 |           "command": "./PATH/TO/toolbox",
261 |           "args": ["--prebuilt","mssql","--stdio"],
262 |           "env": {
263 |             "MSSQL_HOST": "",
264 |             "MSSQL_PORT": "",
265 |             "MSSQL_DATABASE": "",
266 |             "MSSQL_USER": "",
267 |             "MSSQL_PASSWORD": ""
268 |           }
269 |         }
270 |       }
271 |     }
272 |     ```
273 | {{% /tab %}}
274 | {{% tab header="Gemini Code Assist" lang="en" %}}
275 | 
276 | 1.  Install the [Gemini Code
277 |     Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
278 |     extension in Visual Studio Code.
279 | 1.  Enable Agent Mode in Gemini Code Assist chat.
280 | 1.  In your working directory, create a folder named `.gemini`. Within it,
281 |     create a `settings.json` file.
282 | 1.  Add the following configuration, replace the environment variables with your
283 |     values, and then save:
284 | 
285 |     ```json
286 |     {
287 |       "mcpServers": {
288 |         "sqlserver": {
289 |           "command": "./PATH/TO/toolbox",
290 |           "args": ["--prebuilt","mssql","--stdio"],
291 |           "env": {
292 |             "MSSQL_HOST": "",
293 |             "MSSQL_PORT": "",
294 |             "MSSQL_DATABASE": "",
295 |             "MSSQL_USER": "",
296 |             "MSSQL_PASSWORD": ""
297 |           }
298 |         }
299 |       }
300 |     }
301 |     ```
302 | {{% /tab %}}
303 | {{< /tabpane >}}
304 | 
305 | ## Use Tools
306 | 
307 | Your AI tool is now connected to SQL Server using MCP. Try asking your AI
308 | assistant to list tables, create a table, or define and execute other SQL
309 | statements.
310 | 
311 | The following tools are available to the LLM:
312 | 
313 | 1.  **list_tables**: lists tables and descriptions
314 | 1.  **execute_sql**: execute any SQL statement
315 | 
316 | {{< notice note >}}
317 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
318 | will adapt to the tools available, so this shouldn't affect most users.
319 | {{< /notice >}}
320 | 
```

--------------------------------------------------------------------------------
/tests/alloydbpg/alloydb_pg_integration_test.go:
--------------------------------------------------------------------------------

```go
  1 | // Copyright 2024 Google LLC
  2 | //
  3 | // Licensed under the Apache License, Version 2.0 (the "License");
  4 | // you may not use this file except in compliance with the License.
  5 | // You may obtain a copy of the License at
  6 | //
  7 | //     http://www.apache.org/licenses/LICENSE-2.0
  8 | //
  9 | // Unless required by applicable law or agreed to in writing, software
 10 | // distributed under the License is distributed on an "AS IS" BASIS,
 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 | // See the License for the specific language governing permissions and
 13 | // limitations under the License.
 14 | 
 15 | package alloydbpg
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 	"net"
 21 | 	"os"
 22 | 	"regexp"
 23 | 	"strings"
 24 | 	"testing"
 25 | 	"time"
 26 | 
 27 | 	"cloud.google.com/go/alloydbconn"
 28 | 	"github.com/google/uuid"
 29 | 	"github.com/googleapis/genai-toolbox/internal/testutils"
 30 | 	"github.com/googleapis/genai-toolbox/tests"
 31 | 	"github.com/jackc/pgx/v5/pgxpool"
 32 | )
 33 | 
 34 | var (
 35 | 	AlloyDBPostgresSourceKind = "alloydb-postgres"
 36 | 	AlloyDBPostgresToolKind   = "postgres-sql"
 37 | 	AlloyDBPostgresProject    = os.Getenv("ALLOYDB_POSTGRES_PROJECT")
 38 | 	AlloyDBPostgresRegion     = os.Getenv("ALLOYDB_POSTGRES_REGION")
 39 | 	AlloyDBPostgresCluster    = os.Getenv("ALLOYDB_POSTGRES_CLUSTER")
 40 | 	AlloyDBPostgresInstance   = os.Getenv("ALLOYDB_POSTGRES_INSTANCE")
 41 | 	AlloyDBPostgresDatabase   = os.Getenv("ALLOYDB_POSTGRES_DATABASE")
 42 | 	AlloyDBPostgresUser       = os.Getenv("ALLOYDB_POSTGRES_USER")
 43 | 	AlloyDBPostgresPass       = os.Getenv("ALLOYDB_POSTGRES_PASS")
 44 | )
 45 | 
 46 | func getAlloyDBPgVars(t *testing.T) map[string]any {
 47 | 	switch "" {
 48 | 	case AlloyDBPostgresProject:
 49 | 		t.Fatal("'ALLOYDB_POSTGRES_PROJECT' not set")
 50 | 	case AlloyDBPostgresRegion:
 51 | 		t.Fatal("'ALLOYDB_POSTGRES_REGION' not set")
 52 | 	case AlloyDBPostgresCluster:
 53 | 		t.Fatal("'ALLOYDB_POSTGRES_CLUSTER' not set")
 54 | 	case AlloyDBPostgresInstance:
 55 | 		t.Fatal("'ALLOYDB_POSTGRES_INSTANCE' not set")
 56 | 	case AlloyDBPostgresDatabase:
 57 | 		t.Fatal("'ALLOYDB_POSTGRES_DATABASE' not set")
 58 | 	case AlloyDBPostgresUser:
 59 | 		t.Fatal("'ALLOYDB_POSTGRES_USER' not set")
 60 | 	case AlloyDBPostgresPass:
 61 | 		t.Fatal("'ALLOYDB_POSTGRES_PASS' not set")
 62 | 	}
 63 | 	return map[string]any{
 64 | 		"kind":     AlloyDBPostgresSourceKind,
 65 | 		"project":  AlloyDBPostgresProject,
 66 | 		"cluster":  AlloyDBPostgresCluster,
 67 | 		"instance": AlloyDBPostgresInstance,
 68 | 		"region":   AlloyDBPostgresRegion,
 69 | 		"database": AlloyDBPostgresDatabase,
 70 | 		"user":     AlloyDBPostgresUser,
 71 | 		"password": AlloyDBPostgresPass,
 72 | 	}
 73 | }
 74 | 
 75 | // Copied over from  alloydb_pg.go
 76 | func getAlloyDBDialOpts(ipType string) ([]alloydbconn.DialOption, error) {
 77 | 	switch strings.ToLower(ipType) {
 78 | 	case "private":
 79 | 		return []alloydbconn.DialOption{alloydbconn.WithPrivateIP()}, nil
 80 | 	case "public":
 81 | 		return []alloydbconn.DialOption{alloydbconn.WithPublicIP()}, nil
 82 | 	default:
 83 | 		return nil, fmt.Errorf("invalid ipType %s", ipType)
 84 | 	}
 85 | }
 86 | 
 87 | // Copied over from  alloydb_pg.go
 88 | func initAlloyDBPgConnectionPool(project, region, cluster, instance, ipType, user, pass, dbname string) (*pgxpool.Pool, error) {
 89 | 	// Configure the driver to connect to the database
 90 | 	dsn := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", user, pass, dbname)
 91 | 	config, err := pgxpool.ParseConfig(dsn)
 92 | 	if err != nil {
 93 | 		return nil, fmt.Errorf("unable to parse connection uri: %w", err)
 94 | 	}
 95 | 
 96 | 	// Create a new dialer with options
 97 | 	dialOpts, err := getAlloyDBDialOpts(ipType)
 98 | 	if err != nil {
 99 | 		return nil, err
100 | 	}
101 | 	d, err := alloydbconn.NewDialer(context.Background(), alloydbconn.WithDefaultDialOptions(dialOpts...))
102 | 	if err != nil {
103 | 		return nil, fmt.Errorf("unable to parse connection uri: %w", err)
104 | 	}
105 | 
106 | 	// Tell the driver to use the AlloyDB Go Connector to create connections
107 | 	i := fmt.Sprintf("projects/%s/locations/%s/clusters/%s/instances/%s", project, region, cluster, instance)
108 | 	config.ConnConfig.DialFunc = func(ctx context.Context, _ string, instance string) (net.Conn, error) {
109 | 		return d.Dial(ctx, i)
110 | 	}
111 | 
112 | 	// Interact with the driver directly as you normally would
113 | 	pool, err := pgxpool.NewWithConfig(context.Background(), config)
114 | 	if err != nil {
115 | 		return nil, err
116 | 	}
117 | 	return pool, nil
118 | }
119 | 
120 | func TestAlloyDBPgToolEndpoints(t *testing.T) {
121 | 	sourceConfig := getAlloyDBPgVars(t)
122 | 	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
123 | 	defer cancel()
124 | 
125 | 	var args []string
126 | 
127 | 	pool, err := initAlloyDBPgConnectionPool(AlloyDBPostgresProject, AlloyDBPostgresRegion, AlloyDBPostgresCluster, AlloyDBPostgresInstance, "public", AlloyDBPostgresUser, AlloyDBPostgresPass, AlloyDBPostgresDatabase)
128 | 	if err != nil {
129 | 		t.Fatalf("unable to create AlloyDB connection pool: %s", err)
130 | 	}
131 | 
132 | 	// create table name with UUID
133 | 	tableNameParam := "param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
134 | 	tableNameAuth := "auth_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
135 | 	tableNameTemplateParam := "template_param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
136 | 
137 | 	// set up data for param tool
138 | 	createParamTableStmt, insertParamTableStmt, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, paramTestParams := tests.GetPostgresSQLParamToolInfo(tableNameParam)
139 | 	teardownTable1 := tests.SetupPostgresSQLTable(t, ctx, pool, createParamTableStmt, insertParamTableStmt, tableNameParam, paramTestParams)
140 | 	defer teardownTable1(t)
141 | 
142 | 	// set up data for auth tool
143 | 	createAuthTableStmt, insertAuthTableStmt, authToolStmt, authTestParams := tests.GetPostgresSQLAuthToolInfo(tableNameAuth)
144 | 	teardownTable2 := tests.SetupPostgresSQLTable(t, ctx, pool, createAuthTableStmt, insertAuthTableStmt, tableNameAuth, authTestParams)
145 | 	defer teardownTable2(t)
146 | 
147 | 	// Write config into a file and pass it to command
148 | 	toolsFile := tests.GetToolsConfig(sourceConfig, AlloyDBPostgresToolKind, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, authToolStmt)
149 | 	toolsFile = tests.AddExecuteSqlConfig(t, toolsFile, "postgres-execute-sql")
150 | 	tmplSelectCombined, tmplSelectFilterCombined := tests.GetPostgresSQLTmplToolStatement()
151 | 	toolsFile = tests.AddTemplateParamConfig(t, toolsFile, AlloyDBPostgresToolKind, tmplSelectCombined, tmplSelectFilterCombined, "")
152 | 
153 | 	cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
154 | 	if err != nil {
155 | 		t.Fatalf("command initialization returned an error: %s", err)
156 | 	}
157 | 	defer cleanup()
158 | 
159 | 	waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
160 | 	defer cancel()
161 | 	out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out)
162 | 	if err != nil {
163 | 		t.Logf("toolbox command logs: \n%s", out)
164 | 		t.Fatalf("toolbox didn't start successfully: %s", err)
165 | 	}
166 | 
167 | 	// Get configs for tests
168 | 	select1Want, failInvocationWant, createTableStatement, mcpSelect1Want := tests.GetPostgresWants()
169 | 
170 | 	// Run tests
171 | 	tests.RunToolGetTest(t)
172 | 	tests.RunToolInvokeTest(t, select1Want)
173 | 	tests.RunMCPToolCallMethod(t, failInvocationWant, mcpSelect1Want)
174 | 	tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
175 | 	tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam)
176 | }
177 | 
178 | // Test connection with different IP type
179 | func TestAlloyDBPgIpConnection(t *testing.T) {
180 | 	sourceConfig := getAlloyDBPgVars(t)
181 | 
182 | 	tcs := []struct {
183 | 		name   string
184 | 		ipType string
185 | 	}{
186 | 		{
187 | 			name:   "public ip",
188 | 			ipType: "public",
189 | 		},
190 | 		{
191 | 			name:   "private ip",
192 | 			ipType: "private",
193 | 		},
194 | 	}
195 | 	for _, tc := range tcs {
196 | 		t.Run(tc.name, func(t *testing.T) {
197 | 			sourceConfig["ipType"] = tc.ipType
198 | 			err := tests.RunSourceConnectionTest(t, sourceConfig, AlloyDBPostgresToolKind)
199 | 			if err != nil {
200 | 				t.Fatalf("Connection test failure: %s", err)
201 | 			}
202 | 		})
203 | 	}
204 | }
205 | 
206 | // Test IAM connection
207 | func TestAlloyDBPgIAMConnection(t *testing.T) {
208 | 	getAlloyDBPgVars(t)
209 | 	// service account email used for IAM should trim the suffix
210 | 	serviceAccountEmail := strings.TrimSuffix(tests.ServiceAccountEmail, ".gserviceaccount.com")
211 | 
212 | 	noPassSourceConfig := map[string]any{
213 | 		"kind":     AlloyDBPostgresSourceKind,
214 | 		"project":  AlloyDBPostgresProject,
215 | 		"cluster":  AlloyDBPostgresCluster,
216 | 		"instance": AlloyDBPostgresInstance,
217 | 		"region":   AlloyDBPostgresRegion,
218 | 		"database": AlloyDBPostgresDatabase,
219 | 		"user":     serviceAccountEmail,
220 | 	}
221 | 
222 | 	noUserSourceConfig := map[string]any{
223 | 		"kind":     AlloyDBPostgresSourceKind,
224 | 		"project":  AlloyDBPostgresProject,
225 | 		"cluster":  AlloyDBPostgresCluster,
226 | 		"instance": AlloyDBPostgresInstance,
227 | 		"region":   AlloyDBPostgresRegion,
228 | 		"database": AlloyDBPostgresDatabase,
229 | 		"password": "random",
230 | 	}
231 | 
232 | 	noUserNoPassSourceConfig := map[string]any{
233 | 		"kind":     AlloyDBPostgresSourceKind,
234 | 		"project":  AlloyDBPostgresProject,
235 | 		"cluster":  AlloyDBPostgresCluster,
236 | 		"instance": AlloyDBPostgresInstance,
237 | 		"region":   AlloyDBPostgresRegion,
238 | 		"database": AlloyDBPostgresDatabase,
239 | 	}
240 | 	tcs := []struct {
241 | 		name         string
242 | 		sourceConfig map[string]any
243 | 		isErr        bool
244 | 	}{
245 | 		{
246 | 			name:         "no user no pass",
247 | 			sourceConfig: noUserNoPassSourceConfig,
248 | 			isErr:        false,
249 | 		},
250 | 		{
251 | 			name:         "no password",
252 | 			sourceConfig: noPassSourceConfig,
253 | 			isErr:        false,
254 | 		},
255 | 		{
256 | 			name:         "no user",
257 | 			sourceConfig: noUserSourceConfig,
258 | 			isErr:        true,
259 | 		},
260 | 	}
261 | 	for _, tc := range tcs {
262 | 		t.Run(tc.name, func(t *testing.T) {
263 | 			err := tests.RunSourceConnectionTest(t, tc.sourceConfig, AlloyDBPostgresToolKind)
264 | 			if err != nil {
265 | 				if tc.isErr {
266 | 					return
267 | 				}
268 | 				t.Fatalf("Connection test failure: %s", err)
269 | 			}
270 | 			if tc.isErr {
271 | 				t.Fatalf("Expected error but test passed.")
272 | 			}
273 | 		})
274 | 	}
275 | }
276 | 
```

--------------------------------------------------------------------------------
/internal/tools/bigquery/bigquerysearchcatalog/bigquerysearchcatalog.go:
--------------------------------------------------------------------------------

```go
  1 | // Copyright 2025 Google LLC
  2 | //
  3 | // Licensed under the Apache License, Version 2.0 (the "License");
  4 | // you may not use this file except in compliance with the License.
  5 | // You may obtain a copy of the License at
  6 | //
  7 | //     http://www.apache.org/licenses/LICENSE-2.0
  8 | //
  9 | // Unless required by applicable law or agreed to in writing, software
 10 | // distributed under the License is distributed on an "AS IS" BASIS,
 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 | // See the License for the specific language governing permissions and
 13 | // limitations under the License.
 14 | 
 15 | package bigquerysearchcatalog
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 	"strings"
 21 | 
 22 | 	dataplexapi "cloud.google.com/go/dataplex/apiv1"
 23 | 	dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb"
 24 | 	"github.com/goccy/go-yaml"
 25 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 26 | 	bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
 27 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 28 | 	"google.golang.org/api/iterator"
 29 | )
 30 | 
 31 | const kind string = "bigquery-search-catalog"
 32 | 
 33 | func init() {
 34 | 	if !tools.Register(kind, newConfig) {
 35 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 36 | 	}
 37 | }
 38 | 
 39 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 40 | 	actual := Config{Name: name}
 41 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 42 | 		return nil, err
 43 | 	}
 44 | 	return actual, nil
 45 | }
 46 | 
 47 | type compatibleSource interface {
 48 | 	MakeDataplexCatalogClient() func() (*dataplexapi.CatalogClient, bigqueryds.DataplexClientCreator, error)
 49 | 	BigQueryProject() string
 50 | 	UseClientAuthorization() bool
 51 | }
 52 | 
 53 | // validate compatible sources are still compatible
 54 | var _ compatibleSource = &bigqueryds.Source{}
 55 | 
 56 | var compatibleSources = [...]string{bigqueryds.SourceKind}
 57 | 
 58 | type Config struct {
 59 | 	Name         string   `yaml:"name" validate:"required"`
 60 | 	Kind         string   `yaml:"kind" validate:"required"`
 61 | 	Source       string   `yaml:"source" validate:"required"`
 62 | 	Description  string   `yaml:"description"`
 63 | 	AuthRequired []string `yaml:"authRequired"`
 64 | }
 65 | 
 66 | // validate interface
 67 | var _ tools.ToolConfig = Config{}
 68 | 
 69 | func (cfg Config) ToolConfigKind() string {
 70 | 	return kind
 71 | }
 72 | 
 73 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 74 | 	// Initialize the search configuration with the provided sources
 75 | 	rawS, ok := srcs[cfg.Source]
 76 | 	if !ok {
 77 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 78 | 	}
 79 | 	// verify the source is compatible
 80 | 	s, ok := rawS.(compatibleSource)
 81 | 	if !ok {
 82 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
 83 | 	}
 84 | 
 85 | 	// Get the Dataplex client using the method from the source
 86 | 	makeCatalogClient := s.MakeDataplexCatalogClient()
 87 | 
 88 | 	prompt := tools.NewStringParameter("prompt", "Prompt representing search intention. Do not rewrite the prompt.")
 89 | 	datasetIds := tools.NewArrayParameterWithDefault("datasetIds", []any{}, "Array of dataset IDs.", tools.NewStringParameter("datasetId", "The IDs of the bigquery dataset."))
 90 | 	projectIds := tools.NewArrayParameterWithDefault("projectIds", []any{}, "Array of project IDs.", tools.NewStringParameter("projectId", "The IDs of the bigquery project."))
 91 | 	types := tools.NewArrayParameterWithDefault("types", []any{}, "Array of data types to filter by.", tools.NewStringParameter("type", "The type of the data. Accepted values are: CONNECTION, POLICY, DATASET, MODEL, ROUTINE, TABLE, VIEW."))
 92 | 	pageSize := tools.NewIntParameterWithDefault("pageSize", 5, "Number of results in the search page.")
 93 | 	parameters := tools.Parameters{prompt, datasetIds, projectIds, types, pageSize}
 94 | 
 95 | 	description := "Use this tool to find tables, views, models, routines or connections."
 96 | 	if cfg.Description != "" {
 97 | 		description = cfg.Description
 98 | 	}
 99 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, description, cfg.AuthRequired, parameters)
100 | 
101 | 	t := Tool{
102 | 		Name:              cfg.Name,
103 | 		Kind:              kind,
104 | 		Parameters:        parameters,
105 | 		AuthRequired:      cfg.AuthRequired,
106 | 		UseClientOAuth:    s.UseClientAuthorization(),
107 | 		MakeCatalogClient: makeCatalogClient,
108 | 		ProjectID:         s.BigQueryProject(),
109 | 		manifest: tools.Manifest{
110 | 			Description:  cfg.Description,
111 | 			Parameters:   parameters.Manifest(),
112 | 			AuthRequired: cfg.AuthRequired,
113 | 		},
114 | 		mcpManifest: mcpManifest,
115 | 	}
116 | 	return t, nil
117 | }
118 | 
119 | type Tool struct {
120 | 	Name              string
121 | 	Kind              string
122 | 	Parameters        tools.Parameters
123 | 	AuthRequired      []string
124 | 	UseClientOAuth    bool
125 | 	MakeCatalogClient func() (*dataplexapi.CatalogClient, bigqueryds.DataplexClientCreator, error)
126 | 	ProjectID         string
127 | 	manifest          tools.Manifest
128 | 	mcpManifest       tools.McpManifest
129 | }
130 | 
131 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
132 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
133 | }
134 | 
135 | func (t Tool) RequiresClientAuthorization() bool {
136 | 	return t.UseClientOAuth
137 | }
138 | 
139 | func constructSearchQueryHelper(predicate string, operator string, items []string) string {
140 | 	if len(items) == 0 {
141 | 		return ""
142 | 	}
143 | 
144 | 	if len(items) == 1 {
145 | 		return predicate + operator + items[0]
146 | 	}
147 | 
148 | 	var builder strings.Builder
149 | 	builder.WriteString("(")
150 | 	for i, item := range items {
151 | 		if i > 0 {
152 | 			builder.WriteString(" OR ")
153 | 		}
154 | 		builder.WriteString(predicate)
155 | 		builder.WriteString(operator)
156 | 		builder.WriteString(item)
157 | 	}
158 | 	builder.WriteString(")")
159 | 	return builder.String()
160 | }
161 | 
162 | func constructSearchQuery(projectIds []string, datasetIds []string, types []string) string {
163 | 	queryParts := []string{}
164 | 
165 | 	if clause := constructSearchQueryHelper("projectid", "=", projectIds); clause != "" {
166 | 		queryParts = append(queryParts, clause)
167 | 	}
168 | 
169 | 	if clause := constructSearchQueryHelper("parent", "=", datasetIds); clause != "" {
170 | 		queryParts = append(queryParts, clause)
171 | 	}
172 | 
173 | 	if clause := constructSearchQueryHelper("type", "=", types); clause != "" {
174 | 		queryParts = append(queryParts, clause)
175 | 	}
176 | 	queryParts = append(queryParts, "system=bigquery")
177 | 
178 | 	return strings.Join(queryParts, " AND ")
179 | }
180 | 
181 | type Response struct {
182 | 	DisplayName   string
183 | 	Description   string
184 | 	Type          string
185 | 	Resource      string
186 | 	DataplexEntry string
187 | }
188 | 
189 | var typeMap = map[string]string{
190 | 	"bigquery-connection":  "CONNECTION",
191 | 	"bigquery-data-policy": "POLICY",
192 | 	"bigquery-dataset":     "DATASET",
193 | 	"bigquery-model":       "MODEL",
194 | 	"bigquery-routine":     "ROUTINE",
195 | 	"bigquery-table":       "TABLE",
196 | 	"bigquery-view":        "VIEW",
197 | }
198 | 
199 | func ExtractType(resourceString string) string {
200 | 	lastIndex := strings.LastIndex(resourceString, "/")
201 | 	if lastIndex == -1 {
202 | 		// No "/" found, return the original string
203 | 		return resourceString
204 | 	}
205 | 	return typeMap[resourceString[lastIndex+1:]]
206 | }
207 | 
208 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
209 | 	paramsMap := params.AsMap()
210 | 	pageSize := int32(paramsMap["pageSize"].(int))
211 | 	prompt, _ := paramsMap["prompt"].(string)
212 | 	projectIdSlice, err := tools.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string")
213 | 	if err != nil {
214 | 		return nil, fmt.Errorf("can't convert projectIds to array of strings: %s", err)
215 | 	}
216 | 	projectIds := projectIdSlice.([]string)
217 | 	datasetIdSlice, err := tools.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string")
218 | 	if err != nil {
219 | 		return nil, fmt.Errorf("can't convert datasetIds to array of strings: %s", err)
220 | 	}
221 | 	datasetIds := datasetIdSlice.([]string)
222 | 	typesSlice, err := tools.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string")
223 | 	if err != nil {
224 | 		return nil, fmt.Errorf("can't convert types to array of strings: %s", err)
225 | 	}
226 | 	types := typesSlice.([]string)
227 | 
228 | 	req := &dataplexpb.SearchEntriesRequest{
229 | 		Query:          fmt.Sprintf("%s %s", prompt, constructSearchQuery(projectIds, datasetIds, types)),
230 | 		Name:           fmt.Sprintf("projects/%s/locations/global", t.ProjectID),
231 | 		PageSize:       pageSize,
232 | 		SemanticSearch: true,
233 | 	}
234 | 
235 | 	catalogClient, dataplexClientCreator, _ := t.MakeCatalogClient()
236 | 
237 | 	if t.UseClientOAuth {
238 | 		tokenStr, err := accessToken.ParseBearerToken()
239 | 		if err != nil {
240 | 			return nil, fmt.Errorf("error parsing access token: %w", err)
241 | 		}
242 | 		catalogClient, err = dataplexClientCreator(tokenStr)
243 | 		if err != nil {
244 | 			return nil, fmt.Errorf("error creating client from OAuth access token: %w", err)
245 | 		}
246 | 	}
247 | 
248 | 	it := catalogClient.SearchEntries(ctx, req)
249 | 	if it == nil {
250 | 		return nil, fmt.Errorf("failed to create search entries iterator for project %q", t.ProjectID)
251 | 	}
252 | 
253 | 	var results []Response
254 | 	for {
255 | 		entry, err := it.Next()
256 | 		if err == iterator.Done {
257 | 			break
258 | 		}
259 | 		if err != nil {
260 | 			break
261 | 		}
262 | 		entrySource := entry.DataplexEntry.GetEntrySource()
263 | 		resp := Response{
264 | 			DisplayName:   entrySource.GetDisplayName(),
265 | 			Description:   entrySource.GetDescription(),
266 | 			Type:          ExtractType(entry.DataplexEntry.GetEntryType()),
267 | 			Resource:      entrySource.GetResource(),
268 | 			DataplexEntry: entry.DataplexEntry.GetName(),
269 | 		}
270 | 		results = append(results, resp)
271 | 	}
272 | 	return results, nil
273 | }
274 | 
275 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
276 | 	// Parse parameters from the provided data
277 | 	return tools.ParseParams(t.Parameters, data, claims)
278 | }
279 | 
280 | func (t Tool) Manifest() tools.Manifest {
281 | 	// Returns the tool manifest
282 | 	return t.manifest
283 | }
284 | 
285 | func (t Tool) McpManifest() tools.McpManifest {
286 | 	// Returns the tool MCP manifest
287 | 	return t.mcpManifest
288 | }
289 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/http/http.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "http"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   A "http" tool sends out an HTTP request to an HTTP endpoint.
  7 | aliases:
  8 | - /resources/tools/http
  9 | ---
 10 | 
 11 | 
 12 | ## About
 13 | 
 14 | The `http` tool allows you to make HTTP requests to APIs to retrieve data.
 15 | An HTTP request is the method by which a client communicates with a server to
 16 | retrieve or manipulate resources.
 17 | Toolbox allows you to configure the request URL, method, headers, query
 18 | parameters, and the request body for an HTTP Tool.
 19 | 
 20 | ### URL
 21 | 
 22 | An HTTP request URL identifies the target the client wants to access.
 23 | Toolbox composes the request URL from 3 places:
 24 | 
 25 | 1. The HTTP Source's `baseUrl`.
 26 | 2. The HTTP Tool's `path` field.
 27 | 3. The HTTP Tool's `pathParams` for dynamic path composed during Tool
 28 |    invocation.
 29 | 
 30 | For example, the following config allows you to reach different paths of the
 31 | same server using multiple Tools:
 32 | 
 33 | ```yaml
 34 | sources:
 35 |     my-http-source:
 36 |         kind: http
 37 |         baseUrl: https://api.example.com
 38 | 
 39 | tools:
 40 |     my-post-tool:
 41 |         kind: http
 42 |         source: my-http-source
 43 |         method: POST
 44 |         path: /update
 45 |         description: Tool to update information to the example API
 46 | 
 47 |     my-get-tool:
 48 |         kind: http
 49 |         source: my-http-source
 50 |         method: GET
 51 |         path: /search
 52 |         description: Tool to search information from the example API
 53 | 
 54 |     my-dynamic-path-tool:
 55 |         kind: http
 56 |         source: my-http-source
 57 |         method: GET
 58 |         path: /{{.myPathParam}}/search
 59 |         description: Tool to reach endpoint based on the input to `myPathParam`
 60 |         pathParams:
 61 |             - name: myPathParam
 62 |               type: string
 63 |               description: The dynamic path parameter
 64 | 
 65 | ```
 66 | 
 67 | ### Headers
 68 | 
 69 | An HTTP request header is a key-value pair sent by a client to a server,
 70 | providing additional information about the request, such as the client's
 71 | preferences, the request body content type, and other metadata.
 72 | Headers specified by the HTTP Tool are combined with its HTTP Source headers for
 73 | the resulting HTTP request, and override the Source headers in case of conflict.
 74 | The HTTP Tool allows you to specify headers in two different ways:
 75 | 
 76 | - Static headers can be specified using the `headers` field, and will be the
 77 |   same for every invocation:
 78 | 
 79 | ```yaml
 80 | my-http-tool:
 81 |     kind: http
 82 |     source: my-http-source
 83 |     method: GET
 84 |     path: /search
 85 |     description: Tool to search data from API
 86 |     headers:
 87 |       Authorization: API_KEY
 88 |       Content-Type: application/json
 89 | ```
 90 | 
 91 | - Dynamic headers can be specified as parameters in the `headerParams` field.
 92 |   The `name` of the `headerParams` will be used as the header key, and the value
 93 |   is determined by the LLM input upon Tool invocation:
 94 | 
 95 | ```yaml
 96 | my-http-tool:
 97 |     kind: http
 98 |     source: my-http-source
 99 |     method: GET
100 |     path: /search
101 |     description: some description
102 |     headerParams:
103 |       - name: Content-Type # Example LLM input: "application/json"
104 |         description: request content type
105 |         type: string
106 | ```
107 | 
108 | ### Query parameters
109 | 
110 | Query parameters are key-value pairs appended to a URL after a question mark (?)
111 | to provide additional information to the server for processing the request, like
112 | filtering or sorting data.
113 | 
114 | - Static request query parameters should be specified in the `path` as part of
115 |   the URL itself:
116 | 
117 | ```yaml
118 | my-http-tool:
119 |     kind: http
120 |     source: my-http-source
121 |     method: GET
122 |     path: /search?language=en&id=1
123 |     description: Tool to search for item with ID 1 in English
124 | ```
125 | 
126 | - Dynamic request query parameters should be specified as parameters in the
127 |   `queryParams` section:
128 | 
129 | ```yaml
130 | my-http-tool:
131 |     kind: http
132 |     source: my-http-source
133 |     method: GET
134 |     path: /search
135 |     description: Tool to search for item with ID
136 |     queryParams:
137 |       - name: id
138 |         description: item ID
139 |         type: integer
140 | ```
141 | 
142 | ### Request body
143 | 
144 | The request body payload is a string that supports parameter replacement
145 | following [Go template][go-template-doc]'s annotations.
146 | The parameter names in the `requestBody` should be preceded by "." and enclosed
147 | by double curly brackets "{{}}". The values will be populated into the request
148 | body payload upon Tool invocation.
149 | 
150 | Example:
151 | 
152 | ```yaml
153 | my-http-tool:
154 |     kind: http
155 |     source: my-http-source
156 |     method: GET
157 |     path: /search
158 |     description: Tool to search for person with name and age
159 |     requestBody: |
160 |       {
161 |         "age": {{.age}},
162 |         "name": "{{.name}}"
163 |       }
164 |     bodyParams:
165 |       - name: age
166 |         description: age number
167 |         type: integer
168 |       - name: name
169 |         description: name string
170 |         type: string
171 | ```
172 | 
173 | #### Formatting Parameters
174 | 
175 | Some complex parameters (such as arrays) may require additional formatting to
176 | match the expected output. For convenience, you can specify one of the following
177 | pre-defined functions before the parameter name to format it:
178 | 
179 | ##### JSON
180 | 
181 | The `json` keyword converts a parameter into a JSON format.
182 | 
183 | {{< notice note >}}
184 | Using JSON may add quotes to the variable name for certain types (such as
185 | strings).
186 | {{< /notice >}}
187 | 
188 | Example:
189 | 
190 | ```yaml
191 | requestBody: |
192 |   {
193 |     "age": {{json .age}},
194 |     "name": {{json .name}},
195 |     "nickname": "{{json .nickname}}",
196 |     "nameArray": {{json .nameArray}}
197 |   }
198 | ```
199 | 
200 | will send the following output:
201 | 
202 | ```yaml
203 | {
204 |   "age": 18,
205 |   "name": "Katherine",
206 |   "nickname": ""Kat"", # Duplicate quotes
207 |   "nameArray": ["A", "B", "C"]
208 | }
209 | ```
210 | 
211 | ## Example
212 | 
213 | ```yaml
214 | my-http-tool:
215 |     kind: http
216 |     source: my-http-source
217 |     method: GET
218 |     path: /search
219 |     description: some description
220 |     authRequired:
221 |       - my-google-auth-service
222 |       - other-auth-service
223 |     queryParams:
224 |       - name: country
225 |         description: some description
226 |         type: string
227 |     requestBody: |
228 |       {
229 |         "age": {{.age}},
230 |         "city": "{{.city}}"
231 |       }
232 |     bodyParams:
233 |       - name: age
234 |         description: age number
235 |         type: integer
236 |       - name: city
237 |         description: city string
238 |         type: string
239 |     headers:
240 |       Authorization: API_KEY
241 |       Content-Type: application/json
242 |     headerParams:
243 |       - name: Language
244 |         description: language string
245 |         type: string
246 | ```
247 | 
248 | ## Reference
249 | 
250 | | **field**    |                  **type**                  | **required** | **description**                                                                                                                                                                                                            |
251 | |--------------|:------------------------------------------:|:------------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
252 | | kind         |                   string                   |     true     | Must be "http".                                                                                                                                                                                                            |
253 | | source       |                   string                   |     true     | Name of the source the HTTP request should be sent to.                                                                                                                                                                     |
254 | | description  |                   string                   |     true     | Description of the tool that is passed to the LLM.                                                                                                                                                                         |
255 | | path         |                   string                   |     true     | The path of the HTTP request. You can include static query parameters in the path string.                                                                                                                                  |
256 | | method       |                   string                   |     true     | The HTTP method to use (e.g., GET, POST, PUT, DELETE).                                                                                                                                                                     |
257 | | headers      |             map[string]string              |    false     | A map of headers to include in the HTTP request (overrides source headers).                                                                                                                                                |
258 | | requestBody  |                   string                   |    false     | The request body payload. Use [go template][go-template-doc] with the parameter name as the placeholder (e.g., `{{.id}}` will be replaced with the value of the parameter that has name `id` in the `bodyParams` section). |
259 | | queryParams  | [parameters](../#specifying-parameters) |    false     | List of [parameters](../#specifying-parameters) that will be inserted into the query string.                                                                                                                            |
260 | | bodyParams   | [parameters](../#specifying-parameters) |    false     | List of [parameters](../#specifying-parameters) that will be inserted into the request body payload.                                                                                                                    |
261 | | headerParams | [parameters](../#specifying-parameters) |    false     | List of [parameters](../#specifying-parameters) that will be inserted as the request headers.                                                                                                                           |
262 | 
263 | [go-template-doc]: <https://pkg.go.dev/text/template#pkg-overview>
264 | 
```

--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/postgres_mcp.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "PostgreSQL using MCP"
  3 | type: docs
  4 | weight: 2
  5 | description: >
  6 |   Connect your IDE to PostgreSQL using Toolbox.
  7 | ---
  8 | 
  9 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
 10 | an open protocol for connecting Large Language Models (LLMs) to data sources
 11 | like Postgres. This guide covers how to use [MCP Toolbox for Databases][toolbox]
 12 | to expose your developer assistant tools to a Postgres instance:
 13 | 
 14 | * [Cursor][cursor]
 15 | * [Windsurf][windsurf] (Codium)
 16 | * [Visual Studio Code][vscode] (Copilot)
 17 | * [Cline][cline]  (VS Code extension)
 18 | * [Claude desktop][claudedesktop]
 19 | * [Claude code][claudecode]
 20 | * [Gemini CLI][geminicli]
 21 | * [Gemini Code Assist][geminicodeassist]
 22 | 
 23 | [toolbox]: https://github.com/googleapis/genai-toolbox
 24 | [cursor]: #configure-your-mcp-client
 25 | [windsurf]: #configure-your-mcp-client
 26 | [vscode]: #configure-your-mcp-client
 27 | [cline]: #configure-your-mcp-client
 28 | [claudedesktop]: #configure-your-mcp-client
 29 | [claudecode]: #configure-your-mcp-client
 30 | [geminicli]: #configure-your-mcp-client
 31 | [geminicodeassist]: #configure-your-mcp-client
 32 | 
 33 | {{< notice tip >}}
 34 | This guide can be used with [AlloyDB
 35 | Omni](https://cloud.google.com/alloydb/omni/current/docs/overview).
 36 | {{< /notice >}}
 37 | 
 38 | ## Set up the database
 39 | 
 40 | 1. Create or select a PostgreSQL instance.
 41 | 
 42 |     * [Install PostgreSQL locally](https://www.postgresql.org/download/)
 43 |     * [Install AlloyDB Omni](https://cloud.google.com/alloydb/omni/current/docs/quickstart)
 44 | 
 45 | 1. Create or reuse [a database
 46 |    user](https://cloud.google.com/alloydb/omni/current/docs/database-users/manage-users)
 47 |    and have the username and password ready.
 48 | 
 49 | ## Install MCP Toolbox
 50 | 
 51 | 1. Download the latest version of Toolbox as a binary. Select the [correct
 52 |    binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
 53 |    to your OS and CPU architecture. You are required to use Toolbox version
 54 |    V0.6.0+:
 55 | 
 56 |    <!-- {x-release-please-start-version} -->
 57 |    {{< tabpane persist=header >}}
 58 | {{< tab header="linux/amd64" lang="bash" >}}
 59 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
 60 | {{< /tab >}}
 61 | 
 62 | {{< tab header="darwin/arm64" lang="bash" >}}
 63 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
 64 | {{< /tab >}}
 65 | 
 66 | {{< tab header="darwin/amd64" lang="bash" >}}
 67 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
 68 | {{< /tab >}}
 69 | 
 70 | {{< tab header="windows/amd64" lang="bash" >}}
 71 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
 72 | {{< /tab >}}
 73 | {{< /tabpane >}}
 74 |     <!-- {x-release-please-end} -->
 75 | 
 76 | 1. Make the binary executable:
 77 | 
 78 |     ```bash
 79 |     chmod +x toolbox
 80 |     ```
 81 | 
 82 | 1. Verify the installation:
 83 | 
 84 |     ```bash
 85 |     ./toolbox --version
 86 |     ```
 87 | 
 88 | ## Configure your MCP Client
 89 | 
 90 | {{< tabpane text=true >}}
 91 | {{% tab header="Claude code" lang="en" %}}
 92 | 
 93 | 1. Install [Claude
 94 |    Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
 95 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
 96 | 1. Add the following configuration, replace the environment variables with your
 97 |    values, and save:
 98 | 
 99 |     ```json
100 |     {
101 |       "mcpServers": {
102 |         "postgres": {
103 |           "command": "./PATH/TO/toolbox",
104 |           "args": ["--prebuilt","postgres","--stdio"],
105 |           "env": {
106 |             "POSTGRES_HOST": "",
107 |             "POSTGRES_PORT": "",
108 |             "POSTGRES_DATABASE": "",
109 |             "POSTGRES_USER": "",
110 |             "POSTGRES_PASSWORD": ""
111 |           }
112 |         }
113 |       }
114 |     }
115 |     ```
116 | 
117 | 1. Restart Claude code to apply the new configuration.
118 | {{% /tab %}}
119 | 
120 | {{% tab header="Claude desktop" lang="en" %}}
121 | 
122 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
123 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
124 | 1. Add the following configuration, replace the environment variables with your
125 |    values, and save:
126 | 
127 |     ```json
128 |     {
129 |       "mcpServers": {
130 |         "postgres": {
131 |           "command": "./PATH/TO/toolbox",
132 |           "args": ["--prebuilt","postgres","--stdio"],
133 |           "env": {
134 |             "POSTGRES_HOST": "",
135 |             "POSTGRES_PORT": "",
136 |             "POSTGRES_DATABASE": "",
137 |             "POSTGRES_USER": "",
138 |             "POSTGRES_PASSWORD": ""
139 |           }
140 |         }
141 |       }
142 |     }
143 |     ```
144 | 
145 | 1. Restart Claude desktop.
146 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
147 |    new MCP server available.
148 | {{% /tab %}}
149 | 
150 | {{% tab header="Cline" lang="en" %}}
151 | 
152 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap
153 |    the **MCP Servers** icon.
154 | 1. Tap Configure MCP Servers to open the configuration file.
155 | 1. Add the following configuration, replace the environment variables with your
156 |    values, and save:
157 | 
158 |     ```json
159 |     {
160 |       "mcpServers": {
161 |         "postgres": {
162 |           "command": "./PATH/TO/toolbox",
163 |           "args": ["--prebuilt","postgres","--stdio"],
164 |           "env": {
165 |             "POSTGRES_HOST": "",
166 |             "POSTGRES_PORT": "",
167 |             "POSTGRES_DATABASE": "",
168 |             "POSTGRES_USER": "",
169 |             "POSTGRES_PASSWORD": ""
170 |           }
171 |         }
172 |       }
173 |     }
174 |     ```
175 | 
176 | 1. You should see a green active status after the server is successfully
177 |    connected.
178 | {{% /tab %}}
179 | 
180 | {{% tab header="Cursor" lang="en" %}}
181 | 
182 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
183 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
184 | 1. Add the following configuration, replace the environment variables with your
185 |    values, and save:
186 | 
187 |     ```json
188 |     {
189 |       "mcpServers": {
190 |         "postgres": {
191 |           "command": "./PATH/TO/toolbox",
192 |           "args": ["--prebuilt","postgres","--stdio"],
193 |           "env": {
194 |             "POSTGRES_HOST": "",
195 |             "POSTGRES_PORT": "",
196 |             "POSTGRES_DATABASE": "",
197 |             "POSTGRES_USER": "",
198 |             "POSTGRES_PASSWORD": ""
199 |           }
200 |         }
201 |       }
202 |     }
203 |     ```
204 | 
205 | 1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
206 |    Settings > MCP**. You should see a green active status after the server is
207 |    successfully connected.
208 | {{% /tab %}}
209 | 
210 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
211 | 
212 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
213 |    create a `.vscode` directory in your project root if it doesn't exist.
214 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
215 | 1. Add the following configuration, replace the environment variables with your
216 |    values, and save:
217 | 
218 |     ```json
219 |     {
220 |       "servers": {
221 |         "postgres": {
222 |           "command": "./PATH/TO/toolbox",
223 |           "args": ["--prebuilt","postgres","--stdio"],
224 |           "env": {
225 |             "POSTGRES_HOST": "",
226 |             "POSTGRES_PORT": "",
227 |             "POSTGRES_DATABASE": "",
228 |             "POSTGRES_USER": "",
229 |             "POSTGRES_PASSWORD": ""
230 |           }
231 |         }
232 |       }
233 |     }
234 |     ```
235 | 
236 | {{% /tab %}}
237 | 
238 | {{% tab header="Windsurf" lang="en" %}}
239 | 
240 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
241 |    Cascade assistant.
242 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
243 | 1. Add the following configuration, replace the environment variables with your
244 |    values, and save:
245 | 
246 |     ```json
247 |     {
248 |       "mcpServers": {
249 |         "postgres": {
250 |           "command": "./PATH/TO/toolbox",
251 |           "args": ["--prebuilt","postgres","--stdio"],
252 |           "env": {
253 |             "POSTGRES_HOST": "",
254 |             "POSTGRES_PORT": "",
255 |             "POSTGRES_DATABASE": "",
256 |             "POSTGRES_USER": "",
257 |             "POSTGRES_PASSWORD": ""
258 |           }
259 |         }
260 |       }
261 |     }
262 | 
263 |     ```
264 | 
265 | {{% /tab %}}
266 | 
267 | {{% tab header="Gemini CLI" lang="en" %}}
268 | 
269 | 1.  Install the [Gemini CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
270 | 1.  In your working directory, create a folder named `.gemini`. Within it, create a `settings.json` file.
271 | 1.  Add the following configuration, replace the environment variables with your values, and then save:
272 | 
273 |     ```json
274 |     {
275 |       "mcpServers": {
276 |         "postgres": {
277 |           "command": "./PATH/TO/toolbox",
278 |           "args": ["--prebuilt","postgres","--stdio"],
279 |           "env": {
280 |             "POSTGRES_HOST": "",
281 |             "POSTGRES_PORT": "",
282 |             "POSTGRES_DATABASE": "",
283 |             "POSTGRES_USER": "",
284 |             "POSTGRES_PASSWORD": ""
285 |           }
286 |         }
287 |       }
288 |     }
289 |     ```
290 | {{% /tab %}}
291 | 
292 | {{% tab header="Gemini Code Assist" lang="en" %}}
293 | 
294 | 1.  Install the [Gemini Code Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist) extension in Visual Studio Code.
295 | 1.  Enable Agent Mode in Gemini Code Assist chat.
296 | 1.  In your working directory, create a folder named `.gemini`. Within it, create a `settings.json` file.
297 | 1.  Add the following configuration, replace the environment variables with your values, and then save:
298 | 
299 |     ```json
300 |     {
301 |       "mcpServers": {
302 |         "postgres": {
303 |           "command": "./PATH/TO/toolbox",
304 |           "args": ["--prebuilt","postgres","--stdio"],
305 |           "env": {
306 |             "POSTGRES_HOST": "",
307 |             "POSTGRES_PORT": "",
308 |             "POSTGRES_DATABASE": "",
309 |             "POSTGRES_USER": "",
310 |             "POSTGRES_PASSWORD": ""
311 |           }
312 |         }
313 |       }
314 |     }
315 |     ```
316 | {{% /tab %}}
317 | {{< /tabpane >}}
318 | 
319 | ## Use Tools
320 | 
321 | Your AI tool is now connected to Postgres using MCP. Try asking your AI
322 | assistant to list tables, create a table, or define and execute other SQL
323 | statements.
324 | 
325 | The following tools are available to the LLM:
326 | 
327 | 1. **list_tables**: lists tables and descriptions
328 | 1. **execute_sql**: execute any SQL statement
329 | 
330 | {{< notice note >}}
331 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
332 | will adapt to the tools available, so this shouldn't affect most users.
333 | {{< /notice >}}
334 | 
```

--------------------------------------------------------------------------------
/tests/sqlite/sqlite_integration_test.go:
--------------------------------------------------------------------------------

```go
  1 | // Copyright 2025 Google LLC
  2 | //
  3 | // Licensed under the Apache License, Version 2.0 (the "License");
  4 | // you may not use this file except in compliance with the License.
  5 | // You may obtain a copy of the License at
  6 | //
  7 | //     http://www.apache.org/licenses/LICENSE-2.0
  8 | //
  9 | // Unless required by applicable law or agreed to in writing, software
 10 | // distributed under the License is distributed on an "AS IS" BASIS,
 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12 | // See the License for the specific language governing permissions and
 13 | // limitations under the License.
 14 | 
 15 | package sqlite
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"database/sql"
 20 | 	"fmt"
 21 | 	"io"
 22 | 	"net/http"
 23 | 	"os"
 24 | 	"regexp"
 25 | 	"strings"
 26 | 	"testing"
 27 | 	"time"
 28 | 
 29 | 	"github.com/google/uuid"
 30 | 	"github.com/googleapis/genai-toolbox/internal/testutils"
 31 | 	"github.com/googleapis/genai-toolbox/tests"
 32 | )
 33 | 
 34 | var (
 35 | 	SQLiteSourceKind = "sqlite"
 36 | 	SQLiteToolKind   = "sqlite-sql"
 37 | 	SQLiteDatabase   = os.Getenv("SQLITE_DATABASE")
 38 | )
 39 | 
 40 | func getSQLiteVars(t *testing.T) map[string]any {
 41 | 	return map[string]any{
 42 | 		"kind":     SQLiteSourceKind,
 43 | 		"database": SQLiteDatabase,
 44 | 	}
 45 | }
 46 | 
 47 | func initSQLiteDb(t *testing.T, sqliteDb string) (*sql.DB, func(t *testing.T), string, error) {
 48 | 	if sqliteDb == "" {
 49 | 		// Create a temporary database file
 50 | 		tmpFile, err := os.CreateTemp("", "test-*.db")
 51 | 		if err != nil {
 52 | 			return nil, nil, "", fmt.Errorf("failed to create temp file: %v", err)
 53 | 		}
 54 | 		sqliteDb = tmpFile.Name()
 55 | 	}
 56 | 
 57 | 	// Open database connection
 58 | 	db, err := sql.Open("sqlite", sqliteDb)
 59 | 	if err != nil {
 60 | 		return nil, nil, "", fmt.Errorf("failed to open database: %v", err)
 61 | 	}
 62 | 
 63 | 	cleanup := func(t *testing.T) {
 64 | 		if err := os.Remove(sqliteDb); err != nil {
 65 | 			t.Errorf("Failed to remove test database: %s", err)
 66 | 		}
 67 | 	}
 68 | 
 69 | 	return db, cleanup, sqliteDb, nil
 70 | }
 71 | 
 72 | // setupSQLiteTestDB creates a temporary SQLite database for testing
 73 | func setupSQLiteTestDB(t *testing.T, ctx context.Context, db *sql.DB, createStatement string, insertStatement string, tableName string, params []any) {
 74 | 	// Create test table
 75 | 	_, err := db.ExecContext(ctx, createStatement)
 76 | 	if err != nil {
 77 | 		t.Fatalf("unable to connect to create test table %s: %s", tableName, err)
 78 | 	}
 79 | 
 80 | 	_, err = db.ExecContext(ctx, insertStatement, params...)
 81 | 	if err != nil {
 82 | 		t.Fatalf("unable to insert test data: %s", err)
 83 | 	}
 84 | }
 85 | 
 86 | func getSQLiteParamToolInfo(tableName string) (string, string, string, string, string, string, []any) {
 87 | 	createStatement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT);", tableName)
 88 | 	insertStatement := fmt.Sprintf("INSERT INTO %s (name) VALUES (?), (?), (?), (?);", tableName)
 89 | 	toolStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ? OR name = ?;", tableName)
 90 | 	idToolStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ?;", tableName)
 91 | 	nameToolStatement := fmt.Sprintf("SELECT * FROM %s WHERE name = ?;", tableName)
 92 | 	arrayToolStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ANY({{.idArray}}) AND name = ANY({{.nameArray}});", tableName)
 93 | 	params := []any{"Alice", "Jane", "Sid", nil}
 94 | 	return createStatement, insertStatement, toolStatement, idToolStatement, nameToolStatement, arrayToolStatement, params
 95 | }
 96 | 
 97 | func getSQLiteAuthToolInfo(tableName string) (string, string, string, []any) {
 98 | 	createStatement := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT)", tableName)
 99 | 	insertStatement := fmt.Sprintf("INSERT INTO %s (name, email) VALUES (?, ?), (?,?) RETURNING id, name, email;", tableName)
100 | 	toolStatement := fmt.Sprintf("SELECT name FROM %s WHERE email = ?;", tableName)
101 | 	params := []any{"Alice", tests.ServiceAccountEmail, "Jane", "[email protected]"}
102 | 	return createStatement, insertStatement, toolStatement, params
103 | }
104 | 
105 | func getSQLiteTmplToolStatement() (string, string) {
106 | 	tmplSelectCombined := "SELECT * FROM {{.tableName}} WHERE id = ?"
107 | 	tmplSelectFilterCombined := "SELECT * FROM {{.tableName}} WHERE {{.columnFilter}} = ?"
108 | 	return tmplSelectCombined, tmplSelectFilterCombined
109 | }
110 | 
111 | func TestSQLiteToolEndpoint(t *testing.T) {
112 | 	db, teardownDb, sqliteDb, err := initSQLiteDb(t, SQLiteDatabase)
113 | 	if err != nil {
114 | 		t.Fatal(err)
115 | 	}
116 | 	defer teardownDb(t)
117 | 	defer db.Close()
118 | 
119 | 	sourceConfig := getSQLiteVars(t)
120 | 	sourceConfig["database"] = sqliteDb
121 | 	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
122 | 	defer cancel()
123 | 
124 | 	var args []string
125 | 
126 | 	// create table name with UUID
127 | 	tableNameParam := "param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
128 | 	tableNameAuth := "auth_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
129 | 	tableNameTemplateParam := "template_param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
130 | 
131 | 	// set up data for param tool
132 | 	createParamTableStmt, insertParamTableStmt, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, paramTestParams := getSQLiteParamToolInfo(tableNameParam)
133 | 	setupSQLiteTestDB(t, ctx, db, createParamTableStmt, insertParamTableStmt, tableNameParam, paramTestParams)
134 | 
135 | 	// set up data for auth tool
136 | 	createAuthTableStmt, insertAuthTableStmt, authToolStmt, authTestParams := getSQLiteAuthToolInfo(tableNameAuth)
137 | 	setupSQLiteTestDB(t, ctx, db, createAuthTableStmt, insertAuthTableStmt, tableNameAuth, authTestParams)
138 | 
139 | 	// Write config into a file and pass it to command
140 | 	toolsFile := tests.GetToolsConfig(sourceConfig, SQLiteToolKind, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, authToolStmt)
141 | 	tmplSelectCombined, tmplSelectFilterCombined := getSQLiteTmplToolStatement()
142 | 	toolsFile = tests.AddTemplateParamConfig(t, toolsFile, SQLiteToolKind, tmplSelectCombined, tmplSelectFilterCombined, "")
143 | 
144 | 	cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
145 | 	if err != nil {
146 | 		t.Fatalf("command initialization returned an error: %s", err)
147 | 	}
148 | 	defer cleanup()
149 | 
150 | 	waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
151 | 	defer cancel()
152 | 	out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out)
153 | 	if err != nil {
154 | 		t.Logf("toolbox command logs: \n%s", out)
155 | 		t.Fatalf("toolbox didn't start successfully: %s", err)
156 | 	}
157 | 
158 | 	// Get configs for tests
159 | 	select1Want := "[{\"1\":1}]"
160 | 	mcpMyFailToolWant := `{"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to execute query: SQL logic error: near \"SELEC\": syntax error (1)"}],"isError":true}}`
161 | 	mcpSelect1Want := `{"jsonrpc":"2.0","id":"invoke my-auth-required-tool","result":{"content":[{"type":"text","text":"{\"1\":1}"}]}}`
162 | 
163 | 	// Run tests
164 | 	tests.RunToolGetTest(t)
165 | 	tests.RunToolInvokeTest(t, select1Want, tests.DisableArrayTest())
166 | 	tests.RunMCPToolCallMethod(t, mcpMyFailToolWant, mcpSelect1Want)
167 | 	tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam)
168 | }
169 | 
170 | func TestSQLiteExecuteSqlTool(t *testing.T) {
171 | 	db, teardownDb, sqliteDb, err := initSQLiteDb(t, SQLiteDatabase)
172 | 	if err != nil {
173 | 		t.Fatal(err)
174 | 	}
175 | 	defer teardownDb(t)
176 | 	defer db.Close()
177 | 
178 | 	sourceConfig := getSQLiteVars(t)
179 | 	sourceConfig["database"] = sqliteDb
180 | 	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
181 | 	defer cancel()
182 | 
183 | 	// Create a table and insert data
184 | 	tableName := "exec_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
185 | 	createStmt := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY, name TEXT);", tableName)
186 | 	insertStmt := fmt.Sprintf("INSERT INTO %s (name) VALUES (?);", tableName)
187 | 	params := []any{"Bob"}
188 | 	setupSQLiteTestDB(t, ctx, db, createStmt, insertStmt, tableName, params)
189 | 
190 | 	// Add sqlite-execute-sql tool config
191 | 	toolConfig := map[string]any{
192 | 		"tools": map[string]any{
193 | 			"my-exec-sql-tool": map[string]any{
194 | 				"kind":        "sqlite-execute-sql",
195 | 				"source":      "my-instance",
196 | 				"description": "Tool to execute SQL statements",
197 | 			},
198 | 		},
199 | 		"sources": map[string]any{
200 | 			"my-instance": sourceConfig,
201 | 		},
202 | 	}
203 | 
204 | 	cmd, cleanup, err := tests.StartCmd(ctx, toolConfig)
205 | 	if err != nil {
206 | 		t.Fatalf("command initialization returned an error: %s", err)
207 | 	}
208 | 	defer cleanup()
209 | 
210 | 	waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
211 | 	defer cancel()
212 | 	out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out)
213 | 	if err != nil {
214 | 		t.Logf("toolbox command logs: \n%s", out)
215 | 		t.Fatalf("toolbox didn't start successfully: %s", err)
216 | 	}
217 | 
218 | 	// Table-driven test cases
219 | 	testCases := []struct {
220 | 		name       string
221 | 		sql        string
222 | 		wantStatus int
223 | 		wantBody   string
224 | 	}{
225 | 		{
226 | 			name:       "select existing row",
227 | 			sql:        fmt.Sprintf("SELECT name FROM %s WHERE id = 1", tableName),
228 | 			wantStatus: 200,
229 | 			wantBody:   "Bob",
230 | 		},
231 | 		{
232 | 			name:       "select no rows",
233 | 			sql:        fmt.Sprintf("SELECT name FROM %s WHERE id = 999", tableName),
234 | 			wantStatus: 200,
235 | 			wantBody:   "null",
236 | 		},
237 | 		{
238 | 			name:       "invalid SQL",
239 | 			sql:        "SELEC name FROM not_a_table",
240 | 			wantStatus: 400,
241 | 			wantBody:   "SQL logic error",
242 | 		},
243 | 	}
244 | 
245 | 	for _, tc := range testCases {
246 | 		t.Run(tc.name, func(t *testing.T) {
247 | 			api := "http://127.0.0.1:5000/api/tool/my-exec-sql-tool/invoke"
248 | 			reqBody := strings.NewReader(fmt.Sprintf(`{"sql":"%s"}`, tc.sql))
249 | 			req, err := http.NewRequest("POST", api, reqBody)
250 | 			if err != nil {
251 | 				t.Fatalf("unable to create request: %s", err)
252 | 			}
253 | 			req.Header.Set("Content-Type", "application/json")
254 | 			resp, err := http.DefaultClient.Do(req)
255 | 			if err != nil {
256 | 				t.Fatalf("unable to send request: %s", err)
257 | 			}
258 | 			defer resp.Body.Close()
259 | 			bodyBytes, err := io.ReadAll(resp.Body)
260 | 			if err != nil {
261 | 				t.Fatalf("unable to read response: %s", err)
262 | 			}
263 | 			if resp.StatusCode != tc.wantStatus {
264 | 				t.Fatalf("unexpected status: %d, body: %s", resp.StatusCode, string(bodyBytes))
265 | 			}
266 | 			if tc.wantBody != "" && !strings.Contains(string(bodyBytes), tc.wantBody) {
267 | 				t.Fatalf("expected body to contain %q, got: %s", tc.wantBody, string(bodyBytes))
268 | 			}
269 | 		})
270 | 	}
271 | }
272 | 
```
Page 26/48FirstPrevNextLast