#
tokens: 48809/50000 21/786 files (page 13/45)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 13 of 45. 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
│       │   │   ├── 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-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-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
│       │       ├── 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
│       │       ├── 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
│   │       ├── 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
│   │   ├── 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
│   │   │   ├── 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
│   │   │   ├── 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
│   │   ├── 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
│   │   ├── 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
    ├── 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

--------------------------------------------------------------------------------
/internal/tools/firestore/firestoregetrules/firestoregetrules.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 firestoregetrules
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	firestoreds "github.com/googleapis/genai-toolbox/internal/sources/firestore"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | 	"google.golang.org/api/firebaserules/v1"
 26 | )
 27 | 
 28 | const kind string = "firestore-get-rules"
 29 | 
 30 | func init() {
 31 | 	if !tools.Register(kind, newConfig) {
 32 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 33 | 	}
 34 | }
 35 | 
 36 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 37 | 	actual := Config{Name: name}
 38 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 39 | 		return nil, err
 40 | 	}
 41 | 	return actual, nil
 42 | }
 43 | 
 44 | type compatibleSource interface {
 45 | 	FirebaseRulesClient() *firebaserules.Service
 46 | 	GetProjectId() string
 47 | 	GetDatabaseId() string
 48 | }
 49 | 
 50 | // validate compatible sources are still compatible
 51 | var _ compatibleSource = &firestoreds.Source{}
 52 | 
 53 | var compatibleSources = [...]string{firestoreds.SourceKind}
 54 | 
 55 | type Config struct {
 56 | 	Name         string   `yaml:"name" validate:"required"`
 57 | 	Kind         string   `yaml:"kind" validate:"required"`
 58 | 	Source       string   `yaml:"source" validate:"required"`
 59 | 	Description  string   `yaml:"description" validate:"required"`
 60 | 	AuthRequired []string `yaml:"authRequired"`
 61 | }
 62 | 
 63 | // validate interface
 64 | var _ tools.ToolConfig = Config{}
 65 | 
 66 | func (cfg Config) ToolConfigKind() string {
 67 | 	return kind
 68 | }
 69 | 
 70 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 71 | 	// verify source exists
 72 | 	rawS, ok := srcs[cfg.Source]
 73 | 	if !ok {
 74 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 75 | 	}
 76 | 
 77 | 	// verify the source is compatible
 78 | 	s, ok := rawS.(compatibleSource)
 79 | 	if !ok {
 80 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
 81 | 	}
 82 | 
 83 | 	// No parameters needed for this tool
 84 | 	parameters := tools.Parameters{}
 85 | 
 86 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
 87 | 
 88 | 	// finish tool setup
 89 | 	t := Tool{
 90 | 		Name:         cfg.Name,
 91 | 		Kind:         kind,
 92 | 		Parameters:   parameters,
 93 | 		AuthRequired: cfg.AuthRequired,
 94 | 		RulesClient:  s.FirebaseRulesClient(),
 95 | 		ProjectId:    s.GetProjectId(),
 96 | 		DatabaseId:   s.GetDatabaseId(),
 97 | 		manifest:     tools.Manifest{Description: cfg.Description, Parameters: parameters.Manifest(), AuthRequired: cfg.AuthRequired},
 98 | 		mcpManifest:  mcpManifest,
 99 | 	}
100 | 	return t, nil
101 | }
102 | 
103 | // validate interface
104 | var _ tools.Tool = Tool{}
105 | 
106 | type Tool struct {
107 | 	Name         string           `yaml:"name"`
108 | 	Kind         string           `yaml:"kind"`
109 | 	AuthRequired []string         `yaml:"authRequired"`
110 | 	Parameters   tools.Parameters `yaml:"parameters"`
111 | 
112 | 	RulesClient *firebaserules.Service
113 | 	ProjectId   string
114 | 	DatabaseId  string
115 | 	manifest    tools.Manifest
116 | 	mcpManifest tools.McpManifest
117 | }
118 | 
119 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
120 | 	// Get the latest release for Firestore
121 | 	releaseName := fmt.Sprintf("projects/%s/releases/cloud.firestore/%s", t.ProjectId, t.DatabaseId)
122 | 	release, err := t.RulesClient.Projects.Releases.Get(releaseName).Context(ctx).Do()
123 | 	if err != nil {
124 | 		return nil, fmt.Errorf("failed to get latest Firestore release: %w", err)
125 | 	}
126 | 
127 | 	if release.RulesetName == "" {
128 | 		return nil, fmt.Errorf("no active Firestore rules were found in project '%s' and database '%s'", t.ProjectId, t.DatabaseId)
129 | 	}
130 | 
131 | 	// Get the ruleset content
132 | 	ruleset, err := t.RulesClient.Projects.Rulesets.Get(release.RulesetName).Context(ctx).Do()
133 | 	if err != nil {
134 | 		return nil, fmt.Errorf("failed to get ruleset content: %w", err)
135 | 	}
136 | 
137 | 	if ruleset.Source == nil || len(ruleset.Source.Files) == 0 {
138 | 		return nil, fmt.Errorf("no rules files found in ruleset")
139 | 	}
140 | 
141 | 	return ruleset, nil
142 | }
143 | 
144 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
145 | 	return tools.ParseParams(t.Parameters, data, claims)
146 | }
147 | 
148 | func (t Tool) Manifest() tools.Manifest {
149 | 	return t.manifest
150 | }
151 | 
152 | func (t Tool) McpManifest() tools.McpManifest {
153 | 	return t.mcpManifest
154 | }
155 | 
156 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
157 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
158 | }
159 | 
160 | func (t Tool) RequiresClientAuthorization() bool {
161 | 	return false
162 | }
163 | 
```

--------------------------------------------------------------------------------
/internal/tools/postgres/postgreslistinstalledextensions/postgreslistinstalledextensions.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 postgreslistinstalledextensions
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	"github.com/googleapis/genai-toolbox/internal/sources/alloydbpg"
 24 | 	"github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
 25 | 	"github.com/googleapis/genai-toolbox/internal/sources/postgres"
 26 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 27 | 	"github.com/jackc/pgx/v5/pgxpool"
 28 | )
 29 | 
 30 | const kind string = "postgres-list-installed-extensions"
 31 | 
 32 | const listAvailableExtensionsQuery = `
 33 | 	SELECT
 34 | 		e.extname AS name,
 35 | 		e.extversion AS version,
 36 | 		n.nspname AS schema,
 37 | 		pg_get_userbyid(e.extowner) AS owner,
 38 | 		c.description AS description
 39 | 	FROM
 40 | 		pg_catalog.pg_extension e
 41 | 	LEFT JOIN
 42 | 		pg_catalog.pg_namespace n
 43 | 	ON
 44 | 		n.oid = e.extnamespace
 45 | 	LEFT JOIN
 46 | 		pg_catalog.pg_description c
 47 | 	ON
 48 | 		c.objoid = e.oid
 49 | 		AND c.classoid = 'pg_catalog.pg_extension'::pg_catalog.regclass
 50 | 	ORDER BY 1;
 51 | `
 52 | 
 53 | func init() {
 54 | 	if !tools.Register(kind, newConfig) {
 55 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 56 | 	}
 57 | }
 58 | 
 59 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 60 | 	actual := Config{Name: name}
 61 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 62 | 		return nil, err
 63 | 	}
 64 | 	return actual, nil
 65 | }
 66 | 
 67 | type compatibleSource interface {
 68 | 	PostgresPool() *pgxpool.Pool
 69 | }
 70 | 
 71 | // validate compatible sources are still compatible
 72 | var _ compatibleSource = &alloydbpg.Source{}
 73 | var _ compatibleSource = &cloudsqlpg.Source{}
 74 | var _ compatibleSource = &postgres.Source{}
 75 | 
 76 | var compatibleSources = [...]string{alloydbpg.SourceKind, cloudsqlpg.SourceKind, postgres.SourceKind}
 77 | 
 78 | type Config struct {
 79 | 	Name         string   `yaml:"name" validate:"required"`
 80 | 	Kind         string   `yaml:"kind" validate:"required"`
 81 | 	Source       string   `yaml:"source" validate:"required"`
 82 | 	Description  string   `yaml:"description" validate:"required"`
 83 | 	AuthRequired []string `yaml:"authRequired"`
 84 | }
 85 | 
 86 | // validate interface
 87 | var _ tools.ToolConfig = Config{}
 88 | 
 89 | func (cfg Config) ToolConfigKind() string {
 90 | 	return kind
 91 | }
 92 | 
 93 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 94 | 	// verify source exists
 95 | 	rawS, ok := srcs[cfg.Source]
 96 | 	if !ok {
 97 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 98 | 	}
 99 | 
100 | 	// verify the source is compatible
101 | 	s, ok := rawS.(compatibleSource)
102 | 	if !ok {
103 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
104 | 	}
105 | 
106 | 	parameters := tools.Parameters{}
107 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
108 | 
109 | 	// finish tool setup
110 | 	t := Tool{
111 | 		Name:         cfg.Name,
112 | 		Kind:         cfg.Kind,
113 | 		AuthRequired: cfg.AuthRequired,
114 | 		Pool:         s.PostgresPool(),
115 | 		manifest: tools.Manifest{
116 | 			Description:  cfg.Description,
117 | 			Parameters:   parameters.Manifest(),
118 | 			AuthRequired: cfg.AuthRequired,
119 | 		},
120 | 		mcpManifest: mcpManifest,
121 | 	}
122 | 	return t, nil
123 | }
124 | 
125 | // validate interface
126 | var _ tools.Tool = Tool{}
127 | 
128 | type Tool struct {
129 | 	Name         string   `yaml:"name"`
130 | 	Kind         string   `yaml:"kind"`
131 | 	AuthRequired []string `yaml:"authRequired"`
132 | 	Pool         *pgxpool.Pool
133 | 	manifest     tools.Manifest
134 | 	mcpManifest  tools.McpManifest
135 | }
136 | 
137 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
138 | 	results, err := t.Pool.Query(ctx, listAvailableExtensionsQuery)
139 | 	if err != nil {
140 | 		return nil, fmt.Errorf("unable to execute query: %w", err)
141 | 	}
142 | 
143 | 	fields := results.FieldDescriptions()
144 | 
145 | 	var out []any
146 | 	for results.Next() {
147 | 		v, err := results.Values()
148 | 		if err != nil {
149 | 			return nil, fmt.Errorf("unable to parse row: %w", err)
150 | 		}
151 | 		vMap := make(map[string]any)
152 | 		for i, f := range fields {
153 | 			vMap[f.Name] = v[i]
154 | 		}
155 | 		out = append(out, vMap)
156 | 	}
157 | 
158 | 	return out, nil
159 | }
160 | 
161 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
162 | 	return tools.ParamValues{}, nil
163 | }
164 | 
165 | func (t Tool) Manifest() tools.Manifest {
166 | 	return t.manifest
167 | }
168 | 
169 | func (t Tool) McpManifest() tools.McpManifest {
170 | 	return t.mcpManifest
171 | }
172 | 
173 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
174 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
175 | }
176 | 
177 | func (t Tool) RequiresClientAuthorization() bool {
178 | 	return false
179 | }
180 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/couchbase/couchbase-sql.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "couchbase-sql"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   A "couchbase-sql" tool executes a pre-defined SQL statement against a Couchbase
  7 |   database.
  8 | aliases:
  9 | - /resources/tools/couchbase-sql
 10 | ---
 11 | 
 12 | ## About
 13 | 
 14 | A `couchbase-sql` tool executes a pre-defined SQL statement against a Couchbase
 15 | database. It's compatible with any of the following sources:
 16 | 
 17 | - [couchbase](../../sources/couchbase.md)
 18 | 
 19 | The specified SQL statement is executed as a parameterized statement, and specified
 20 | parameters will be used according to their name: e.g. `$id`.
 21 | 
 22 | ## Example
 23 | 
 24 | > **Note:** This tool uses parameterized queries to prevent SQL injections.
 25 | > Query parameters can be used as substitutes for arbitrary expressions.
 26 | > Parameters cannot be used as substitutes for identifiers, column names, table
 27 | > names, or other parts of the query.
 28 | 
 29 | ```yaml
 30 | tools:
 31 |     search_products_by_category:
 32 |         kind: couchbase-sql
 33 |         source: my-couchbase-instance
 34 |         statement: |
 35 |             SELECT p.name, p.price, p.description
 36 |             FROM products p
 37 |             WHERE p.category = $category AND p.price < $max_price
 38 |             ORDER BY p.price DESC
 39 |             LIMIT 10
 40 |         description: |
 41 |             Use this tool to get a list of products for a specific category under a maximum price.
 42 |             Takes a category name, e.g. "Electronics" and a maximum price e.g 500 and returns a list of product names, prices, and descriptions.
 43 |             Do NOT use this tool with invalid category names. Do NOT guess a category name, Do NOT guess a price.
 44 |             Example:
 45 |             {{
 46 |                 "category": "Electronics",
 47 |                 "max_price": 500
 48 |             }}
 49 |             Example:
 50 |             {{
 51 |                 "category": "Furniture",
 52 |                 "max_price": 1000
 53 |             }}
 54 |         parameters:
 55 |             - name: category
 56 |               type: string
 57 |               description: Product category name
 58 |             - name: max_price
 59 |               type: integer
 60 |               description: Maximum price (positive integer)
 61 | ```
 62 | 
 63 | ### Example with Template Parameters
 64 | 
 65 | > **Note:** This tool allows direct modifications to the SQL statement,
 66 | > including identifiers, column names, and table names. **This makes it more
 67 | > vulnerable to SQL injections**. Using basic parameters only (see above) is
 68 | > recommended for performance and safety reasons. For more details, please check
 69 | > [templateParameters](..#template-parameters).
 70 | 
 71 | ```yaml
 72 | tools:
 73 |  list_table:
 74 |     kind: couchbase-sql
 75 |     source: my-couchbase-instance
 76 |     statement: |
 77 |       SELECT * FROM {{.tableName}};
 78 |     description: |
 79 |       Use this tool to list all information from a specific table.
 80 |       Example:
 81 |       {{
 82 |           "tableName": "flights",
 83 |       }}
 84 |     templateParameters:
 85 |       - name: tableName
 86 |         type: string
 87 |         description: Table to select from
 88 | ```
 89 | 
 90 | ## Reference
 91 | 
 92 | | **field**          |                  **type**                        | **required** | **description**                                                                                                                            |
 93 | |--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
 94 | | kind               |                   string                         |     true     | Must be "couchbase-sql".                                                                                                                   |
 95 | | source             |                   string                         |     true     | Name of the source the SQL query should execute on.                                                                                        |
 96 | | description        |                   string                         |     true     | Description of the tool that is passed to the LLM.                                                                                         |
 97 | | statement          |                   string                         |     true     | SQL statement to execute                                                                                                                   |
 98 | | parameters         | [parameters](../#specifying-parameters)       |    false     | List of [parameters](../#specifying-parameters) that will be used with the SQL statement.                                               |
 99 | | templateParameters | [templateParameters](..#template-parameters) |    false     | List of [templateParameters](..#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
100 | | authRequired       |                array[string]                     |    false     | List of auth services that are required to use this tool.                                                                                  |
101 | 
```

--------------------------------------------------------------------------------
/internal/util/util.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 | package util
 15 | 
 16 | import (
 17 | 	"bytes"
 18 | 	"context"
 19 | 	"encoding/json"
 20 | 	"fmt"
 21 | 	"io"
 22 | 	"strings"
 23 | 
 24 | 	"github.com/go-playground/validator/v10"
 25 | 	yaml "github.com/goccy/go-yaml"
 26 | 	"github.com/googleapis/genai-toolbox/internal/log"
 27 | 	"github.com/googleapis/genai-toolbox/internal/telemetry"
 28 | )
 29 | 
 30 | // DecodeJSON decodes a given reader into an interface using the json decoder.
 31 | func DecodeJSON(r io.Reader, v interface{}) error {
 32 | 	defer io.Copy(io.Discard, r) //nolint:errcheck
 33 | 	d := json.NewDecoder(r)
 34 | 	// specify JSON numbers should get parsed to json.Number instead of float64 by default.
 35 | 	// This prevents loss between floats/ints.
 36 | 	d.UseNumber()
 37 | 	return d.Decode(v)
 38 | }
 39 | 
 40 | // ConvertNumbers traverses an interface and converts all json.Number
 41 | // instances to int64 or float64.
 42 | func ConvertNumbers(data any) (any, error) {
 43 | 	switch v := data.(type) {
 44 | 	// If it's a map, recursively convert the values.
 45 | 	case map[string]any:
 46 | 		for key, val := range v {
 47 | 			convertedVal, err := ConvertNumbers(val)
 48 | 			if err != nil {
 49 | 				return nil, err
 50 | 			}
 51 | 			v[key] = convertedVal
 52 | 		}
 53 | 		return v, nil
 54 | 
 55 | 	// If it's a slice, recursively convert the elements.
 56 | 	case []any:
 57 | 		for i, val := range v {
 58 | 			convertedVal, err := ConvertNumbers(val)
 59 | 			if err != nil {
 60 | 				return nil, err
 61 | 			}
 62 | 			v[i] = convertedVal
 63 | 		}
 64 | 		return v, nil
 65 | 
 66 | 	// If it's a json.Number, convert it to float or int
 67 | 	case json.Number:
 68 | 		// Check for a decimal point to decide the type.
 69 | 		if strings.Contains(v.String(), ".") {
 70 | 			return v.Float64()
 71 | 		}
 72 | 		return v.Int64()
 73 | 
 74 | 	// For all other types, return them as is.
 75 | 	default:
 76 | 		return data, nil
 77 | 	}
 78 | }
 79 | 
 80 | var _ yaml.InterfaceUnmarshalerContext = &DelayedUnmarshaler{}
 81 | 
 82 | // DelayedUnmarshaler is struct that saves the provided unmarshal function
 83 | // passed to UnmarshalYAML so it can be re-used later once the target interface
 84 | // is known.
 85 | type DelayedUnmarshaler struct {
 86 | 	unmarshal func(interface{}) error
 87 | }
 88 | 
 89 | func (d *DelayedUnmarshaler) UnmarshalYAML(ctx context.Context, unmarshal func(interface{}) error) error {
 90 | 	d.unmarshal = unmarshal
 91 | 	return nil
 92 | }
 93 | 
 94 | func (d *DelayedUnmarshaler) Unmarshal(v interface{}) error {
 95 | 	if d.unmarshal == nil {
 96 | 		return fmt.Errorf("nothing to unmarshal")
 97 | 	}
 98 | 	return d.unmarshal(v)
 99 | }
100 | 
101 | type contextKey string
102 | 
103 | // userAgentKey is the key used to store userAgent within context
104 | const userAgentKey contextKey = "userAgent"
105 | 
106 | // WithUserAgent adds a user agent into the context as a value
107 | func WithUserAgent(ctx context.Context, versionString string) context.Context {
108 | 	userAgent := "genai-toolbox/" + versionString
109 | 	return context.WithValue(ctx, userAgentKey, userAgent)
110 | }
111 | 
112 | // UserAgentFromContext retrieves the user agent or return an error
113 | func UserAgentFromContext(ctx context.Context) (string, error) {
114 | 	if ua := ctx.Value(userAgentKey); ua != nil {
115 | 		return ua.(string), nil
116 | 	} else {
117 | 		return "", fmt.Errorf("unable to retrieve user agent")
118 | 	}
119 | }
120 | 
121 | func NewStrictDecoder(v interface{}) (*yaml.Decoder, error) {
122 | 	b, err := yaml.Marshal(v)
123 | 	if err != nil {
124 | 		return nil, fmt.Errorf("fail to marshal %q: %w", v, err)
125 | 	}
126 | 
127 | 	dec := yaml.NewDecoder(
128 | 		bytes.NewReader(b),
129 | 		yaml.Strict(),
130 | 		yaml.Validator(validator.New()),
131 | 	)
132 | 	return dec, nil
133 | }
134 | 
135 | // loggerKey is the key used to store logger within context
136 | const loggerKey contextKey = "logger"
137 | 
138 | // WithLogger adds a logger into the context as a value
139 | func WithLogger(ctx context.Context, logger log.Logger) context.Context {
140 | 	return context.WithValue(ctx, loggerKey, logger)
141 | }
142 | 
143 | // LoggerFromContext retrieves the logger or return an error
144 | func LoggerFromContext(ctx context.Context) (log.Logger, error) {
145 | 	if logger, ok := ctx.Value(loggerKey).(log.Logger); ok {
146 | 		return logger, nil
147 | 	}
148 | 	return nil, fmt.Errorf("unable to retrieve logger")
149 | }
150 | 
151 | const instrumentationKey contextKey = "instrumentation"
152 | 
153 | // WithInstrumentation adds an instrumentation into the context as a value
154 | func WithInstrumentation(ctx context.Context, instrumentation *telemetry.Instrumentation) context.Context {
155 | 	return context.WithValue(ctx, instrumentationKey, instrumentation)
156 | }
157 | 
158 | // InstrumentationFromContext retrieves the instrumentation or return an error
159 | func InstrumentationFromContext(ctx context.Context) (*telemetry.Instrumentation, error) {
160 | 	if instrumentation, ok := ctx.Value(instrumentationKey).(*telemetry.Instrumentation); ok {
161 | 		return instrumentation, nil
162 | 	}
163 | 	return nil, fmt.Errorf("unable to retrieve instrumentation")
164 | }
165 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/bigquery/bigquery-sql.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "bigquery-sql"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   A "bigquery-sql" tool executes a pre-defined SQL statement.
  7 | aliases:
  8 | - /resources/tools/bigquery-sql
  9 | ---
 10 | 
 11 | ## About
 12 | 
 13 | A `bigquery-sql` tool executes a pre-defined SQL statement. It's compatible with
 14 | the following sources:
 15 | 
 16 | - [bigquery](../../sources/bigquery.md)
 17 | 
 18 | The behavior of this tool is influenced by the `writeMode` setting on its `bigquery` source:
 19 | 
 20 | - **`allowed` (default) and `blocked`:** These modes do not impose any restrictions on the `bigquery-sql` tool. The pre-defined SQL statement will be executed as-is.
 21 | - **`protected`:** This mode enables session-based execution. The tool will operate within the same BigQuery session as other tools using the same source, allowing it to interact with temporary resources like `TEMP` tables created within that session.
 22 | 
 23 | ### GoogleSQL
 24 | 
 25 | BigQuery uses [GoogleSQL][bigquery-googlesql] for querying data. The integration
 26 | with Toolbox supports this dialect. The specified SQL statement is executed, and
 27 | parameters can be inserted into the query. BigQuery supports both named parameters
 28 | (e.g., `@name`) and positional parameters (`?`), but they cannot be mixed in the
 29 | same query.
 30 | 
 31 | [bigquery-googlesql]: https://cloud.google.com/bigquery/docs/reference/standard-sql/
 32 | 
 33 | ## Example
 34 | 
 35 | > **Note:** This tool uses [parameterized
 36 | > queries](https://cloud.google.com/bigquery/docs/parameterized-queries) to
 37 | > prevent SQL injections. Query parameters can be used as substitutes for
 38 | > arbitrary expressions. Parameters cannot be used as substitutes for
 39 | > identifiers, column names, table names, or other parts of the query.
 40 | 
 41 | ```yaml
 42 | tools:
 43 |   # Example: Querying a user table in BigQuery
 44 |   search_users_bq:
 45 |     kind: bigquery-sql
 46 |     source: my-bigquery-source
 47 |     statement: |
 48 |       SELECT
 49 |         id,
 50 |         name,
 51 |         email
 52 |       FROM
 53 |         `my-project.my-dataset.users`
 54 |       WHERE
 55 |         id = @id OR email = @email;
 56 |     description: |
 57 |       Use this tool to get information for a specific user.
 58 |       Takes an id number or a name and returns info on the user.
 59 | 
 60 |       Example:
 61 |       {{
 62 |           "id": 123,
 63 |           "name": "Alice",
 64 |       }}
 65 |     parameters:
 66 |       - name: id
 67 |         type: integer
 68 |         description: User ID
 69 |       - name: email
 70 |         type: string
 71 |         description: Email address of the user
 72 | ```
 73 | 
 74 | ### Example with Template Parameters
 75 | 
 76 | > **Note:** This tool allows direct modifications to the SQL statement,
 77 | > including identifiers, column names, and table names. **This makes it more
 78 | > vulnerable to SQL injections**. Using basic parameters only (see above) is
 79 | > recommended for performance and safety reasons. For more details, please check
 80 | > [templateParameters](../#template-parameters).
 81 | 
 82 | ```yaml
 83 | tools:
 84 |  list_table:
 85 |     kind: bigquery-sql
 86 |     source: my-bigquery-source
 87 |     statement: |
 88 |       SELECT * FROM {{.tableName}};
 89 |     description: |
 90 |       Use this tool to list all information from a specific table.
 91 |       Example:
 92 |       {{
 93 |           "tableName": "flights",
 94 |       }}
 95 |     templateParameters:
 96 |       - name: tableName
 97 |         type: string
 98 |         description: Table to select from
 99 | ```
100 | 
101 | ## Reference
102 | 
103 | | **field**          |                  **type**                        | **required** | **description**                                                                                                                            |
104 | |--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
105 | | kind               |                   string                         |     true     | Must be "bigquery-sql".                                                                                                                    |
106 | | source             |                   string                         |     true     | Name of the source the GoogleSQL should execute on.                                                                                        |
107 | | description        |                   string                         |     true     | Description of the tool that is passed to the LLM.                                                                                         |
108 | | statement          |                   string                         |     true     | The GoogleSQL statement to execute.                                                                                                        |
109 | | parameters         | [parameters](../#specifying-parameters)       |    false     | List of [parameters](../#specifying-parameters) that will be inserted into the SQL statement.                                           |
110 | | templateParameters | [templateParameters](../#template-parameters) |    false     | List of [templateParameters](../#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
111 | 
```

--------------------------------------------------------------------------------
/internal/server/web_test.go:
--------------------------------------------------------------------------------

```go
  1 | package server
  2 | 
  3 | import (
  4 | 	"io"
  5 | 	"net/http"
  6 | 	"net/http/httptest"
  7 | 	"net/url"
  8 | 	"strings"
  9 | 	"testing"
 10 | 
 11 | 	"github.com/go-chi/chi/v5"
 12 | 	"github.com/go-goquery/goquery"
 13 | )
 14 | 
 15 | // TestWebEndpoint tests the routes defined in webRouter mounted under /ui.
 16 | func TestWebEndpoint(t *testing.T) {
 17 | 	mainRouter := chi.NewRouter()
 18 | 	webR, err := webRouter()
 19 | 	if err != nil {
 20 | 		t.Fatalf("Failed to create webRouter: %v", err)
 21 | 	}
 22 | 	mainRouter.Mount("/ui", webR)
 23 | 
 24 | 	ts := httptest.NewServer(mainRouter)
 25 | 	defer ts.Close()
 26 | 
 27 | 	testCases := []struct {
 28 | 		name            string
 29 | 		path            string
 30 | 		wantStatus      int
 31 | 		wantContentType string
 32 | 		wantPageTitle   string
 33 | 	}{
 34 | 		{
 35 | 			name:            "web index page",
 36 | 			path:            "/ui",
 37 | 			wantStatus:      http.StatusOK,
 38 | 			wantContentType: "text/html",
 39 | 			wantPageTitle:   "Toolbox UI",
 40 | 		},
 41 | 		{
 42 | 			name:            "web index page with trailing slash",
 43 | 			path:            "/ui/",
 44 | 			wantStatus:      http.StatusOK,
 45 | 			wantContentType: "text/html",
 46 | 			wantPageTitle:   "Toolbox UI",
 47 | 		},
 48 | 		{
 49 | 			name:            "web tools page",
 50 | 			path:            "/ui/tools",
 51 | 			wantStatus:      http.StatusOK,
 52 | 			wantContentType: "text/html",
 53 | 			wantPageTitle:   "Tools View",
 54 | 		},
 55 | 		{
 56 | 			name:            "web tools page with trailing slash",
 57 | 			path:            "/ui/tools/",
 58 | 			wantStatus:      http.StatusOK,
 59 | 			wantContentType: "text/html",
 60 | 			wantPageTitle:   "Tools View",
 61 | 		},
 62 | 		{
 63 | 			name:            "web toolsets page",
 64 | 			path:            "/ui/toolsets",
 65 | 			wantStatus:      http.StatusOK,
 66 | 			wantContentType: "text/html",
 67 | 			wantPageTitle:   "Toolsets View",
 68 | 		},
 69 | 		{
 70 | 			name:            "web toolsets page with trailing slash",
 71 | 			path:            "/ui/toolsets/",
 72 | 			wantStatus:      http.StatusOK,
 73 | 			wantContentType: "text/html",
 74 | 			wantPageTitle:   "Toolsets View",
 75 | 		},
 76 | 	}
 77 | 
 78 | 	for _, tc := range testCases {
 79 | 		t.Run(tc.name, func(t *testing.T) {
 80 | 			reqURL := ts.URL + tc.path
 81 | 			req, err := http.NewRequest(http.MethodGet, reqURL, nil)
 82 | 			if err != nil {
 83 | 				t.Fatalf("Failed to create request: %v", err)
 84 | 			}
 85 | 
 86 | 			client := ts.Client()
 87 | 			resp, err := client.Do(req)
 88 | 			if err != nil {
 89 | 				t.Fatalf("Failed to send request: %v", err)
 90 | 			}
 91 | 			defer resp.Body.Close()
 92 | 
 93 | 			if resp.StatusCode != tc.wantStatus {
 94 | 				body, _ := io.ReadAll(resp.Body)
 95 | 				t.Fatalf("Unexpected status code for %s: got %d, want %d, body: %s", tc.path, resp.StatusCode, tc.wantStatus, string(body))
 96 | 			}
 97 | 
 98 | 			contentType := resp.Header.Get("Content-Type")
 99 | 			if !strings.HasPrefix(contentType, tc.wantContentType) {
100 | 				t.Errorf("Unexpected Content-Type header for %s: got %s, want prefix %s", tc.path, contentType, tc.wantContentType)
101 | 			}
102 | 
103 | 			body, err := io.ReadAll(resp.Body)
104 | 			if err != nil {
105 | 				t.Fatalf("Failed to read response body: %v", err)
106 | 			}
107 | 
108 | 			doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
109 | 			if err != nil {
110 | 				t.Fatalf("Failed to parse HTML: %v", err)
111 | 			}
112 | 
113 | 			gotPageTitle := doc.Find("title").Text()
114 | 			if gotPageTitle != tc.wantPageTitle {
115 | 				t.Errorf("Unexpected page title for %s: got %q, want %q", tc.path, gotPageTitle, tc.wantPageTitle)
116 | 			}
117 | 
118 | 			pageURL := resp.Request.URL
119 | 			verifyLinkedResources(t, ts, pageURL, doc)
120 | 		})
121 | 	}
122 | }
123 | 
124 | // verifyLinkedResources checks that resources linked in the HTML are served correctly.
125 | func verifyLinkedResources(t *testing.T, ts *httptest.Server, pageURL *url.URL, doc *goquery.Document) {
126 | 	t.Helper()
127 | 
128 | 	selectors := map[string]string{
129 | 		"stylesheet": "link[rel=stylesheet]",
130 | 		"script":     "script[src]",
131 | 	}
132 | 
133 | 	attrMap := map[string]string{
134 | 		"stylesheet": "href",
135 | 		"script":     "src",
136 | 	}
137 | 
138 | 	foundResource := false
139 | 	for resourceType, selector := range selectors {
140 | 		doc.Find(selector).Each(func(i int, s *goquery.Selection) {
141 | 			foundResource = true
142 | 			attrName := attrMap[resourceType]
143 | 			resourcePath, exists := s.Attr(attrName)
144 | 			if !exists || resourcePath == "" {
145 | 				t.Errorf("Resource element %s is missing attribute %s on page %s", selector, attrName, pageURL.String())
146 | 				return
147 | 			}
148 | 
149 | 			// Resolve the URL relative to the page URL
150 | 			resURL, err := url.Parse(resourcePath)
151 | 			if err != nil {
152 | 				t.Errorf("Failed to parse resource path %q on page %s: %v", resourcePath, pageURL.String(), err)
153 | 				return
154 | 			}
155 | 			absoluteResourceURL := pageURL.ResolveReference(resURL)
156 | 
157 | 			// Skip external hosts
158 | 			if absoluteResourceURL.Host != pageURL.Host {
159 | 				t.Logf("Skipping resource on different host: %s", absoluteResourceURL.String())
160 | 				return
161 | 			}
162 | 
163 | 			resp, err := ts.Client().Get(absoluteResourceURL.String())
164 | 			if err != nil {
165 | 				t.Errorf("Failed to GET %s resource %s: %v", resourceType, absoluteResourceURL.String(), err)
166 | 				return
167 | 			}
168 | 			defer resp.Body.Close()
169 | 
170 | 			if resp.StatusCode != http.StatusOK {
171 | 				t.Errorf("Resource %s %s: expected status OK (200), but got %d", resourceType, absoluteResourceURL.String(), resp.StatusCode)
172 | 			}
173 | 		})
174 | 	}
175 | 
176 | 	if !foundResource {
177 | 		t.Logf("No stylesheet or script resources found to check on page %s", pageURL.String())
178 | 	}
179 | }
180 | 
```

--------------------------------------------------------------------------------
/internal/tools/alloydb/alloydblistusers/alloydblistusers.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 alloydblistusers
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	alloydbadmin "github.com/googleapis/genai-toolbox/internal/sources/alloydbadmin"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | )
 26 | 
 27 | const kind string = "alloydb-list-users"
 28 | 
 29 | func init() {
 30 | 	if !tools.Register(kind, newConfig) {
 31 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 32 | 	}
 33 | }
 34 | 
 35 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 36 | 	actual := Config{Name: name}
 37 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 38 | 		return nil, err
 39 | 	}
 40 | 	return actual, nil
 41 | }
 42 | 
 43 | // Configuration for the list-users tool.
 44 | type Config struct {
 45 | 	Name         string   `yaml:"name" validate:"required"`
 46 | 	Kind         string   `yaml:"kind" validate:"required"`
 47 | 	Source       string   `yaml:"source" validate:"required"`
 48 | 	Description  string   `yaml:"description"`
 49 | 	AuthRequired []string `yaml:"authRequired"`
 50 | 	BaseURL      string   `yaml:"baseURL"`
 51 | }
 52 | 
 53 | // validate interface
 54 | var _ tools.ToolConfig = Config{}
 55 | 
 56 | // ToolConfigKind returns the kind of the tool.
 57 | func (cfg Config) ToolConfigKind() string {
 58 | 	return kind
 59 | }
 60 | 
 61 | // Initialize initializes the tool from the configuration.
 62 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 63 | 	rawS, ok := srcs[cfg.Source]
 64 | 	if !ok {
 65 | 		return nil, fmt.Errorf("source %q not found", cfg.Source)
 66 | 	}
 67 | 
 68 | 	s, ok := rawS.(*alloydbadmin.Source)
 69 | 	if !ok {
 70 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `%s`", kind, alloydbadmin.SourceKind)
 71 | 	}
 72 | 
 73 | 	allParameters := tools.Parameters{
 74 | 		tools.NewStringParameter("project", "The GCP project ID."),
 75 | 		tools.NewStringParameter("location", "The location of the cluster (e.g., 'us-central1')."),
 76 | 		tools.NewStringParameter("cluster", "The ID of the cluster to list users from."),
 77 | 	}
 78 | 	paramManifest := allParameters.Manifest()
 79 | 
 80 | 	description := cfg.Description
 81 | 	if description == "" {
 82 | 		description = "Lists all AlloyDB users in a given project, location and cluster."
 83 | 	}
 84 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, description, cfg.AuthRequired, allParameters)
 85 | 
 86 | 	return Tool{
 87 | 		Name:        cfg.Name,
 88 | 		Kind:        kind,
 89 | 		Source:      s,
 90 | 		AllParams:   allParameters,
 91 | 		manifest:    tools.Manifest{Description: description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
 92 | 		mcpManifest: mcpManifest,
 93 | 	}, nil
 94 | }
 95 | 
 96 | // Tool represents the list-users tool.
 97 | type Tool struct {
 98 | 	Name        string `yaml:"name"`
 99 | 	Kind        string `yaml:"kind"`
100 | 	Description string `yaml:"description"`
101 | 
102 | 	Source    *alloydbadmin.Source
103 | 	AllParams tools.Parameters `yaml:"allParams"`
104 | 
105 | 	manifest    tools.Manifest
106 | 	mcpManifest tools.McpManifest
107 | }
108 | 
109 | // Invoke executes the tool's logic.
110 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
111 | 	paramsMap := params.AsMap()
112 | 
113 | 	project, ok := paramsMap["project"].(string)
114 | 	if !ok {
115 | 		return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
116 | 	}
117 | 	location, ok := paramsMap["location"].(string)
118 | 	if !ok {
119 | 		return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
120 | 	}
121 | 	cluster, ok := paramsMap["cluster"].(string)
122 | 	if !ok {
123 | 		return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
124 | 	}
125 | 
126 | 	service, err := t.Source.GetService(ctx, string(accessToken))
127 | 	if err != nil {
128 | 		return nil, err
129 | 	}
130 | 
131 | 	urlString := fmt.Sprintf("projects/%s/locations/%s/clusters/%s", project, location, cluster)
132 | 
133 | 	resp, err := service.Projects.Locations.Clusters.Users.List(urlString).Do()
134 | 	if err != nil {
135 | 		return nil, fmt.Errorf("error listing AlloyDB users: %w", err)
136 | 	}
137 | 
138 | 	return resp, nil
139 | }
140 | 
141 | // ParseParams parses the parameters for the tool.
142 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
143 | 	return tools.ParseParams(t.AllParams, data, claims)
144 | }
145 | 
146 | // Manifest returns the tool's manifest.
147 | func (t Tool) Manifest() tools.Manifest {
148 | 	return t.manifest
149 | }
150 | 
151 | // McpManifest returns the tool's MCP manifest.
152 | func (t Tool) McpManifest() tools.McpManifest {
153 | 	return t.mcpManifest
154 | }
155 | 
156 | // Authorized checks if the tool is authorized.
157 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
158 | 	return true
159 | }
160 | 
161 | func (t Tool) RequiresClientAuthorization() bool {
162 | 	return t.Source.UseClientAuthorization()
163 | }
164 | 
```

--------------------------------------------------------------------------------
/internal/tools/mongodb/mongodbinsertmany/mongodbinsertmany.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 | package mongodbinsertmany
 15 | 
 16 | import (
 17 | 	"context"
 18 | 	"errors"
 19 | 	"fmt"
 20 | 
 21 | 	"github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	mongosrc "github.com/googleapis/genai-toolbox/internal/sources/mongodb"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | 	"go.mongodb.org/mongo-driver/bson"
 26 | 	"go.mongodb.org/mongo-driver/mongo"
 27 | 	"go.mongodb.org/mongo-driver/mongo/options"
 28 | )
 29 | 
 30 | const kind string = "mongodb-insert-many"
 31 | 
 32 | const paramDataKey = "data"
 33 | 
 34 | func init() {
 35 | 	if !tools.Register(kind, newConfig) {
 36 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 37 | 	}
 38 | }
 39 | 
 40 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 41 | 	actual := Config{Name: name}
 42 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 43 | 		return nil, err
 44 | 	}
 45 | 	return actual, nil
 46 | }
 47 | 
 48 | type Config struct {
 49 | 	Name         string   `yaml:"name" validate:"required"`
 50 | 	Kind         string   `yaml:"kind" validate:"required"`
 51 | 	Source       string   `yaml:"source" validate:"required"`
 52 | 	AuthRequired []string `yaml:"authRequired" validate:"required"`
 53 | 	Description  string   `yaml:"description" validate:"required"`
 54 | 	Database     string   `yaml:"database" validate:"required"`
 55 | 	Collection   string   `yaml:"collection" validate:"required"`
 56 | 	Canonical    bool     `yaml:"canonical" validate:"required"` //i want to force the user to choose
 57 | }
 58 | 
 59 | // validate interface
 60 | var _ tools.ToolConfig = Config{}
 61 | 
 62 | func (cfg Config) ToolConfigKind() string {
 63 | 	return kind
 64 | }
 65 | 
 66 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 67 | 	// verify source exists
 68 | 	rawS, ok := srcs[cfg.Source]
 69 | 	if !ok {
 70 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 71 | 	}
 72 | 
 73 | 	// verify the source is compatible
 74 | 	s, ok := rawS.(*mongosrc.Source)
 75 | 	if !ok {
 76 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `mongodb`", kind)
 77 | 	}
 78 | 
 79 | 	dataParam := tools.NewStringParameterWithRequired(paramDataKey, "the JSON payload to insert, should be a JSON array of documents", true)
 80 | 
 81 | 	allParameters := tools.Parameters{dataParam}
 82 | 
 83 | 	// Create Toolbox manifest
 84 | 	paramManifest := allParameters.Manifest()
 85 | 
 86 | 	if paramManifest == nil {
 87 | 		paramManifest = make([]tools.ParameterManifest, 0)
 88 | 	}
 89 | 
 90 | 	// Create MCP manifest
 91 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, allParameters)
 92 | 	// finish tool setup
 93 | 	return Tool{
 94 | 		Name:          cfg.Name,
 95 | 		Kind:          kind,
 96 | 		AuthRequired:  cfg.AuthRequired,
 97 | 		Collection:    cfg.Collection,
 98 | 		Canonical:     cfg.Canonical,
 99 | 		PayloadParams: allParameters,
100 | 		database:      s.Client.Database(cfg.Database),
101 | 		manifest:      tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
102 | 		mcpManifest:   mcpManifest,
103 | 	}, nil
104 | }
105 | 
106 | // validate interface
107 | var _ tools.Tool = Tool{}
108 | 
109 | type Tool struct {
110 | 	Name          string   `yaml:"name"`
111 | 	Kind          string   `yaml:"kind"`
112 | 	AuthRequired  []string `yaml:"authRequired"`
113 | 	Description   string   `yaml:"description"`
114 | 	Collection    string   `yaml:"collection"`
115 | 	Canonical     bool     `yaml:"canonical" validation:"required"` //i want to force the user to choose
116 | 	PayloadParams tools.Parameters
117 | 
118 | 	database    *mongo.Database
119 | 	manifest    tools.Manifest
120 | 	mcpManifest tools.McpManifest
121 | }
122 | 
123 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
124 | 	if len(params) == 0 {
125 | 		return nil, errors.New("no input found")
126 | 	}
127 | 
128 | 	paramsMap := params.AsMap()
129 | 
130 | 	var jsonData, ok = paramsMap[paramDataKey].(string)
131 | 	if !ok {
132 | 		return nil, errors.New("no input found")
133 | 	}
134 | 
135 | 	var data = []any{}
136 | 	err := bson.UnmarshalExtJSON([]byte(jsonData), t.Canonical, &data)
137 | 	if err != nil {
138 | 		return nil, err
139 | 	}
140 | 
141 | 	res, err := t.database.Collection(t.Collection).InsertMany(ctx, data, options.InsertMany())
142 | 	if err != nil {
143 | 		return nil, err
144 | 	}
145 | 
146 | 	return res.InsertedIDs, nil
147 | }
148 | 
149 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
150 | 	return tools.ParseParams(t.PayloadParams, data, claims)
151 | }
152 | 
153 | func (t Tool) Manifest() tools.Manifest {
154 | 	return t.manifest
155 | }
156 | 
157 | func (t Tool) McpManifest() tools.McpManifest {
158 | 	return t.mcpManifest
159 | }
160 | 
161 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
162 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
163 | }
164 | 
165 | func (t Tool) RequiresClientAuthorization() bool {
166 | 	return false
167 | }
168 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/trino/trino-sql.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "trino-sql"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   A "trino-sql" tool executes a pre-defined SQL statement against a Trino
  7 |   database.
  8 | aliases:
  9 | - /resources/tools/trino-sql
 10 | ---
 11 | 
 12 | ## About
 13 | 
 14 | A `trino-sql` tool executes a pre-defined SQL statement against a Trino
 15 | database. It's compatible with any of the following sources:
 16 | 
 17 | - [trino](../../sources/trino.md)
 18 | 
 19 | The specified SQL statement is executed as a [prepared statement][trino-prepare],
 20 | and specified parameters will be inserted according to their position: e.g. `$1`
 21 | will be the first parameter specified, `$2` will be the second parameter, and so
 22 | on. If template parameters are included, they will be resolved before execution
 23 | of the prepared statement.
 24 | 
 25 | [trino-prepare]: https://trino.io/docs/current/sql/prepare.html
 26 | 
 27 | ## Example
 28 | 
 29 | > **Note:** This tool uses parameterized queries to prevent SQL injections.
 30 | > Query parameters can be used as substitutes for arbitrary expressions.
 31 | > Parameters cannot be used as substitutes for identifiers, column names, table
 32 | > names, or other parts of the query.
 33 | 
 34 | ```yaml
 35 | tools:
 36 |  search_orders_by_region:
 37 |     kind: trino-sql
 38 |     source: my-trino-instance
 39 |     statement: |
 40 |       SELECT * FROM hive.sales.orders
 41 |       WHERE region = $1
 42 |       AND order_date >= DATE($2)
 43 |       LIMIT 10
 44 |     description: |
 45 |       Use this tool to get information for orders in a specific region.
 46 |       Takes a region code and date and returns info on the orders.
 47 |       Do NOT use this tool with an order id. Do NOT guess a region code or date.
 48 |       A region code is a code for a geographic region consisting of two-character
 49 |       region designator and followed by optional subregion.
 50 |       For example, if given US-WEST, the region is "US-WEST".
 51 |       Another example for this is EU-CENTRAL, the region is "EU-CENTRAL".
 52 |       If the tool returns more than one option choose the date closest to today.
 53 |       Example:
 54 |       {{
 55 |           "region": "US-WEST",
 56 |           "order_date": "2024-01-01",
 57 |       }}
 58 |       Example:
 59 |       {{
 60 |           "region": "EU-CENTRAL",
 61 |           "order_date": "2024-01-15",
 62 |       }}
 63 |     parameters:
 64 |       - name: region
 65 |         type: string
 66 |         description: Region unique identifier
 67 |       - name: order_date
 68 |         type: string
 69 |         description: Order date in YYYY-MM-DD format
 70 | ```
 71 | 
 72 | ### Example with Template Parameters
 73 | 
 74 | > **Note:** This tool allows direct modifications to the SQL statement,
 75 | > including identifiers, column names, and table names. **This makes it more
 76 | > vulnerable to SQL injections**. Using basic parameters only (see above) is
 77 | > recommended for performance and safety reasons. For more details, please check
 78 | > [templateParameters](..#template-parameters).
 79 | 
 80 | ```yaml
 81 | tools:
 82 |  list_table:
 83 |     kind: trino-sql
 84 |     source: my-trino-instance
 85 |     statement: |
 86 |       SELECT * FROM {{.tableName}}
 87 |     description: |
 88 |       Use this tool to list all information from a specific table.
 89 |       Example:
 90 |       {{
 91 |           "tableName": "hive.sales.orders",
 92 |       }}
 93 |     templateParameters:
 94 |       - name: tableName
 95 |         type: string
 96 |         description: Table to select from
 97 | ```
 98 | 
 99 | ## Reference
100 | 
101 | | **field**           |                  **type**                                 | **required** | **description**                                                                                                                            |
102 | |---------------------|:---------------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
103 | | kind                |                   string                                  |     true     | Must be "trino-sql".                                                                                                                       |
104 | | source              |                   string                                  |     true     | Name of the source the SQL should execute on.                                                                                              |
105 | | description         |                   string                                  |     true     | Description of the tool that is passed to the LLM.                                                                                         |
106 | | statement           |                   string                                  |     true     | SQL statement to execute on.                                                                                                               |
107 | | parameters          | [parameters](../#specifying-parameters)                |    false     | List of [parameters](../#specifying-parameters) that will be inserted into the SQL statement.                                           |
108 | | templateParameters  |  [templateParameters](..#template-parameters)         |    false     | List of [templateParameters](..#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
109 | 
```

--------------------------------------------------------------------------------
/internal/tools/looker/lookergetmodels/lookergetmodels.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 | package lookergetmodels
 15 | 
 16 | import (
 17 | 	"context"
 18 | 	"fmt"
 19 | 
 20 | 	yaml "github.com/goccy/go-yaml"
 21 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 22 | 	lookersrc "github.com/googleapis/genai-toolbox/internal/sources/looker"
 23 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools/looker/lookercommon"
 25 | 	"github.com/googleapis/genai-toolbox/internal/util"
 26 | 
 27 | 	"github.com/looker-open-source/sdk-codegen/go/rtl"
 28 | 	v4 "github.com/looker-open-source/sdk-codegen/go/sdk/v4"
 29 | )
 30 | 
 31 | const kind string = "looker-get-models"
 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 Config struct {
 48 | 	Name         string   `yaml:"name" validate:"required"`
 49 | 	Kind         string   `yaml:"kind" validate:"required"`
 50 | 	Source       string   `yaml:"source" validate:"required"`
 51 | 	Description  string   `yaml:"description" validate:"required"`
 52 | 	AuthRequired []string `yaml:"authRequired"`
 53 | }
 54 | 
 55 | // validate interface
 56 | var _ tools.ToolConfig = Config{}
 57 | 
 58 | func (cfg Config) ToolConfigKind() string {
 59 | 	return kind
 60 | }
 61 | 
 62 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 63 | 	// verify source exists
 64 | 	rawS, ok := srcs[cfg.Source]
 65 | 	if !ok {
 66 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 67 | 	}
 68 | 
 69 | 	// verify the source is compatible
 70 | 	s, ok := rawS.(*lookersrc.Source)
 71 | 	if !ok {
 72 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `looker`", kind)
 73 | 	}
 74 | 
 75 | 	parameters := tools.Parameters{}
 76 | 
 77 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
 78 | 
 79 | 	// finish tool setup
 80 | 	return Tool{
 81 | 		Name:           cfg.Name,
 82 | 		Kind:           kind,
 83 | 		Parameters:     parameters,
 84 | 		AuthRequired:   cfg.AuthRequired,
 85 | 		UseClientOAuth: s.UseClientOAuth,
 86 | 		Client:         s.Client,
 87 | 		ApiSettings:    s.ApiSettings,
 88 | 		manifest: tools.Manifest{
 89 | 			Description:  cfg.Description,
 90 | 			Parameters:   parameters.Manifest(),
 91 | 			AuthRequired: cfg.AuthRequired,
 92 | 		},
 93 | 		mcpManifest:      mcpManifest,
 94 | 		ShowHiddenModels: s.ShowHiddenModels,
 95 | 	}, nil
 96 | }
 97 | 
 98 | // validate interface
 99 | var _ tools.Tool = Tool{}
100 | 
101 | type Tool struct {
102 | 	Name             string `yaml:"name"`
103 | 	Kind             string `yaml:"kind"`
104 | 	UseClientOAuth   bool
105 | 	Client           *v4.LookerSDK
106 | 	ApiSettings      *rtl.ApiSettings
107 | 	AuthRequired     []string         `yaml:"authRequired"`
108 | 	Parameters       tools.Parameters `yaml:"parameters"`
109 | 	manifest         tools.Manifest
110 | 	mcpManifest      tools.McpManifest
111 | 	ShowHiddenModels bool
112 | }
113 | 
114 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
115 | 	logger, err := util.LoggerFromContext(ctx)
116 | 	if err != nil {
117 | 		return nil, fmt.Errorf("unable to get logger from ctx: %s", err)
118 | 	}
119 | 
120 | 	excludeEmpty := false
121 | 	excludeHidden := !t.ShowHiddenModels
122 | 	includeInternal := true
123 | 
124 | 	sdk, err := lookercommon.GetLookerSDK(t.UseClientOAuth, t.ApiSettings, t.Client, accessToken)
125 | 	if err != nil {
126 | 		return nil, fmt.Errorf("error getting sdk: %w", err)
127 | 	}
128 | 	req := v4.RequestAllLookmlModels{
129 | 		ExcludeEmpty:    &excludeEmpty,
130 | 		ExcludeHidden:   &excludeHidden,
131 | 		IncludeInternal: &includeInternal,
132 | 	}
133 | 	resp, err := sdk.AllLookmlModels(req, t.ApiSettings)
134 | 	if err != nil {
135 | 		return nil, fmt.Errorf("error making get_models request: %s", err)
136 | 	}
137 | 
138 | 	var data []any
139 | 	for _, v := range resp {
140 | 		logger.DebugContext(ctx, "Got response element of %v\n", v)
141 | 		vMap := make(map[string]any)
142 | 		vMap["label"] = *v.Label
143 | 		vMap["name"] = *v.Name
144 | 		vMap["project_name"] = *v.ProjectName
145 | 		logger.DebugContext(ctx, "Converted to %v\n", vMap)
146 | 		data = append(data, vMap)
147 | 	}
148 | 	logger.DebugContext(ctx, "data = ", data)
149 | 
150 | 	return data, nil
151 | }
152 | 
153 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
154 | 	return tools.ParamValues{}, nil
155 | }
156 | 
157 | func (t Tool) Manifest() tools.Manifest {
158 | 	return t.manifest
159 | }
160 | 
161 | func (t Tool) McpManifest() tools.McpManifest {
162 | 	return t.mcpManifest
163 | }
164 | 
165 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
166 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
167 | }
168 | 
169 | func (t Tool) RequiresClientAuthorization() bool {
170 | 	return t.UseClientOAuth
171 | }
172 | 
```

--------------------------------------------------------------------------------
/internal/prebuiltconfigs/tools/sqlite.yaml:
--------------------------------------------------------------------------------

```yaml
  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 | sources:
 16 |   sqlite-source:
 17 |     kind: sqlite
 18 |     database: ${SQLITE_DATABASE}
 19 | tools:
 20 |   execute_sql:
 21 |     kind: sqlite-execute-sql
 22 |     source: sqlite-source
 23 |     description: Use this tool to execute SQL.
 24 |   list_tables:
 25 |     kind: sqlite-sql
 26 |     source: sqlite-source
 27 |     description: "Lists SQLite tables. Use 'output_format' ('simple'/'detailed') and 'table_names' (comma-separated or empty) to control output."
 28 |     statement: |
 29 |       WITH table_columns AS (
 30 |         SELECT
 31 |           m.name AS table_name,
 32 |           json_group_array(json_object('column_name', ti.name, 'data_type', ti.type, 'ordinal_position', ti.cid, 'is_not_nullable', ti."notnull" = 1, 'column_default', ti.dflt_value, 'is_primary_key', ti.pk > 0)) AS details
 33 |         FROM sqlite_master AS m, pragma_table_info(m.name) AS ti
 34 |         WHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'
 35 |         GROUP BY m.name
 36 |       ),
 37 |       table_constraints AS (
 38 |         SELECT
 39 |           table_name,
 40 |           json_group_array(json(details)) AS details
 41 |         FROM (
 42 |           SELECT m.name AS table_name, json_object('constraint_name', 'PRIMARY', 'constraint_type', 'PRIMARY KEY', 'constraint_columns', json_group_array(T.name)) AS details
 43 |           FROM sqlite_master AS m, pragma_table_info(m.name) AS T
 44 |           WHERE m.type = 'table' AND T.pk > 0
 45 |           GROUP BY m.name
 46 |           HAVING COUNT(T.name) > 0
 47 |           UNION ALL
 48 |           SELECT m.name, json_object('constraint_name', 'fk_' || m.name || '_' || F.id, 'constraint_type', 'FOREIGN KEY', 'constraint_columns', json_group_array(F."from"), 'foreign_key_referenced_table', F."table", 'foreign_key_referenced_columns', json_group_array(F."to"))
 49 |           FROM sqlite_master AS m, pragma_foreign_key_list(m.name) AS F
 50 |           WHERE m.type = 'table'
 51 |           GROUP BY m.name, F.id
 52 |           UNION ALL
 53 |           SELECT m.name, json_object('constraint_name', I.name, 'constraint_type', 'UNIQUE', 'constraint_columns', (SELECT json_group_array(C.name) FROM pragma_index_info(I.name) AS C ORDER BY C.seqno))
 54 |           FROM sqlite_master AS m, pragma_index_list(m.name) AS I
 55 |           WHERE m.type = 'table' AND I."unique" = 1 AND I.origin != 'pk'
 56 |         )
 57 |         GROUP BY table_name
 58 |       ),
 59 |       table_indexes AS (
 60 |         SELECT
 61 |           m.name AS table_name,
 62 |           json_group_array(json_object('index_name', il.name, 'is_unique', il."unique" = 1, 'is_primary', il.origin = 'pk', 'index_columns', (SELECT json_group_array(ii.name) FROM pragma_index_info(il.name) AS ii))) AS details
 63 |         FROM sqlite_master AS m, pragma_index_list(m.name) AS il
 64 |         WHERE m.type = 'table' AND m.name NOT LIKE 'sqlite_%'
 65 |         GROUP BY m.name
 66 |       ),
 67 |       table_triggers AS (
 68 |         SELECT
 69 |           tbl_name AS table_name,
 70 |           json_group_array(json_object('trigger_name', name, 'trigger_definition', sql)) AS details
 71 |         FROM sqlite_master
 72 |         WHERE type = 'trigger'
 73 |         GROUP BY tbl_name
 74 |       )
 75 |       SELECT
 76 |         CASE
 77 |           WHEN '{{.output_format}}' = 'simple' THEN json_object('name', m.name)
 78 |           ELSE json_object(
 79 |             'schema_name', 'main',
 80 |             'object_name', m.name,
 81 |             'object_type', m.type,
 82 |             'columns', json(COALESCE(tc.details, '[]')),
 83 |             'constraints', json(COALESCE(tcons.details, '[]')),
 84 |             'indexes', json(COALESCE(ti.details, '[]')),
 85 |             'triggers', json(COALESCE(tt.details, '[]'))
 86 |           )
 87 |         END AS object_details
 88 |       FROM
 89 |         sqlite_master AS m
 90 |       LEFT JOIN table_columns tc ON m.name = tc.table_name
 91 |       LEFT JOIN table_constraints tcons ON m.name = tcons.table_name
 92 |       LEFT JOIN table_indexes ti ON m.name = ti.table_name
 93 |       LEFT JOIN table_triggers tt ON m.name = tt.table_name
 94 |       WHERE
 95 |         m.type = 'table'
 96 |         AND m.name NOT LIKE 'sqlite_%'
 97 |         {{if .table_names}}
 98 |         AND instr(',' || '{{.table_names}}' || ',', ',' || m.name || ',') > 0
 99 |         {{end}};
100 |     templateParameters:
101 |       - name: output_format
102 |         type: string
103 |         description: "Optional: Use 'simple' to return table names only or use 'detailed' to return the full information schema."
104 |         default: "detailed"
105 |       - name: table_names
106 |         type: string
107 |         description: "Optional: A comma-separated list of table names. If empty, details for all tables in user-accessible schemas will be listed."
108 |         default: ""
109 | toolsets:
110 |   sqlite_database_tools:
111 |     - execute_sql
112 |     - list_tables
113 | 
```

--------------------------------------------------------------------------------
/internal/sources/oracle/oracle.go:
--------------------------------------------------------------------------------

```go
  1 | // Copyright © 2025, Oracle and/or its affiliates.
  2 | package oracle
  3 | 
  4 | import (
  5 | 	"context"
  6 | 	"database/sql"
  7 | 	"fmt"
  8 | 	"os"
  9 | 	"strings"
 10 | 
 11 | 	"github.com/goccy/go-yaml"
 12 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 13 | 	"github.com/googleapis/genai-toolbox/internal/util"
 14 | 	_ "github.com/sijms/go-ora/v2"
 15 | 	"go.opentelemetry.io/otel/trace"
 16 | )
 17 | 
 18 | const SourceKind string = "oracle"
 19 | 
 20 | // validate interface
 21 | var _ sources.SourceConfig = Config{}
 22 | 
 23 | func init() {
 24 | 	if !sources.Register(SourceKind, newConfig) {
 25 | 		panic(fmt.Sprintf("source kind %q already registered", SourceKind))
 26 | 	}
 27 | }
 28 | 
 29 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
 30 | 	actual := Config{Name: name}
 31 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 32 | 		return nil, err
 33 | 	}
 34 | 
 35 | 	// Validate that we have one of: tns_alias, connection_string, or host+service_name
 36 | 	if err := actual.validate(); err != nil {
 37 | 		return nil, fmt.Errorf("invalid Oracle configuration: %w", err)
 38 | 	}
 39 | 
 40 | 	return actual, nil
 41 | }
 42 | 
 43 | type Config struct {
 44 | 	Name             string `yaml:"name" validate:"required"`
 45 | 	Kind             string `yaml:"kind" validate:"required"`
 46 | 	ConnectionString string `yaml:"connectionString,omitempty"` // Direct connection string (hostname[:port]/servicename)
 47 | 	TnsAlias         string `yaml:"tnsAlias,omitempty"`         // TNS alias from tnsnames.ora
 48 | 	Host             string `yaml:"host,omitempty"`             // Optional when using connectionString/tnsAlias
 49 | 	Port             int    `yaml:"port,omitempty"`             // Explicit port support
 50 | 	ServiceName      string `yaml:"serviceName,omitempty"`      // Optional when using connectionString/tnsAlias
 51 | 	User             string `yaml:"user" validate:"required"`
 52 | 	Password         string `yaml:"password" validate:"required"`
 53 | 	TnsAdmin         string `yaml:"tnsAdmin,omitempty"` // Optional: override TNS_ADMIN environment variable
 54 | }
 55 | 
 56 | // validate ensures we have one of: tns_alias, connection_string, or host+service_name
 57 | func (c Config) validate() error {
 58 | 	hasTnsAlias := strings.TrimSpace(c.TnsAlias) != ""
 59 | 	hasConnStr := strings.TrimSpace(c.ConnectionString) != ""
 60 | 	hasHostService := strings.TrimSpace(c.Host) != "" && strings.TrimSpace(c.ServiceName) != ""
 61 | 
 62 | 	connectionMethods := 0
 63 | 	if hasTnsAlias {
 64 | 		connectionMethods++
 65 | 	}
 66 | 	if hasConnStr {
 67 | 		connectionMethods++
 68 | 	}
 69 | 	if hasHostService {
 70 | 		connectionMethods++
 71 | 	}
 72 | 
 73 | 	if connectionMethods == 0 {
 74 | 		return fmt.Errorf("must provide one of: 'tns_alias', 'connection_string', or both 'host' and 'service_name'")
 75 | 	}
 76 | 
 77 | 	if connectionMethods > 1 {
 78 | 		return fmt.Errorf("provide only one connection method: 'tns_alias', 'connection_string', or 'host'+'service_name'")
 79 | 	}
 80 | 
 81 | 	return nil
 82 | }
 83 | 
 84 | func (r Config) SourceConfigKind() string {
 85 | 	return SourceKind
 86 | }
 87 | 
 88 | func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
 89 | 	db, err := initOracleConnection(ctx, tracer, r)
 90 | 	if err != nil {
 91 | 		return nil, fmt.Errorf("unable to create Oracle connection: %w", err)
 92 | 	}
 93 | 
 94 | 	err = db.PingContext(ctx)
 95 | 	if err != nil {
 96 | 		return nil, fmt.Errorf("unable to connect to Oracle successfully: %w", err)
 97 | 	}
 98 | 
 99 | 	s := &Source{
100 | 		Name: r.Name,
101 | 		Kind: SourceKind,
102 | 		DB:   db,
103 | 	}
104 | 	return s, nil
105 | }
106 | 
107 | var _ sources.Source = &Source{}
108 | 
109 | type Source struct {
110 | 	Name string `yaml:"name"`
111 | 	Kind string `yaml:"kind"`
112 | 	DB   *sql.DB
113 | }
114 | 
115 | func (s *Source) SourceKind() string {
116 | 	return SourceKind
117 | }
118 | 
119 | func (s *Source) OracleDB() *sql.DB {
120 | 	return s.DB
121 | }
122 | 
123 | func initOracleConnection(ctx context.Context, tracer trace.Tracer, config Config) (*sql.DB, error) {
124 | 	//nolint:all // Reassigned ctx
125 | 	ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceKind, config.Name)
126 | 	defer span.End()
127 | 
128 | 	logger, err := util.LoggerFromContext(ctx)
129 | 	if err != nil {
130 | 		panic(err)
131 | 	}
132 | 
133 | 	// Set TNS_ADMIN environment variable if specified in config.
134 | 	if config.TnsAdmin != "" {
135 | 		originalTnsAdmin := os.Getenv("TNS_ADMIN")
136 | 		os.Setenv("TNS_ADMIN", config.TnsAdmin)
137 | 		logger.DebugContext(ctx, fmt.Sprintf("Setting TNS_ADMIN to: %s\n", config.TnsAdmin))
138 | 		// Restore original TNS_ADMIN after connection
139 | 		defer func() {
140 | 			if originalTnsAdmin != "" {
141 | 				os.Setenv("TNS_ADMIN", originalTnsAdmin)
142 | 			} else {
143 | 				os.Unsetenv("TNS_ADMIN")
144 | 			}
145 | 		}()
146 | 	}
147 | 
148 | 	var serverString string
149 | 	if config.TnsAlias != "" {
150 | 		// Use TNS alias
151 | 		serverString = strings.TrimSpace(config.TnsAlias)
152 | 	} else if config.ConnectionString != "" {
153 | 		// Use provided connection string directly (hostname[:port]/servicename format)
154 | 		serverString = strings.TrimSpace(config.ConnectionString)
155 | 	} else {
156 | 		// Build connection string from host and service_name
157 | 		if config.Port > 0 {
158 | 			serverString = fmt.Sprintf("%s:%d/%s", config.Host, config.Port, config.ServiceName)
159 | 		} else {
160 | 			serverString = fmt.Sprintf("%s/%s", config.Host, config.ServiceName)
161 | 		}
162 | 	}
163 | 
164 | 	connStr := fmt.Sprintf("oracle://%s:%s@%s",
165 | 		config.User, config.Password, serverString)
166 | 
167 | 	db, err := sql.Open("oracle", connStr)
168 | 	if err != nil {
169 | 		return nil, fmt.Errorf("unable to open Oracle connection: %w", err)
170 | 	}
171 | 
172 | 	return db, nil
173 | }
174 | 
```

--------------------------------------------------------------------------------
/internal/tools/mongodb/mongodbinsertone/mongodbinsertone.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 | package mongodbinsertone
 15 | 
 16 | import (
 17 | 	"context"
 18 | 	"errors"
 19 | 	"fmt"
 20 | 
 21 | 	"github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	mongosrc "github.com/googleapis/genai-toolbox/internal/sources/mongodb"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | 	"go.mongodb.org/mongo-driver/bson"
 26 | 	"go.mongodb.org/mongo-driver/mongo"
 27 | 	"go.mongodb.org/mongo-driver/mongo/options"
 28 | )
 29 | 
 30 | const kind string = "mongodb-insert-one"
 31 | 
 32 | const dataParamsKey = "data"
 33 | 
 34 | func init() {
 35 | 	if !tools.Register(kind, newConfig) {
 36 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 37 | 	}
 38 | }
 39 | 
 40 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 41 | 	actual := Config{Name: name}
 42 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 43 | 		return nil, err
 44 | 	}
 45 | 	return actual, nil
 46 | }
 47 | 
 48 | type Config struct {
 49 | 	Name         string   `yaml:"name" validate:"required"`
 50 | 	Kind         string   `yaml:"kind" validate:"required"`
 51 | 	Source       string   `yaml:"source" validate:"required"`
 52 | 	AuthRequired []string `yaml:"authRequired" validate:"required"`
 53 | 	Description  string   `yaml:"description" validate:"required"`
 54 | 	Database     string   `yaml:"database" validate:"required"`
 55 | 	Collection   string   `yaml:"collection" validate:"required"`
 56 | 	Canonical    bool     `yaml:"canonical" validate:"required"` //i want to force the user to choose
 57 | }
 58 | 
 59 | // validate interface
 60 | var _ tools.ToolConfig = Config{}
 61 | 
 62 | func (cfg Config) ToolConfigKind() string {
 63 | 	return kind
 64 | }
 65 | 
 66 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 67 | 	// verify source exists
 68 | 	rawS, ok := srcs[cfg.Source]
 69 | 	if !ok {
 70 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 71 | 	}
 72 | 
 73 | 	// verify the source is compatible
 74 | 	s, ok := rawS.(*mongosrc.Source)
 75 | 	if !ok {
 76 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `mongodb`", kind)
 77 | 	}
 78 | 
 79 | 	payloadParams := tools.NewStringParameterWithRequired(dataParamsKey, "the JSON payload to insert, should be a JSON object", true)
 80 | 
 81 | 	allParameters := tools.Parameters{payloadParams}
 82 | 
 83 | 	// Create Toolbox manifest
 84 | 	paramManifest := allParameters.Manifest()
 85 | 
 86 | 	if paramManifest == nil {
 87 | 		paramManifest = make([]tools.ParameterManifest, 0)
 88 | 	}
 89 | 
 90 | 	// Create MCP manifest
 91 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, allParameters)
 92 | 
 93 | 	// finish tool setup
 94 | 	return Tool{
 95 | 		Name:          cfg.Name,
 96 | 		Kind:          kind,
 97 | 		AuthRequired:  cfg.AuthRequired,
 98 | 		Collection:    cfg.Collection,
 99 | 		Canonical:     cfg.Canonical,
100 | 		PayloadParams: allParameters,
101 | 		database:      s.Client.Database(cfg.Database),
102 | 		manifest:      tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
103 | 		mcpManifest:   mcpManifest,
104 | 	}, nil
105 | }
106 | 
107 | // validate interface
108 | var _ tools.Tool = Tool{}
109 | 
110 | type Tool struct {
111 | 	Name          string           `yaml:"name"`
112 | 	Kind          string           `yaml:"kind"`
113 | 	AuthRequired  []string         `yaml:"authRequired"`
114 | 	Description   string           `yaml:"description"`
115 | 	Collection    string           `yaml:"collection"`
116 | 	Canonical     bool             `yaml:"canonical" validation:"required"`
117 | 	PayloadParams tools.Parameters `yaml:"payloadParams" validate:"required"`
118 | 
119 | 	database    *mongo.Database
120 | 	manifest    tools.Manifest
121 | 	mcpManifest tools.McpManifest
122 | }
123 | 
124 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
125 | 	if len(params) == 0 {
126 | 		return nil, errors.New("no input found")
127 | 	}
128 | 	// use the first, assume it's a string
129 | 	var jsonData, ok = params[0].Value.(string)
130 | 	if !ok {
131 | 		return nil, errors.New("no input found")
132 | 	}
133 | 
134 | 	var data any
135 | 	err := bson.UnmarshalExtJSON([]byte(jsonData), t.Canonical, &data)
136 | 	if err != nil {
137 | 		return nil, err
138 | 	}
139 | 
140 | 	res, err := t.database.Collection(t.Collection).InsertOne(ctx, data, options.InsertOne())
141 | 	if err != nil {
142 | 		return nil, err
143 | 	}
144 | 
145 | 	return res.InsertedID, nil
146 | }
147 | 
148 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
149 | 	return tools.ParseParams(t.PayloadParams, data, claims)
150 | }
151 | 
152 | func (t Tool) Manifest() tools.Manifest {
153 | 	return t.manifest
154 | }
155 | 
156 | func (t Tool) McpManifest() tools.McpManifest {
157 | 	return t.mcpManifest
158 | }
159 | 
160 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
161 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
162 | }
163 | 
164 | func (t Tool) RequiresClientAuthorization() bool {
165 | 	return false
166 | }
167 | 
```

--------------------------------------------------------------------------------
/internal/tools/postgres/postgresexecutesql/postgresexecutesql.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 postgresexecutesql
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	"github.com/googleapis/genai-toolbox/internal/sources/alloydbpg"
 24 | 	"github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
 25 | 	"github.com/googleapis/genai-toolbox/internal/sources/postgres"
 26 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 27 | 	"github.com/googleapis/genai-toolbox/internal/util"
 28 | 	"github.com/jackc/pgx/v5/pgxpool"
 29 | )
 30 | 
 31 | const kind string = "postgres-execute-sql"
 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 | 	PostgresPool() *pgxpool.Pool
 49 | }
 50 | 
 51 | // validate compatible sources are still compatible
 52 | var _ compatibleSource = &alloydbpg.Source{}
 53 | var _ compatibleSource = &cloudsqlpg.Source{}
 54 | var _ compatibleSource = &postgres.Source{}
 55 | 
 56 | var compatibleSources = [...]string{alloydbpg.SourceKind, cloudsqlpg.SourceKind, postgres.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" validate:"required"`
 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 | 	// verify source exists
 75 | 	rawS, ok := srcs[cfg.Source]
 76 | 	if !ok {
 77 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 78 | 	}
 79 | 
 80 | 	// verify the source is compatible
 81 | 	s, ok := rawS.(compatibleSource)
 82 | 	if !ok {
 83 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
 84 | 	}
 85 | 
 86 | 	sqlParameter := tools.NewStringParameter("sql", "The sql to execute.")
 87 | 	parameters := tools.Parameters{sqlParameter}
 88 | 
 89 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
 90 | 
 91 | 	// finish tool setup
 92 | 	t := Tool{
 93 | 		Name:         cfg.Name,
 94 | 		Kind:         kind,
 95 | 		Parameters:   parameters,
 96 | 		AuthRequired: cfg.AuthRequired,
 97 | 		Pool:         s.PostgresPool(),
 98 | 		manifest:     tools.Manifest{Description: cfg.Description, Parameters: parameters.Manifest(), AuthRequired: cfg.AuthRequired},
 99 | 		mcpManifest:  mcpManifest,
100 | 	}
101 | 	return t, nil
102 | }
103 | 
104 | // validate interface
105 | var _ tools.Tool = Tool{}
106 | 
107 | type Tool struct {
108 | 	Name         string           `yaml:"name"`
109 | 	Kind         string           `yaml:"kind"`
110 | 	AuthRequired []string         `yaml:"authRequired"`
111 | 	Parameters   tools.Parameters `yaml:"parameters"`
112 | 
113 | 	Pool        *pgxpool.Pool
114 | 	manifest    tools.Manifest
115 | 	mcpManifest tools.McpManifest
116 | }
117 | 
118 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
119 | 	paramsMap := params.AsMap()
120 | 	sql, ok := paramsMap["sql"].(string)
121 | 	if !ok {
122 | 		return nil, fmt.Errorf("unable to get cast %s", paramsMap["sql"])
123 | 	}
124 | 	// Log the query executed for debugging.
125 | 	logger, err := util.LoggerFromContext(ctx)
126 | 	if err != nil {
127 | 		return nil, fmt.Errorf("error getting logger: %s", err)
128 | 	}
129 | 	logger.DebugContext(ctx, "executing `%s` tool query: %s", kind, sql)
130 | 
131 | 	results, err := t.Pool.Query(ctx, sql)
132 | 	if err != nil {
133 | 		return nil, fmt.Errorf("unable to execute query: %w", err)
134 | 	}
135 | 
136 | 	fields := results.FieldDescriptions()
137 | 
138 | 	var out []any
139 | 	for results.Next() {
140 | 		v, err := results.Values()
141 | 		if err != nil {
142 | 			return nil, fmt.Errorf("unable to parse row: %w", err)
143 | 		}
144 | 		vMap := make(map[string]any)
145 | 		for i, f := range fields {
146 | 			vMap[f.Name] = v[i]
147 | 		}
148 | 		out = append(out, vMap)
149 | 	}
150 | 
151 | 	return out, nil
152 | }
153 | 
154 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
155 | 	return tools.ParseParams(t.Parameters, data, claims)
156 | }
157 | 
158 | func (t Tool) Manifest() tools.Manifest {
159 | 	return t.manifest
160 | }
161 | 
162 | func (t Tool) McpManifest() tools.McpManifest {
163 | 	return t.mcpManifest
164 | }
165 | 
166 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
167 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
168 | }
169 | 
170 | func (t Tool) RequiresClientAuthorization() bool {
171 | 	return false
172 | }
173 | 
```

--------------------------------------------------------------------------------
/internal/tools/cloudsql/cloudsqllistdatabases/cloudsqllistdatabases.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 cloudsqllistdatabases
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	"github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	cloudsqladminsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudsqladmin"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | )
 26 | 
 27 | const kind string = "cloud-sql-list-databases"
 28 | 
 29 | func init() {
 30 | 	if !tools.Register(kind, newConfig) {
 31 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 32 | 	}
 33 | }
 34 | 
 35 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 36 | 	actual := Config{Name: name}
 37 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 38 | 		return nil, err
 39 | 	}
 40 | 	return actual, nil
 41 | }
 42 | 
 43 | // Config defines the configuration for the list-databases tool.
 44 | type Config struct {
 45 | 	Name         string   `yaml:"name" validate:"required"`
 46 | 	Kind         string   `yaml:"kind" validate:"required"`
 47 | 	Source       string   `yaml:"source" validate:"required"`
 48 | 	Description  string   `yaml:"description"`
 49 | 	AuthRequired []string `yaml:"authRequired"`
 50 | }
 51 | 
 52 | // validate interface
 53 | var _ tools.ToolConfig = Config{}
 54 | 
 55 | // ToolConfigKind returns the kind of the tool.
 56 | func (cfg Config) ToolConfigKind() string {
 57 | 	return kind
 58 | }
 59 | 
 60 | // Initialize initializes the tool from the configuration.
 61 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 62 | 	rawS, ok := srcs[cfg.Source]
 63 | 	if !ok {
 64 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 65 | 	}
 66 | 	s, ok := rawS.(*cloudsqladminsrc.Source)
 67 | 	if !ok {
 68 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `cloud-sql-admin`", kind)
 69 | 	}
 70 | 
 71 | 	allParameters := tools.Parameters{
 72 | 		tools.NewStringParameter("project", "The project ID"),
 73 | 		tools.NewStringParameter("instance", "The instance ID"),
 74 | 	}
 75 | 	paramManifest := allParameters.Manifest()
 76 | 
 77 | 	description := cfg.Description
 78 | 	if description == "" {
 79 | 		description = "Lists all databases for a Cloud SQL instance."
 80 | 	}
 81 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, description, cfg.AuthRequired, allParameters)
 82 | 
 83 | 	return Tool{
 84 | 		Name:         cfg.Name,
 85 | 		Kind:         kind,
 86 | 		AuthRequired: cfg.AuthRequired,
 87 | 		Source:       s,
 88 | 		AllParams:    allParameters,
 89 | 		manifest:     tools.Manifest{Description: description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
 90 | 		mcpManifest:  mcpManifest,
 91 | 	}, nil
 92 | }
 93 | 
 94 | // Tool represents the list-databases tool.
 95 | type Tool struct {
 96 | 	Name         string   `yaml:"name"`
 97 | 	Kind         string   `yaml:"kind"`
 98 | 	Description  string   `yaml:"description"`
 99 | 	AuthRequired []string `yaml:"authRequired"`
100 | 
101 | 	AllParams   tools.Parameters `yaml:"allParams"`
102 | 	Source      *cloudsqladminsrc.Source
103 | 	manifest    tools.Manifest
104 | 	mcpManifest tools.McpManifest
105 | }
106 | 
107 | // Invoke executes the tool's logic.
108 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
109 | 	paramsMap := params.AsMap()
110 | 
111 | 	project, ok := paramsMap["project"].(string)
112 | 	if !ok {
113 | 		return nil, fmt.Errorf("missing 'project' parameter")
114 | 	}
115 | 	instance, ok := paramsMap["instance"].(string)
116 | 	if !ok {
117 | 		return nil, fmt.Errorf("missing 'instance' parameter")
118 | 	}
119 | 
120 | 	service, err := t.Source.GetService(ctx, string(accessToken))
121 | 	if err != nil {
122 | 		return nil, err
123 | 	}
124 | 
125 | 	resp, err := service.Databases.List(project, instance).Do()
126 | 	if err != nil {
127 | 		return nil, fmt.Errorf("error listing databases: %w", err)
128 | 	}
129 | 
130 | 	if resp.Items == nil {
131 | 		return []any{}, nil
132 | 	}
133 | 
134 | 	type databaseInfo struct {
135 | 		Name      string `json:"name"`
136 | 		Charset   string `json:"charset"`
137 | 		Collation string `json:"collation"`
138 | 	}
139 | 
140 | 	var databases []databaseInfo
141 | 	for _, item := range resp.Items {
142 | 		databases = append(databases, databaseInfo{
143 | 			Name:      item.Name,
144 | 			Charset:   item.Charset,
145 | 			Collation: item.Collation,
146 | 		})
147 | 	}
148 | 
149 | 	return databases, nil
150 | }
151 | 
152 | // ParseParams parses the parameters for the tool.
153 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
154 | 	return tools.ParseParams(t.AllParams, data, claims)
155 | }
156 | 
157 | // Manifest returns the tool's manifest.
158 | func (t Tool) Manifest() tools.Manifest {
159 | 	return t.manifest
160 | }
161 | 
162 | // McpManifest returns the tool's MCP manifest.
163 | func (t Tool) McpManifest() tools.McpManifest {
164 | 	return t.mcpManifest
165 | }
166 | 
167 | // Authorized checks if the tool is authorized.
168 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
169 | 	return true
170 | }
171 | 
172 | func (t Tool) RequiresClientAuthorization() bool {
173 | 	return t.Source.UseClientAuthorization()
174 | }
175 | 
```

--------------------------------------------------------------------------------
/internal/tools/cloudsql/cloudsqlcreatedatabase/cloudsqlcreatedatabase.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 cloudsqlcreatedatabase
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	"github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	"github.com/googleapis/genai-toolbox/internal/sources/cloudsqladmin"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | 	sqladmin "google.golang.org/api/sqladmin/v1"
 26 | )
 27 | 
 28 | const kind string = "cloud-sql-create-database"
 29 | 
 30 | func init() {
 31 | 	if !tools.Register(kind, newConfig) {
 32 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 33 | 	}
 34 | }
 35 | 
 36 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 37 | 	actual := Config{Name: name}
 38 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 39 | 		return nil, err
 40 | 	}
 41 | 	return actual, nil
 42 | }
 43 | 
 44 | // Config defines the configuration for the create-database tool.
 45 | type Config struct {
 46 | 	Name         string   `yaml:"name" validate:"required"`
 47 | 	Kind         string   `yaml:"kind" validate:"required"`
 48 | 	Source       string   `yaml:"source" validate:"required"`
 49 | 	Description  string   `yaml:"description"`
 50 | 	AuthRequired []string `yaml:"authRequired"`
 51 | }
 52 | 
 53 | // validate interface
 54 | var _ tools.ToolConfig = Config{}
 55 | 
 56 | // ToolConfigKind returns the kind of the tool.
 57 | func (cfg Config) ToolConfigKind() string {
 58 | 	return kind
 59 | }
 60 | 
 61 | // Initialize initializes the tool from the configuration.
 62 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 63 | 	rawS, ok := srcs[cfg.Source]
 64 | 	if !ok {
 65 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 66 | 	}
 67 | 	s, ok := rawS.(*cloudsqladmin.Source)
 68 | 	if !ok {
 69 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `cloud-sql-admin`", kind)
 70 | 	}
 71 | 
 72 | 	allParameters := tools.Parameters{
 73 | 		tools.NewStringParameter("project", "The project ID"),
 74 | 		tools.NewStringParameter("instance", "The ID of the instance where the database will be created."),
 75 | 		tools.NewStringParameter("name", "The name for the new database. Must be unique within the instance."),
 76 | 	}
 77 | 	paramManifest := allParameters.Manifest()
 78 | 
 79 | 	description := cfg.Description
 80 | 	if description == "" {
 81 | 		description = "Creates a new database in a Cloud SQL instance."
 82 | 	}
 83 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, description, cfg.AuthRequired, allParameters)
 84 | 
 85 | 	return Tool{
 86 | 		Name:         cfg.Name,
 87 | 		Kind:         kind,
 88 | 		AuthRequired: cfg.AuthRequired,
 89 | 		Source:       s,
 90 | 		AllParams:    allParameters,
 91 | 		manifest:     tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
 92 | 		mcpManifest:  mcpManifest,
 93 | 	}, nil
 94 | }
 95 | 
 96 | // Tool represents the create-database tool.
 97 | type Tool struct {
 98 | 	Name         string   `yaml:"name"`
 99 | 	Kind         string   `yaml:"kind"`
100 | 	Description  string   `yaml:"description"`
101 | 	AuthRequired []string `yaml:"authRequired"`
102 | 
103 | 	Source      *cloudsqladmin.Source
104 | 	AllParams   tools.Parameters `yaml:"allParams"`
105 | 	manifest    tools.Manifest
106 | 	mcpManifest tools.McpManifest
107 | }
108 | 
109 | // Invoke executes the tool's logic.
110 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
111 | 	paramsMap := params.AsMap()
112 | 
113 | 	project, ok := paramsMap["project"].(string)
114 | 	if !ok {
115 | 		return nil, fmt.Errorf("missing 'project' parameter")
116 | 	}
117 | 	instance, ok := paramsMap["instance"].(string)
118 | 	if !ok {
119 | 		return nil, fmt.Errorf("missing 'instance' parameter")
120 | 	}
121 | 	name, ok := paramsMap["name"].(string)
122 | 	if !ok {
123 | 		return nil, fmt.Errorf("missing 'name' parameter")
124 | 	}
125 | 
126 | 	database := sqladmin.Database{
127 | 		Name:     name,
128 | 		Project:  project,
129 | 		Instance: instance,
130 | 	}
131 | 
132 | 	service, err := t.Source.GetService(ctx, string(accessToken))
133 | 	if err != nil {
134 | 		return nil, err
135 | 	}
136 | 
137 | 	resp, err := service.Databases.Insert(project, instance, &database).Do()
138 | 	if err != nil {
139 | 		return nil, fmt.Errorf("error creating database: %w", err)
140 | 	}
141 | 
142 | 	return resp, nil
143 | }
144 | 
145 | // ParseParams parses the parameters for the tool.
146 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
147 | 	return tools.ParseParams(t.AllParams, data, claims)
148 | }
149 | 
150 | // Manifest returns the tool's manifest.
151 | func (t Tool) Manifest() tools.Manifest {
152 | 	return t.manifest
153 | }
154 | 
155 | // McpManifest returns the tool's MCP manifest.
156 | func (t Tool) McpManifest() tools.McpManifest {
157 | 	return t.mcpManifest
158 | }
159 | 
160 | // Authorized checks if the tool is authorized.
161 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
162 | 	return true
163 | }
164 | 
165 | func (t Tool) RequiresClientAuthorization() bool {
166 | 	return t.Source.UseClientAuthorization()
167 | }
168 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/mongodb/mongodb-update-many.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: "mongodb-update-many"
 3 | type: docs
 4 | weight: 1
 5 | description: > 
 6 |   A "mongodb-update-many" tool updates all documents in a MongoDB collection that match a filter.
 7 | aliases:
 8 | - /resources/tools/mongodb-update-many
 9 | ---
10 | 
11 | ## About
12 | 
13 | A `mongodb-update-many` tool updates **all** documents within a specified
14 | MongoDB collection that match a given filter. It locates the documents using a
15 | `filterPayload` and applies the modifications defined in an `updatePayload`.
16 | 
17 | The tool returns an array of three integers: `[ModifiedCount, UpsertedCount,
18 | MatchedCount]`.
19 | 
20 | This tool is compatible with the following source kind:
21 | 
22 | * [`mongodb`](../../sources/mongodb.md)
23 | 
24 | ---
25 | 
26 | ## Example
27 | 
28 | Here's an example configuration. This tool applies a discount to all items
29 | within a specific category and also marks them as being on sale.
30 | 
31 | ```yaml
32 | tools:
33 |   apply_category_discount:
34 |     kind: mongodb-update-many
35 |     source: my-mongo-source
36 |     description: Use this tool to apply a discount to all items in a given category.
37 |     database: products
38 |     collection: inventory
39 |     filterPayload: |
40 |         { "category": {{json .category_name}} }
41 |     filterParams:
42 |       - name: category_name
43 |         type: string
44 |         description: The category of items to update.
45 |     updatePayload: |
46 |         { 
47 |           "$mul": { "price": {{json .discount_multiplier}} },
48 |           "$set": { "on_sale": true }
49 |         }
50 |     updateParams:
51 |       - name: discount_multiplier
52 |         type: number
53 |         description: The multiplier to apply to the price (e.g., 0.8 for a 20% discount).
54 |     canonical: false
55 |     upsert: false
56 | ```
57 | 
58 | ## Reference
59 | 
60 | | **field**     | **type** | **required** | **description**                                                                                                                                                                                                             |
61 | |:--------------|:---------|:-------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
62 | | kind          | string   | true         | Must be `mongodb-update-many`.                                                                                                                                                                                              |
63 | | source        | string   | true         | The name of the `mongodb` source to use.                                                                                                                                                                                    |
64 | | description   | string   | true         | A description of the tool that is passed to the LLM.                                                                                                                                                                        |
65 | | database      | string   | true         | The name of the MongoDB database containing the collection.                                                                                                                                                                 |
66 | | collection    | string   | true         | The name of the MongoDB collection in which to update documents.                                                                                                                                                            |
67 | | filterPayload | string   | true         | The MongoDB query filter document to select the documents for updating. It's written as a Go template, using `{{json .param_name}}` to insert parameters.                                                                   |
68 | | filterParams  | list     | true         | A list of parameter objects that define the variables used in the `filterPayload`.                                                                                                                                          |
69 | | updatePayload | string   | true         | The MongoDB update document, It's written as a Go template, using `{{json .param_name}}` to insert parameters.                                                                                                              |
70 | | updateParams  | list     | true         | A list of parameter objects that define the variables used in the `updatePayload`.                                                                                                                                          |
71 | | canonical     | bool     | true         | Determines if the `filterPayload` and `updatePayload` strings are parsed using MongoDB's Canonical or Relaxed Extended JSON format. **Canonical** is stricter about type representation, while **Relaxed** is more lenient. |
72 | | upsert        | bool     | false        | If `true`, a new document is created if no document matches the `filterPayload`. Defaults to `false`.                                                                                                                       |
73 | 
```

--------------------------------------------------------------------------------
/internal/tools/cloudmonitoring/cloudmonitoring.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 cloudmonitoring
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"encoding/json"
 20 | 	"fmt"
 21 | 	"io"
 22 | 	"net/http"
 23 | 
 24 | 	"github.com/goccy/go-yaml"
 25 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 26 | 	cloudmonitoringsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudmonitoring"
 27 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 28 | )
 29 | 
 30 | const kind string = "cloud-monitoring-query-prometheus"
 31 | 
 32 | func init() {
 33 | 	if !tools.Register(kind, newConfig) {
 34 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 35 | 	}
 36 | }
 37 | 
 38 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 39 | 	actual := Config{Name: name}
 40 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 41 | 		return nil, err
 42 | 	}
 43 | 	return actual, nil
 44 | }
 45 | 
 46 | type Config struct {
 47 | 	Name         string   `yaml:"name" validate:"required"`
 48 | 	Kind         string   `yaml:"kind" validate:"required"`
 49 | 	Source       string   `yaml:"source" validate:"required"`
 50 | 	Description  string   `yaml:"description" validate:"required"`
 51 | 	AuthRequired []string `yaml:"authRequired"`
 52 | }
 53 | 
 54 | // validate interface
 55 | var _ tools.ToolConfig = Config{}
 56 | 
 57 | func (cfg Config) ToolConfigKind() string {
 58 | 	return kind
 59 | }
 60 | 
 61 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 62 | 	// verify source exists
 63 | 	rawS, ok := srcs[cfg.Source]
 64 | 	if !ok {
 65 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 66 | 	}
 67 | 
 68 | 	// verify the source is compatible
 69 | 	s, ok := rawS.(*cloudmonitoringsrc.Source)
 70 | 	if !ok {
 71 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `cloudmonitoring`", kind)
 72 | 	}
 73 | 
 74 | 	// Define the parameters internally instead of from the config file.
 75 | 	allParameters := tools.Parameters{
 76 | 		tools.NewStringParameterWithRequired("projectId", "The Id of the Google Cloud project.", true),
 77 | 		tools.NewStringParameterWithRequired("query", "The promql query to execute.", true),
 78 | 	}
 79 | 
 80 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, allParameters)
 81 | 
 82 | 	return Tool{
 83 | 		Name:        cfg.Name,
 84 | 		Kind:        kind,
 85 | 		Description: cfg.Description,
 86 | 		AllParams:   allParameters,
 87 | 		BaseURL:     s.BaseURL,
 88 | 		UserAgent:   s.UserAgent,
 89 | 		Client:      s.Client,
 90 | 		manifest:    tools.Manifest{Description: cfg.Description, Parameters: allParameters.Manifest()},
 91 | 		mcpManifest: mcpManifest,
 92 | 	}, nil
 93 | }
 94 | 
 95 | // validate interface
 96 | var _ tools.Tool = Tool{}
 97 | 
 98 | type Tool struct {
 99 | 	Name        string           `yaml:"name"`
100 | 	Kind        string           `yaml:"kind"`
101 | 	Description string           `yaml:"description"`
102 | 	AllParams   tools.Parameters `yaml:"allParams"`
103 | 	BaseURL     string           `yaml:"baseURL"`
104 | 	UserAgent   string
105 | 	Client      *http.Client
106 | 	manifest    tools.Manifest
107 | 	mcpManifest tools.McpManifest
108 | }
109 | 
110 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
111 | 	paramsMap := params.AsMap()
112 | 	projectID, ok := paramsMap["projectId"].(string)
113 | 	if !ok {
114 | 		return nil, fmt.Errorf("projectId parameter not found or not a string")
115 | 	}
116 | 	query, ok := paramsMap["query"].(string)
117 | 	if !ok {
118 | 		return nil, fmt.Errorf("query parameter not found or not a string")
119 | 	}
120 | 
121 | 	url := fmt.Sprintf("%s/v1/projects/%s/location/global/prometheus/api/v1/query", t.BaseURL, projectID)
122 | 
123 | 	req, err := http.NewRequest(http.MethodGet, url, nil)
124 | 	if err != nil {
125 | 		return nil, err
126 | 	}
127 | 
128 | 	q := req.URL.Query()
129 | 	q.Add("query", query)
130 | 	req.URL.RawQuery = q.Encode()
131 | 
132 | 	req.Header.Set("User-Agent", t.UserAgent)
133 | 
134 | 	resp, err := t.Client.Do(req)
135 | 	if err != nil {
136 | 		return nil, err
137 | 	}
138 | 	defer resp.Body.Close()
139 | 
140 | 	body, err := io.ReadAll(resp.Body)
141 | 	if err != nil {
142 | 		return nil, fmt.Errorf("failed to read response body: %w", err)
143 | 	}
144 | 
145 | 	if resp.StatusCode != http.StatusOK {
146 | 		return nil, fmt.Errorf("request failed: %s, body: %s", resp.Status, string(body))
147 | 	}
148 | 
149 | 	if len(body) == 0 {
150 | 		return nil, nil
151 | 	}
152 | 
153 | 	var result map[string]any
154 | 	if err := json.Unmarshal(body, &result); err != nil {
155 | 		return nil, fmt.Errorf("failed to unmarshal json: %w, body: %s", err, string(body))
156 | 	}
157 | 
158 | 	return result, nil
159 | }
160 | 
161 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
162 | 	return tools.ParseParams(t.AllParams, data, claims)
163 | }
164 | 
165 | func (t Tool) Manifest() tools.Manifest {
166 | 	return t.manifest
167 | }
168 | 
169 | func (t Tool) McpManifest() tools.McpManifest {
170 | 	return t.mcpManifest
171 | }
172 | 
173 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
174 | 	return true
175 | }
176 | 
177 | func (t Tool) RequiresClientAuthorization() bool {
178 | 	return false
179 | }
180 | 
```

--------------------------------------------------------------------------------
/internal/tools/alloydb/alloydbgetuser/alloydbgetuser.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 alloydbgetuser
 16 | 
 17 | import (
 18 | 	"context"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	alloydbadmin "github.com/googleapis/genai-toolbox/internal/sources/alloydbadmin"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | )
 26 | 
 27 | const kind string = "alloydb-get-user"
 28 | 
 29 | func init() {
 30 | 	if !tools.Register(kind, newConfig) {
 31 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 32 | 	}
 33 | }
 34 | 
 35 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 36 | 	actual := Config{Name: name}
 37 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 38 | 		return nil, err
 39 | 	}
 40 | 	return actual, nil
 41 | }
 42 | 
 43 | // Configuration for the get-user tool.
 44 | type Config struct {
 45 | 	Name         string   `yaml:"name" validate:"required"`
 46 | 	Kind         string   `yaml:"kind" validate:"required"`
 47 | 	Source       string   `yaml:"source" validate:"required"`
 48 | 	Description  string   `yaml:"description"`
 49 | 	AuthRequired []string `yaml:"authRequired"`
 50 | 	BaseURL      string   `yaml:"baseURL"`
 51 | }
 52 | 
 53 | // validate interface
 54 | var _ tools.ToolConfig = Config{}
 55 | 
 56 | // ToolConfigKind returns the kind of the tool.
 57 | func (cfg Config) ToolConfigKind() string {
 58 | 	return kind
 59 | }
 60 | 
 61 | // Initialize initializes the tool from the configuration.
 62 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 63 | 	rawS, ok := srcs[cfg.Source]
 64 | 	if !ok {
 65 | 		return nil, fmt.Errorf("source %q not found", cfg.Source)
 66 | 	}
 67 | 
 68 | 	s, ok := rawS.(*alloydbadmin.Source)
 69 | 	if !ok {
 70 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `%s`", kind, alloydbadmin.SourceKind)
 71 | 	}
 72 | 
 73 | 	allParameters := tools.Parameters{
 74 | 		tools.NewStringParameter("project", "The GCP project ID."),
 75 | 		tools.NewStringParameter("location", "The location of the cluster (e.g., 'us-central1')."),
 76 | 		tools.NewStringParameter("cluster", "The ID of the cluster."),
 77 | 		tools.NewStringParameter("user", "The ID of the user."),
 78 | 	}
 79 | 	paramManifest := allParameters.Manifest()
 80 | 
 81 | 	description := cfg.Description
 82 | 	if description == "" {
 83 | 		description = "Retrieves details about a specific AlloyDB user."
 84 | 	}
 85 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, description, cfg.AuthRequired, allParameters)
 86 | 
 87 | 	return Tool{
 88 | 		Name:        cfg.Name,
 89 | 		Kind:        kind,
 90 | 		Source:      s,
 91 | 		AllParams:   allParameters,
 92 | 		manifest:    tools.Manifest{Description: description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
 93 | 		mcpManifest: mcpManifest,
 94 | 	}, nil
 95 | }
 96 | 
 97 | // Tool represents the get-user tool.
 98 | type Tool struct {
 99 | 	Name string `yaml:"name"`
100 | 	Kind string `yaml:"kind"`
101 | 
102 | 	Source    *alloydbadmin.Source
103 | 	AllParams tools.Parameters
104 | 
105 | 	manifest    tools.Manifest
106 | 	mcpManifest tools.McpManifest
107 | }
108 | 
109 | // Invoke executes the tool's logic.
110 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
111 | 	paramsMap := params.AsMap()
112 | 
113 | 	project, ok := paramsMap["project"].(string)
114 | 	if !ok {
115 | 		return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
116 | 	}
117 | 	location, ok := paramsMap["location"].(string)
118 | 	if !ok {
119 | 		return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
120 | 	}
121 | 	cluster, ok := paramsMap["cluster"].(string)
122 | 	if !ok {
123 | 		return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
124 | 	}
125 | 	user, ok := paramsMap["user"].(string)
126 | 	if !ok {
127 | 		return nil, fmt.Errorf("invalid 'user' parameter; expected a string")
128 | 	}
129 | 
130 | 	service, err := t.Source.GetService(ctx, string(accessToken))
131 | 	if err != nil {
132 | 		return nil, err
133 | 	}
134 | 
135 | 	urlString := fmt.Sprintf("projects/%s/locations/%s/clusters/%s/users/%s", project, location, cluster, user)
136 | 
137 | 	resp, err := service.Projects.Locations.Clusters.Users.Get(urlString).Do()
138 | 	if err != nil {
139 | 		return nil, fmt.Errorf("error getting AlloyDB user: %w", err)
140 | 	}
141 | 
142 | 	return resp, nil
143 | }
144 | 
145 | // ParseParams parses the parameters for the tool.
146 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
147 | 	return tools.ParseParams(t.AllParams, data, claims)
148 | }
149 | 
150 | // Manifest returns the tool's manifest.
151 | func (t Tool) Manifest() tools.Manifest {
152 | 	return t.manifest
153 | }
154 | 
155 | // McpManifest returns the tool's MCP manifest.
156 | func (t Tool) McpManifest() tools.McpManifest {
157 | 	return t.mcpManifest
158 | }
159 | 
160 | // Authorized checks if the tool is authorized.
161 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
162 | 	return true
163 | }
164 | 
165 | func (t Tool) RequiresClientAuthorization() bool {
166 | 	return t.Source.UseClientAuthorization()
167 | }
168 | 
```

--------------------------------------------------------------------------------
/docs/en/resources/tools/mssql/mssql-sql.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: "mssql-sql"
  3 | type: docs
  4 | weight: 1
  5 | description: >
  6 |   A "mssql-sql" tool executes a pre-defined SQL statement against a SQL Server
  7 |   database.
  8 | aliases:
  9 | - /resources/tools/mssql-sql
 10 | ---
 11 | 
 12 | ## About
 13 | 
 14 | A `mssql-sql` tool executes a pre-defined SQL statement against a SQL Server
 15 | database. It's compatible with any of the following sources:
 16 | 
 17 | - [cloud-sql-mssql](../../sources/cloud-sql-mssql.md)
 18 | - [mssql](../../sources/mssql.md)
 19 | 
 20 | Toolbox supports the [prepare statement syntax][prepare-statement] of MS SQL
 21 | Server and expects parameters in the SQL query to be in the form of either
 22 | `@Name` or `@p1` to `@pN` (ordinal position).
 23 | 
 24 | ```go
 25 | db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob")
 26 | ```
 27 | 
 28 | [prepare-statement]: https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-prepare-transact-sql?view=sql-server-ver16
 29 | 
 30 | ## Example
 31 | 
 32 | > **Note:** This tool uses parameterized queries to prevent SQL injections.
 33 | > Query parameters can be used as substitutes for arbitrary expressions.
 34 | > Parameters cannot be used as substitutes for identifiers, column names, table
 35 | > names, or other parts of the query.
 36 | 
 37 | ```yaml
 38 | tools:
 39 |  search_flights_by_number:
 40 |     kind: mssql-sql
 41 |     source: my-instance
 42 |     statement: |
 43 |       SELECT * FROM flights
 44 |       WHERE airline = @airline
 45 |       AND flight_number = @flight_number
 46 |       LIMIT 10
 47 |     description: |
 48 |       Use this tool to get information for a specific flight.
 49 |       Takes an airline code and flight number and returns info on the flight.
 50 |       Do NOT use this tool with a flight id. Do NOT guess an airline code or flight number.
 51 |       A airline code is a code for an airline service consisting of two-character
 52 |       airline designator and followed by flight number, which is 1 to 4 digit number.
 53 |       For example, if given CY 0123, the airline is "CY", and flight_number is "123".
 54 |       Another example for this is DL 1234, the airline is "DL", and flight_number is "1234".
 55 |       If the tool returns more than one option choose the date closes to today.
 56 |       Example:
 57 |       {{
 58 |           "airline": "CY",
 59 |           "flight_number": "888",
 60 |       }}
 61 |       Example:
 62 |       {{
 63 |           "airline": "DL",
 64 |           "flight_number": "1234",
 65 |       }}
 66 |     parameters:
 67 |       - name: airline
 68 |         type: string
 69 |         description: Airline unique 2 letter identifier
 70 |       - name: flight_number
 71 |         type: string
 72 |         description: 1 to 4 digit number
 73 | ```
 74 | 
 75 | ### Example with Template Parameters
 76 | 
 77 | > **Note:** This tool allows direct modifications to the SQL statement,
 78 | > including identifiers, column names, and table names. **This makes it more
 79 | > vulnerable to SQL injections**. Using basic parameters only (see above) is
 80 | > recommended for performance and safety reasons. For more details, please check
 81 | > [templateParameters](..#template-parameters).
 82 | 
 83 | ```yaml
 84 | tools:
 85 |  list_table:
 86 |     kind: mssql-sql
 87 |     source: my-instance
 88 |     statement: |
 89 |       SELECT * FROM {{.tableName}};
 90 |     description: |
 91 |       Use this tool to list all information from a specific table.
 92 |       Example:
 93 |       {{
 94 |           "tableName": "flights",
 95 |       }}
 96 |     templateParameters:
 97 |       - name: tableName
 98 |         type: string
 99 |         description: Table to select from
100 | ```
101 | 
102 | ## Reference
103 | 
104 | | **field**          |                  **type**                        | **required** | **description**                                                                                                                            |
105 | |--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
106 | | kind               |                   string                         |     true     | Must be "mssql-sql".                                                                                                                       |
107 | | source             |                   string                         |     true     | Name of the source the T-SQL statement should execute on.                                                                                  |
108 | | description        |                   string                         |     true     | Description of the tool that is passed to the LLM.                                                                                         |
109 | | statement          |                   string                         |     true     | SQL statement to execute.                                                                                                                  |
110 | | parameters         | [parameters](../#specifying-parameters)       |    false     | List of [parameters](../#specifying-parameters) that will be inserted into the SQL statement.                                           |
111 | | templateParameters | [templateParameters](..#template-parameters) |    false     | List of [templateParameters](..#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
112 | 
```

--------------------------------------------------------------------------------
/internal/tools/looker/lookerrunlook/lookerrunlook.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 | package lookerrunlook
 15 | 
 16 | import (
 17 | 	"context"
 18 | 	"encoding/json"
 19 | 	"fmt"
 20 | 
 21 | 	yaml "github.com/goccy/go-yaml"
 22 | 	"github.com/googleapis/genai-toolbox/internal/sources"
 23 | 	lookersrc "github.com/googleapis/genai-toolbox/internal/sources/looker"
 24 | 	"github.com/googleapis/genai-toolbox/internal/tools"
 25 | 	"github.com/googleapis/genai-toolbox/internal/tools/looker/lookercommon"
 26 | 	"github.com/googleapis/genai-toolbox/internal/util"
 27 | 
 28 | 	"github.com/looker-open-source/sdk-codegen/go/rtl"
 29 | 	v4 "github.com/looker-open-source/sdk-codegen/go/sdk/v4"
 30 | )
 31 | 
 32 | const kind string = "looker-run-look"
 33 | 
 34 | func init() {
 35 | 	if !tools.Register(kind, newConfig) {
 36 | 		panic(fmt.Sprintf("tool kind %q already registered", kind))
 37 | 	}
 38 | }
 39 | 
 40 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
 41 | 	actual := Config{Name: name}
 42 | 	if err := decoder.DecodeContext(ctx, &actual); err != nil {
 43 | 		return nil, err
 44 | 	}
 45 | 	return actual, nil
 46 | }
 47 | 
 48 | type Config struct {
 49 | 	Name         string   `yaml:"name" validate:"required"`
 50 | 	Kind         string   `yaml:"kind" validate:"required"`
 51 | 	Source       string   `yaml:"source" validate:"required"`
 52 | 	Description  string   `yaml:"description" validate:"required"`
 53 | 	AuthRequired []string `yaml:"authRequired"`
 54 | }
 55 | 
 56 | // validate interface
 57 | var _ tools.ToolConfig = Config{}
 58 | 
 59 | func (cfg Config) ToolConfigKind() string {
 60 | 	return kind
 61 | }
 62 | 
 63 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
 64 | 	// verify source exists
 65 | 	rawS, ok := srcs[cfg.Source]
 66 | 	if !ok {
 67 | 		return nil, fmt.Errorf("no source named %q configured", cfg.Source)
 68 | 	}
 69 | 
 70 | 	// verify the source is compatible
 71 | 	s, ok := rawS.(*lookersrc.Source)
 72 | 	if !ok {
 73 | 		return nil, fmt.Errorf("invalid source for %q tool: source kind must be `looker`", kind)
 74 | 	}
 75 | 
 76 | 	lookidParameter := tools.NewStringParameter("look_id", "The id of the look to run.")
 77 | 	limitParameter := tools.NewIntParameterWithDefault("limit", 500, "The row limit. Default 500")
 78 | 
 79 | 	parameters := tools.Parameters{
 80 | 		lookidParameter,
 81 | 		limitParameter,
 82 | 	}
 83 | 
 84 | 	mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
 85 | 
 86 | 	// finish tool setup
 87 | 	return Tool{
 88 | 		Name:           cfg.Name,
 89 | 		Kind:           kind,
 90 | 		Parameters:     parameters,
 91 | 		AuthRequired:   cfg.AuthRequired,
 92 | 		UseClientOAuth: s.UseClientOAuth,
 93 | 		Client:         s.Client,
 94 | 		ApiSettings:    s.ApiSettings,
 95 | 		manifest: tools.Manifest{
 96 | 			Description:  cfg.Description,
 97 | 			Parameters:   parameters.Manifest(),
 98 | 			AuthRequired: cfg.AuthRequired,
 99 | 		},
100 | 		mcpManifest: mcpManifest,
101 | 	}, nil
102 | }
103 | 
104 | // validate interface
105 | var _ tools.Tool = Tool{}
106 | 
107 | type Tool struct {
108 | 	Name           string `yaml:"name"`
109 | 	Kind           string `yaml:"kind"`
110 | 	UseClientOAuth bool
111 | 	Client         *v4.LookerSDK
112 | 	ApiSettings    *rtl.ApiSettings
113 | 	AuthRequired   []string         `yaml:"authRequired"`
114 | 	Parameters     tools.Parameters `yaml:"parameters"`
115 | 	manifest       tools.Manifest
116 | 	mcpManifest    tools.McpManifest
117 | }
118 | 
119 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
120 | 	logger, err := util.LoggerFromContext(ctx)
121 | 	if err != nil {
122 | 		return nil, fmt.Errorf("unable to get logger from ctx: %s", err)
123 | 	}
124 | 	logger.DebugContext(ctx, "params = ", params)
125 | 	paramsMap := params.AsMap()
126 | 
127 | 	look_id := paramsMap["look_id"].(string)
128 | 	limit := int64(paramsMap["limit"].(int))
129 | 
130 | 	sdk, err := lookercommon.GetLookerSDK(t.UseClientOAuth, t.ApiSettings, t.Client, accessToken)
131 | 	if err != nil {
132 | 		return nil, fmt.Errorf("error getting sdk: %w", err)
133 | 	}
134 | 	req := v4.RequestRunLook{
135 | 		LookId:       look_id,
136 | 		ResultFormat: "json",
137 | 		Limit:        &limit,
138 | 	}
139 | 	resp, err := sdk.RunLook(req, t.ApiSettings)
140 | 	if err != nil {
141 | 		return nil, fmt.Errorf("error making run_look request: %s", err)
142 | 	}
143 | 	logger.DebugContext(ctx, "resp = ", resp)
144 | 
145 | 	var data []any
146 | 	e := json.Unmarshal([]byte(resp), &data)
147 | 	if e != nil {
148 | 		return nil, fmt.Errorf("error Unmarshaling run_look response: %s", e)
149 | 	}
150 | 
151 | 	logger.DebugContext(ctx, "data = ", data)
152 | 
153 | 	return data, nil
154 | }
155 | 
156 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
157 | 	return tools.ParseParams(t.Parameters, data, claims)
158 | }
159 | 
160 | func (t Tool) Manifest() tools.Manifest {
161 | 	return t.manifest
162 | }
163 | 
164 | func (t Tool) McpManifest() tools.McpManifest {
165 | 	return t.mcpManifest
166 | }
167 | 
168 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
169 | 	return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
170 | }
171 | 
172 | func (t Tool) RequiresClientAuthorization() bool {
173 | 	return t.UseClientOAuth
174 | }
175 | 
```
Page 13/45FirstPrevNextLast