This is page 25 of 48. Use http://codebase.md/googleapis/genai-toolbox?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .ci
│ ├── continuous.release.cloudbuild.yaml
│ ├── generate_release_table.sh
│ ├── integration.cloudbuild.yaml
│ ├── quickstart_test
│ │ ├── go.integration.cloudbuild.yaml
│ │ ├── js.integration.cloudbuild.yaml
│ │ ├── py.integration.cloudbuild.yaml
│ │ ├── run_go_tests.sh
│ │ ├── run_js_tests.sh
│ │ ├── run_py_tests.sh
│ │ └── setup_hotels_sample.sql
│ ├── test_with_coverage.sh
│ └── versioned.release.cloudbuild.yaml
├── .github
│ ├── auto-label.yaml
│ ├── blunderbuss.yml
│ ├── CODEOWNERS
│ ├── header-checker-lint.yml
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.yml
│ │ └── question.yml
│ ├── label-sync.yml
│ ├── labels.yaml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── release-please.yml
│ ├── renovate.json5
│ ├── sync-repo-settings.yaml
│ └── workflows
│ ├── cloud_build_failure_reporter.yml
│ ├── deploy_dev_docs.yaml
│ ├── deploy_previous_version_docs.yaml
│ ├── deploy_versioned_docs.yaml
│ ├── docs_deploy.yaml
│ ├── docs_preview_clean.yaml
│ ├── docs_preview_deploy.yaml
│ ├── lint.yaml
│ ├── schedule_reporter.yml
│ ├── sync-labels.yaml
│ └── tests.yaml
├── .gitignore
├── .gitmodules
├── .golangci.yaml
├── .hugo
│ ├── archetypes
│ │ └── default.md
│ ├── assets
│ │ ├── icons
│ │ │ └── logo.svg
│ │ └── scss
│ │ ├── _styles_project.scss
│ │ └── _variables_project.scss
│ ├── go.mod
│ ├── go.sum
│ ├── hugo.toml
│ ├── layouts
│ │ ├── _default
│ │ │ └── home.releases.releases
│ │ ├── index.llms-full.txt
│ │ ├── index.llms.txt
│ │ ├── partials
│ │ │ ├── hooks
│ │ │ │ └── head-end.html
│ │ │ ├── navbar-version-selector.html
│ │ │ ├── page-meta-links.html
│ │ │ └── td
│ │ │ └── render-heading.html
│ │ ├── robot.txt
│ │ └── shortcodes
│ │ ├── include.html
│ │ ├── ipynb.html
│ │ └── regionInclude.html
│ ├── package-lock.json
│ ├── package.json
│ └── static
│ ├── favicons
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ └── favicon.ico
│ └── js
│ └── w3.js
├── CHANGELOG.md
├── cmd
│ ├── options_test.go
│ ├── options.go
│ ├── root_test.go
│ ├── root.go
│ └── version.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DEVELOPER.md
├── Dockerfile
├── docs
│ └── en
│ ├── _index.md
│ ├── about
│ │ ├── _index.md
│ │ └── faq.md
│ ├── concepts
│ │ ├── _index.md
│ │ └── telemetry
│ │ ├── index.md
│ │ ├── telemetry_flow.png
│ │ └── telemetry_traces.png
│ ├── getting-started
│ │ ├── _index.md
│ │ ├── colab_quickstart.ipynb
│ │ ├── configure.md
│ │ ├── introduction
│ │ │ ├── _index.md
│ │ │ └── architecture.png
│ │ ├── local_quickstart_go.md
│ │ ├── local_quickstart_js.md
│ │ ├── local_quickstart.md
│ │ ├── mcp_quickstart
│ │ │ ├── _index.md
│ │ │ ├── inspector_tools.png
│ │ │ └── inspector.png
│ │ └── quickstart
│ │ ├── go
│ │ │ ├── genAI
│ │ │ │ ├── go.mod
│ │ │ │ ├── go.sum
│ │ │ │ └── quickstart.go
│ │ │ ├── genkit
│ │ │ │ ├── go.mod
│ │ │ │ ├── go.sum
│ │ │ │ └── quickstart.go
│ │ │ ├── langchain
│ │ │ │ ├── go.mod
│ │ │ │ ├── go.sum
│ │ │ │ └── quickstart.go
│ │ │ ├── openAI
│ │ │ │ ├── go.mod
│ │ │ │ ├── go.sum
│ │ │ │ └── quickstart.go
│ │ │ └── quickstart_test.go
│ │ ├── golden.txt
│ │ ├── js
│ │ │ ├── genAI
│ │ │ │ ├── package-lock.json
│ │ │ │ ├── package.json
│ │ │ │ └── quickstart.js
│ │ │ ├── genkit
│ │ │ │ ├── package-lock.json
│ │ │ │ ├── package.json
│ │ │ │ └── quickstart.js
│ │ │ ├── langchain
│ │ │ │ ├── package-lock.json
│ │ │ │ ├── package.json
│ │ │ │ └── quickstart.js
│ │ │ ├── llamaindex
│ │ │ │ ├── package-lock.json
│ │ │ │ ├── package.json
│ │ │ │ └── quickstart.js
│ │ │ └── quickstart.test.js
│ │ ├── python
│ │ │ ├── __init__.py
│ │ │ ├── adk
│ │ │ │ ├── quickstart.py
│ │ │ │ └── requirements.txt
│ │ │ ├── core
│ │ │ │ ├── quickstart.py
│ │ │ │ └── requirements.txt
│ │ │ ├── langchain
│ │ │ │ ├── quickstart.py
│ │ │ │ └── requirements.txt
│ │ │ ├── llamaindex
│ │ │ │ ├── quickstart.py
│ │ │ │ └── requirements.txt
│ │ │ └── quickstart_test.py
│ │ └── shared
│ │ ├── cloud_setup.md
│ │ ├── configure_toolbox.md
│ │ └── database_setup.md
│ ├── how-to
│ │ ├── _index.md
│ │ ├── connect_via_geminicli.md
│ │ ├── connect_via_mcp.md
│ │ ├── connect-ide
│ │ │ ├── _index.md
│ │ │ ├── alloydb_pg_admin_mcp.md
│ │ │ ├── alloydb_pg_mcp.md
│ │ │ ├── bigquery_mcp.md
│ │ │ ├── cloud_sql_mssql_admin_mcp.md
│ │ │ ├── cloud_sql_mssql_mcp.md
│ │ │ ├── cloud_sql_mysql_admin_mcp.md
│ │ │ ├── cloud_sql_mysql_mcp.md
│ │ │ ├── cloud_sql_pg_admin_mcp.md
│ │ │ ├── cloud_sql_pg_mcp.md
│ │ │ ├── firestore_mcp.md
│ │ │ ├── looker_mcp.md
│ │ │ ├── mssql_mcp.md
│ │ │ ├── mysql_mcp.md
│ │ │ ├── neo4j_mcp.md
│ │ │ ├── postgres_mcp.md
│ │ │ ├── spanner_mcp.md
│ │ │ └── sqlite_mcp.md
│ │ ├── deploy_docker.md
│ │ ├── deploy_gke.md
│ │ ├── deploy_toolbox.md
│ │ ├── export_telemetry.md
│ │ └── toolbox-ui
│ │ ├── edit-headers.gif
│ │ ├── edit-headers.png
│ │ ├── index.md
│ │ ├── optional-param-checked.png
│ │ ├── optional-param-unchecked.png
│ │ ├── run-tool.gif
│ │ ├── tools.png
│ │ └── toolsets.png
│ ├── reference
│ │ ├── _index.md
│ │ ├── cli.md
│ │ └── prebuilt-tools.md
│ ├── resources
│ │ ├── _index.md
│ │ ├── authServices
│ │ │ ├── _index.md
│ │ │ └── google.md
│ │ ├── sources
│ │ │ ├── _index.md
│ │ │ ├── alloydb-admin.md
│ │ │ ├── alloydb-pg.md
│ │ │ ├── bigquery.md
│ │ │ ├── bigtable.md
│ │ │ ├── cassandra.md
│ │ │ ├── clickhouse.md
│ │ │ ├── cloud-monitoring.md
│ │ │ ├── cloud-sql-admin.md
│ │ │ ├── cloud-sql-mssql.md
│ │ │ ├── cloud-sql-mysql.md
│ │ │ ├── cloud-sql-pg.md
│ │ │ ├── couchbase.md
│ │ │ ├── dataplex.md
│ │ │ ├── dgraph.md
│ │ │ ├── firebird.md
│ │ │ ├── firestore.md
│ │ │ ├── http.md
│ │ │ ├── looker.md
│ │ │ ├── mongodb.md
│ │ │ ├── mssql.md
│ │ │ ├── mysql.md
│ │ │ ├── neo4j.md
│ │ │ ├── oceanbase.md
│ │ │ ├── oracle.md
│ │ │ ├── postgres.md
│ │ │ ├── redis.md
│ │ │ ├── spanner.md
│ │ │ ├── sqlite.md
│ │ │ ├── tidb.md
│ │ │ ├── trino.md
│ │ │ ├── valkey.md
│ │ │ └── yugabytedb.md
│ │ └── tools
│ │ ├── _index.md
│ │ ├── alloydb
│ │ │ ├── _index.md
│ │ │ ├── alloydb-create-cluster.md
│ │ │ ├── alloydb-create-instance.md
│ │ │ ├── alloydb-create-user.md
│ │ │ ├── alloydb-get-cluster.md
│ │ │ ├── alloydb-get-instance.md
│ │ │ ├── alloydb-get-user.md
│ │ │ ├── alloydb-list-clusters.md
│ │ │ ├── alloydb-list-instances.md
│ │ │ ├── alloydb-list-users.md
│ │ │ └── alloydb-wait-for-operation.md
│ │ ├── alloydbainl
│ │ │ ├── _index.md
│ │ │ └── alloydb-ai-nl.md
│ │ ├── bigquery
│ │ │ ├── _index.md
│ │ │ ├── bigquery-analyze-contribution.md
│ │ │ ├── bigquery-conversational-analytics.md
│ │ │ ├── bigquery-execute-sql.md
│ │ │ ├── bigquery-forecast.md
│ │ │ ├── bigquery-get-dataset-info.md
│ │ │ ├── bigquery-get-table-info.md
│ │ │ ├── bigquery-list-dataset-ids.md
│ │ │ ├── bigquery-list-table-ids.md
│ │ │ ├── bigquery-search-catalog.md
│ │ │ └── bigquery-sql.md
│ │ ├── bigtable
│ │ │ ├── _index.md
│ │ │ └── bigtable-sql.md
│ │ ├── cassandra
│ │ │ ├── _index.md
│ │ │ └── cassandra-cql.md
│ │ ├── clickhouse
│ │ │ ├── _index.md
│ │ │ ├── clickhouse-execute-sql.md
│ │ │ ├── clickhouse-list-databases.md
│ │ │ ├── clickhouse-list-tables.md
│ │ │ └── clickhouse-sql.md
│ │ ├── cloudmonitoring
│ │ │ ├── _index.md
│ │ │ └── cloud-monitoring-query-prometheus.md
│ │ ├── cloudsql
│ │ │ ├── _index.md
│ │ │ ├── cloudsqlcreatedatabase.md
│ │ │ ├── cloudsqlcreateusers.md
│ │ │ ├── cloudsqlgetinstances.md
│ │ │ ├── cloudsqllistdatabases.md
│ │ │ ├── cloudsqllistinstances.md
│ │ │ ├── cloudsqlmssqlcreateinstance.md
│ │ │ ├── cloudsqlmysqlcreateinstance.md
│ │ │ ├── cloudsqlpgcreateinstances.md
│ │ │ └── cloudsqlwaitforoperation.md
│ │ ├── couchbase
│ │ │ ├── _index.md
│ │ │ └── couchbase-sql.md
│ │ ├── dataform
│ │ │ ├── _index.md
│ │ │ └── dataform-compile-local.md
│ │ ├── dataplex
│ │ │ ├── _index.md
│ │ │ ├── dataplex-lookup-entry.md
│ │ │ ├── dataplex-search-aspect-types.md
│ │ │ └── dataplex-search-entries.md
│ │ ├── dgraph
│ │ │ ├── _index.md
│ │ │ └── dgraph-dql.md
│ │ ├── firebird
│ │ │ ├── _index.md
│ │ │ ├── firebird-execute-sql.md
│ │ │ └── firebird-sql.md
│ │ ├── firestore
│ │ │ ├── _index.md
│ │ │ ├── firestore-add-documents.md
│ │ │ ├── firestore-delete-documents.md
│ │ │ ├── firestore-get-documents.md
│ │ │ ├── firestore-get-rules.md
│ │ │ ├── firestore-list-collections.md
│ │ │ ├── firestore-query-collection.md
│ │ │ ├── firestore-query.md
│ │ │ ├── firestore-update-document.md
│ │ │ └── firestore-validate-rules.md
│ │ ├── http
│ │ │ ├── _index.md
│ │ │ └── http.md
│ │ ├── looker
│ │ │ ├── _index.md
│ │ │ ├── looker-add-dashboard-element.md
│ │ │ ├── looker-conversational-analytics.md
│ │ │ ├── looker-create-project-file.md
│ │ │ ├── looker-delete-project-file.md
│ │ │ ├── looker-dev-mode.md
│ │ │ ├── looker-get-dashboards.md
│ │ │ ├── looker-get-dimensions.md
│ │ │ ├── looker-get-explores.md
│ │ │ ├── looker-get-filters.md
│ │ │ ├── looker-get-looks.md
│ │ │ ├── looker-get-measures.md
│ │ │ ├── looker-get-models.md
│ │ │ ├── looker-get-parameters.md
│ │ │ ├── looker-get-project-file.md
│ │ │ ├── looker-get-project-files.md
│ │ │ ├── looker-get-projects.md
│ │ │ ├── looker-health-analyze.md
│ │ │ ├── looker-health-pulse.md
│ │ │ ├── looker-health-vacuum.md
│ │ │ ├── looker-make-dashboard.md
│ │ │ ├── looker-make-look.md
│ │ │ ├── looker-query-sql.md
│ │ │ ├── looker-query-url.md
│ │ │ ├── looker-query.md
│ │ │ ├── looker-run-look.md
│ │ │ └── looker-update-project-file.md
│ │ ├── mongodb
│ │ │ ├── _index.md
│ │ │ ├── mongodb-aggregate.md
│ │ │ ├── mongodb-delete-many.md
│ │ │ ├── mongodb-delete-one.md
│ │ │ ├── mongodb-find-one.md
│ │ │ ├── mongodb-find.md
│ │ │ ├── mongodb-insert-many.md
│ │ │ ├── mongodb-insert-one.md
│ │ │ ├── mongodb-update-many.md
│ │ │ └── mongodb-update-one.md
│ │ ├── mssql
│ │ │ ├── _index.md
│ │ │ ├── mssql-execute-sql.md
│ │ │ ├── mssql-list-tables.md
│ │ │ └── mssql-sql.md
│ │ ├── mysql
│ │ │ ├── _index.md
│ │ │ ├── mysql-execute-sql.md
│ │ │ ├── mysql-list-active-queries.md
│ │ │ ├── mysql-list-table-fragmentation.md
│ │ │ ├── mysql-list-tables-missing-unique-indexes.md
│ │ │ ├── mysql-list-tables.md
│ │ │ └── mysql-sql.md
│ │ ├── neo4j
│ │ │ ├── _index.md
│ │ │ ├── neo4j-cypher.md
│ │ │ ├── neo4j-execute-cypher.md
│ │ │ └── neo4j-schema.md
│ │ ├── oceanbase
│ │ │ ├── _index.md
│ │ │ ├── oceanbase-execute-sql.md
│ │ │ └── oceanbase-sql.md
│ │ ├── oracle
│ │ │ ├── _index.md
│ │ │ ├── oracle-execute-sql.md
│ │ │ └── oracle-sql.md
│ │ ├── postgres
│ │ │ ├── _index.md
│ │ │ ├── postgres-execute-sql.md
│ │ │ ├── postgres-list-active-queries.md
│ │ │ ├── postgres-list-available-extensions.md
│ │ │ ├── postgres-list-installed-extensions.md
│ │ │ ├── postgres-list-tables.md
│ │ │ └── postgres-sql.md
│ │ ├── redis
│ │ │ ├── _index.md
│ │ │ └── redis.md
│ │ ├── 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
│ │ │ ├── lookercreateprojectfile
│ │ │ │ ├── lookercreateprojectfile_test.go
│ │ │ │ └── lookercreateprojectfile.go
│ │ │ ├── lookerdeleteprojectfile
│ │ │ │ ├── lookerdeleteprojectfile_test.go
│ │ │ │ └── lookerdeleteprojectfile.go
│ │ │ ├── lookerdevmode
│ │ │ │ ├── lookerdevmode_test.go
│ │ │ │ └── lookerdevmode.go
│ │ │ ├── lookergetdashboards
│ │ │ │ ├── lookergetdashboards_test.go
│ │ │ │ └── lookergetdashboards.go
│ │ │ ├── lookergetdimensions
│ │ │ │ ├── lookergetdimensions_test.go
│ │ │ │ └── lookergetdimensions.go
│ │ │ ├── lookergetexplores
│ │ │ │ ├── lookergetexplores_test.go
│ │ │ │ └── lookergetexplores.go
│ │ │ ├── lookergetfilters
│ │ │ │ ├── lookergetfilters_test.go
│ │ │ │ └── lookergetfilters.go
│ │ │ ├── lookergetlooks
│ │ │ │ ├── lookergetlooks_test.go
│ │ │ │ └── lookergetlooks.go
│ │ │ ├── lookergetmeasures
│ │ │ │ ├── lookergetmeasures_test.go
│ │ │ │ └── lookergetmeasures.go
│ │ │ ├── lookergetmodels
│ │ │ │ ├── lookergetmodels_test.go
│ │ │ │ └── lookergetmodels.go
│ │ │ ├── lookergetparameters
│ │ │ │ ├── lookergetparameters_test.go
│ │ │ │ └── lookergetparameters.go
│ │ │ ├── lookergetprojectfile
│ │ │ │ ├── lookergetprojectfile_test.go
│ │ │ │ └── lookergetprojectfile.go
│ │ │ ├── lookergetprojectfiles
│ │ │ │ ├── lookergetprojectfiles_test.go
│ │ │ │ └── lookergetprojectfiles.go
│ │ │ ├── lookergetprojects
│ │ │ │ ├── lookergetprojects_test.go
│ │ │ │ └── lookergetprojects.go
│ │ │ ├── lookerhealthanalyze
│ │ │ │ ├── lookerhealthanalyze_test.go
│ │ │ │ └── lookerhealthanalyze.go
│ │ │ ├── lookerhealthpulse
│ │ │ │ ├── lookerhealthpulse_test.go
│ │ │ │ └── lookerhealthpulse.go
│ │ │ ├── lookerhealthvacuum
│ │ │ │ ├── lookerhealthvacuum_test.go
│ │ │ │ └── lookerhealthvacuum.go
│ │ │ ├── lookermakedashboard
│ │ │ │ ├── lookermakedashboard_test.go
│ │ │ │ └── lookermakedashboard.go
│ │ │ ├── lookermakelook
│ │ │ │ ├── lookermakelook_test.go
│ │ │ │ └── lookermakelook.go
│ │ │ ├── lookerquery
│ │ │ │ ├── lookerquery_test.go
│ │ │ │ └── lookerquery.go
│ │ │ ├── lookerquerysql
│ │ │ │ ├── lookerquerysql_test.go
│ │ │ │ └── lookerquerysql.go
│ │ │ ├── lookerqueryurl
│ │ │ │ ├── lookerqueryurl_test.go
│ │ │ │ └── lookerqueryurl.go
│ │ │ ├── lookerrunlook
│ │ │ │ ├── lookerrunlook_test.go
│ │ │ │ └── lookerrunlook.go
│ │ │ └── lookerupdateprojectfile
│ │ │ ├── lookerupdateprojectfile_test.go
│ │ │ └── lookerupdateprojectfile.go
│ │ ├── mongodb
│ │ │ ├── mongodbaggregate
│ │ │ │ ├── mongodbaggregate_test.go
│ │ │ │ └── mongodbaggregate.go
│ │ │ ├── mongodbdeletemany
│ │ │ │ ├── mongodbdeletemany_test.go
│ │ │ │ └── mongodbdeletemany.go
│ │ │ ├── mongodbdeleteone
│ │ │ │ ├── mongodbdeleteone_test.go
│ │ │ │ └── mongodbdeleteone.go
│ │ │ ├── mongodbfind
│ │ │ │ ├── mongodbfind_test.go
│ │ │ │ └── mongodbfind.go
│ │ │ ├── mongodbfindone
│ │ │ │ ├── mongodbfindone_test.go
│ │ │ │ └── mongodbfindone.go
│ │ │ ├── mongodbinsertmany
│ │ │ │ ├── mongodbinsertmany_test.go
│ │ │ │ └── mongodbinsertmany.go
│ │ │ ├── mongodbinsertone
│ │ │ │ ├── mongodbinsertone_test.go
│ │ │ │ └── mongodbinsertone.go
│ │ │ ├── mongodbupdatemany
│ │ │ │ ├── mongodbupdatemany_test.go
│ │ │ │ └── mongodbupdatemany.go
│ │ │ └── mongodbupdateone
│ │ │ ├── mongodbupdateone_test.go
│ │ │ └── mongodbupdateone.go
│ │ ├── mssql
│ │ │ ├── mssqlexecutesql
│ │ │ │ ├── mssqlexecutesql_test.go
│ │ │ │ └── mssqlexecutesql.go
│ │ │ ├── mssqllisttables
│ │ │ │ ├── mssqllisttables_test.go
│ │ │ │ └── mssqllisttables.go
│ │ │ └── mssqlsql
│ │ │ ├── mssqlsql_test.go
│ │ │ └── mssqlsql.go
│ │ ├── mysql
│ │ │ ├── mysqlcommon
│ │ │ │ └── mysqlcommon.go
│ │ │ ├── mysqlexecutesql
│ │ │ │ ├── mysqlexecutesql_test.go
│ │ │ │ └── mysqlexecutesql.go
│ │ │ ├── mysqllistactivequeries
│ │ │ │ ├── mysqllistactivequeries_test.go
│ │ │ │ └── mysqllistactivequeries.go
│ │ │ ├── mysqllisttablefragmentation
│ │ │ │ ├── mysqllisttablefragmentation_test.go
│ │ │ │ └── mysqllisttablefragmentation.go
│ │ │ ├── mysqllisttables
│ │ │ │ ├── mysqllisttables_test.go
│ │ │ │ └── mysqllisttables.go
│ │ │ ├── mysqllisttablesmissinguniqueindexes
│ │ │ │ ├── mysqllisttablesmissinguniqueindexes_test.go
│ │ │ │ └── mysqllisttablesmissinguniqueindexes.go
│ │ │ └── mysqlsql
│ │ │ ├── mysqlsql_test.go
│ │ │ └── mysqlsql.go
│ │ ├── neo4j
│ │ │ ├── neo4jcypher
│ │ │ │ ├── neo4jcypher_test.go
│ │ │ │ └── neo4jcypher.go
│ │ │ ├── neo4jexecutecypher
│ │ │ │ ├── classifier
│ │ │ │ │ ├── classifier_test.go
│ │ │ │ │ └── classifier.go
│ │ │ │ ├── neo4jexecutecypher_test.go
│ │ │ │ └── neo4jexecutecypher.go
│ │ │ └── neo4jschema
│ │ │ ├── cache
│ │ │ │ ├── cache_test.go
│ │ │ │ └── cache.go
│ │ │ ├── helpers
│ │ │ │ ├── helpers_test.go
│ │ │ │ └── helpers.go
│ │ │ ├── neo4jschema_test.go
│ │ │ ├── neo4jschema.go
│ │ │ └── types
│ │ │ └── types.go
│ │ ├── oceanbase
│ │ │ ├── oceanbaseexecutesql
│ │ │ │ ├── oceanbaseexecutesql_test.go
│ │ │ │ └── oceanbaseexecutesql.go
│ │ │ └── oceanbasesql
│ │ │ ├── oceanbasesql_test.go
│ │ │ └── oceanbasesql.go
│ │ ├── oracle
│ │ │ ├── oracleexecutesql
│ │ │ │ └── oracleexecutesql.go
│ │ │ └── oraclesql
│ │ │ └── oraclesql.go
│ │ ├── parameters_test.go
│ │ ├── parameters.go
│ │ ├── postgres
│ │ │ ├── postgresexecutesql
│ │ │ │ ├── postgresexecutesql_test.go
│ │ │ │ └── postgresexecutesql.go
│ │ │ ├── postgreslistactivequeries
│ │ │ │ ├── postgreslistactivequeries_test.go
│ │ │ │ └── postgreslistactivequeries.go
│ │ │ ├── postgreslistavailableextensions
│ │ │ │ ├── postgreslistavailableextensions_test.go
│ │ │ │ └── postgreslistavailableextensions.go
│ │ │ ├── postgreslistinstalledextensions
│ │ │ │ ├── postgreslistinstalledextensions_test.go
│ │ │ │ └── postgreslistinstalledextensions.go
│ │ │ ├── postgreslisttables
│ │ │ │ ├── postgreslisttables_test.go
│ │ │ │ └── postgreslisttables.go
│ │ │ └── postgressql
│ │ │ ├── postgressql_test.go
│ │ │ └── postgressql.go
│ │ ├── redis
│ │ │ ├── redis_test.go
│ │ │ └── redis.go
│ │ ├── 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/mysql/mysqllistactivequeries/mysqllistactivequeries.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 mysqllistactivequeries
16 |
17 | import (
18 | "context"
19 | "database/sql"
20 | "fmt"
21 |
22 | yaml "github.com/goccy/go-yaml"
23 | "github.com/googleapis/genai-toolbox/internal/sources"
24 | "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmysql"
25 | "github.com/googleapis/genai-toolbox/internal/sources/mysql"
26 | "github.com/googleapis/genai-toolbox/internal/tools"
27 | "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqlcommon"
28 | "github.com/googleapis/genai-toolbox/internal/util"
29 | )
30 |
31 | const kind string = "mysql-list-active-queries"
32 |
33 | const listActiveQueriesStatementMySQL = `
34 | SELECT
35 | p.id AS processlist_id,
36 | substring(IFNULL(p.info, t.trx_query), 1, 100) AS query,
37 | t.trx_started AS trx_started,
38 | (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(t.trx_started)) AS trx_duration_seconds,
39 | (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(t.trx_wait_started)) AS trx_wait_duration_seconds,
40 | p.time AS query_time,
41 | t.trx_state AS trx_state,
42 | p.state AS process_state,
43 | IF(p.host IS NULL OR p.host = '', p.user, concat(p.user, '@', SUBSTRING_INDEX(p.host, ':', 1))) AS user,
44 | t.trx_rows_locked AS trx_rows_locked,
45 | t.trx_rows_modified AS trx_rows_modified,
46 | p.db AS db
47 | FROM
48 | information_schema.processlist p
49 | LEFT OUTER JOIN
50 | information_schema.innodb_trx t
51 | ON p.id = t.trx_mysql_thread_id
52 | WHERE
53 | (? IS NULL OR p.time >= ?)
54 | AND p.id != CONNECTION_ID()
55 | AND Command NOT IN ('Binlog Dump', 'Binlog Dump GTID', 'Connect', 'Connect Out', 'Register Slave')
56 | AND User NOT IN ('system user', 'event_scheduler')
57 | AND (t.trx_id is NOT NULL OR command != 'Sleep')
58 | ORDER BY
59 | t.trx_started
60 | LIMIT ?;
61 | `
62 |
63 | const listActiveQueriesStatementCloudSQLMySQL = `
64 | SELECT
65 | p.id AS processlist_id,
66 | substring(IFNULL(p.info, t.trx_query), 1, 100) AS query,
67 | t.trx_started AS trx_started,
68 | (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(t.trx_started)) AS trx_duration_seconds,
69 | (UNIX_TIMESTAMP(UTC_TIMESTAMP()) - UNIX_TIMESTAMP(t.trx_wait_started)) AS trx_wait_duration_seconds,
70 | p.time AS query_time,
71 | t.trx_state AS trx_state,
72 | p.state AS process_state,
73 | IF(p.host IS NULL OR p.host = '', p.user, concat(p.user, '@', SUBSTRING_INDEX(p.host, ':', 1))) AS user,
74 | t.trx_rows_locked AS trx_rows_locked,
75 | t.trx_rows_modified AS trx_rows_modified,
76 | p.db AS db
77 | FROM
78 | information_schema.processlist p
79 | LEFT OUTER JOIN
80 | information_schema.innodb_trx t
81 | ON p.id = t.trx_mysql_thread_id
82 | WHERE
83 | (? IS NULL OR p.time >= ?)
84 | AND p.id != CONNECTION_ID()
85 | AND SUBSTRING_INDEX(IFNULL(p.host,''), ':', 1) NOT IN ('localhost', '127.0.0.1')
86 | AND IFNULL(p.host,'') NOT LIKE '::1%'
87 | AND Command NOT IN ('Binlog Dump', 'Binlog Dump GTID', 'Connect', 'Connect Out', 'Register Slave')
88 | AND User NOT IN ('system user', 'event_scheduler')
89 | AND (t.trx_id is NOT NULL OR command != 'sleep')
90 | ORDER BY
91 | t.trx_started
92 | LIMIT ?;
93 | `
94 |
95 | func init() {
96 | if !tools.Register(kind, newConfig) {
97 | panic(fmt.Sprintf("tool kind %q already registered", kind))
98 | }
99 | }
100 |
101 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
102 | actual := Config{Name: name}
103 | if err := decoder.DecodeContext(ctx, &actual); err != nil {
104 | return nil, err
105 | }
106 | return actual, nil
107 | }
108 |
109 | type compatibleSource interface {
110 | MySQLPool() *sql.DB
111 | }
112 |
113 | // validate compatible sources are still compatible
114 | var _ compatibleSource = &mysql.Source{}
115 | var _ compatibleSource = &cloudsqlmysql.Source{}
116 |
117 | var compatibleSources = [...]string{mysql.SourceKind, cloudsqlmysql.SourceKind}
118 |
119 | type Config struct {
120 | Name string `yaml:"name" validate:"required"`
121 | Kind string `yaml:"kind" validate:"required"`
122 | Source string `yaml:"source" validate:"required"`
123 | Description string `yaml:"description" validate:"required"`
124 | AuthRequired []string `yaml:"authRequired"`
125 | }
126 |
127 | // validate interface
128 | var _ tools.ToolConfig = Config{}
129 |
130 | func (cfg Config) ToolConfigKind() string {
131 | return kind
132 | }
133 |
134 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
135 | // verify source exists
136 | rawS, ok := srcs[cfg.Source]
137 | if !ok {
138 | return nil, fmt.Errorf("no source named %q configured", cfg.Source)
139 | }
140 |
141 | // verify the source is compatible
142 | s, ok := rawS.(compatibleSource)
143 | if !ok {
144 | return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
145 | }
146 |
147 | allParameters := tools.Parameters{
148 | tools.NewIntParameterWithDefault("min_duration_secs", 0, "Optional: Only show queries running for at least this long in seconds"),
149 | tools.NewIntParameterWithDefault("limit", 100, "Optional: The maximum number of rows to return."),
150 | }
151 | mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, allParameters)
152 |
153 | var statement string
154 | sourceKind := rawS.SourceKind()
155 |
156 | switch sourceKind {
157 | case mysql.SourceKind:
158 | statement = listActiveQueriesStatementMySQL
159 | case cloudsqlmysql.SourceKind:
160 | statement = listActiveQueriesStatementCloudSQLMySQL
161 | default:
162 | return nil, fmt.Errorf("unsupported source kind kind: %q", sourceKind)
163 | }
164 | // finish tool setup
165 | t := Tool{
166 | Name: cfg.Name,
167 | Kind: kind,
168 | AuthRequired: cfg.AuthRequired,
169 | Pool: s.MySQLPool(),
170 | allParams: allParameters,
171 | manifest: tools.Manifest{Description: cfg.Description, Parameters: allParameters.Manifest(), AuthRequired: cfg.AuthRequired},
172 | mcpManifest: mcpManifest,
173 | statement: statement,
174 | }
175 | return t, nil
176 | }
177 |
178 | // validate interface
179 | var _ tools.Tool = Tool{}
180 |
181 | type Tool struct {
182 | Name string `yaml:"name"`
183 | Kind string `yaml:"kind"`
184 | AuthRequired []string `yaml:"authRequired"`
185 | allParams tools.Parameters `yaml:"parameters"`
186 | Pool *sql.DB
187 | manifest tools.Manifest
188 | mcpManifest tools.McpManifest
189 | statement string
190 | }
191 |
192 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
193 | paramsMap := params.AsMap()
194 |
195 | duration, ok := paramsMap["min_duration_secs"].(int)
196 | if !ok {
197 | return nil, fmt.Errorf("invalid 'min_duration_secs' parameter; expected an integer")
198 | }
199 | limit, ok := paramsMap["limit"].(int)
200 | if !ok {
201 | return nil, fmt.Errorf("invalid 'limit' parameter; expected an integer")
202 | }
203 |
204 | // Log the query executed for debugging.
205 | logger, err := util.LoggerFromContext(ctx)
206 | if err != nil {
207 | return nil, fmt.Errorf("error getting logger: %s", err)
208 | }
209 | logger.DebugContext(ctx, "executing `%s` tool query: %s", kind, t.statement)
210 |
211 | results, err := t.Pool.QueryContext(ctx, t.statement, duration, duration, limit)
212 | if err != nil {
213 | return nil, fmt.Errorf("unable to execute query: %w", err)
214 | }
215 | defer results.Close()
216 |
217 | cols, err := results.Columns()
218 | if err != nil {
219 | return nil, fmt.Errorf("unable to retrieve rows column name: %w", err)
220 | }
221 |
222 | // create an array of values for each column, which can be re-used to scan each row
223 | rawValues := make([]any, len(cols))
224 | values := make([]any, len(cols))
225 | for i := range rawValues {
226 | values[i] = &rawValues[i]
227 | }
228 |
229 | colTypes, err := results.ColumnTypes()
230 | if err != nil {
231 | return nil, fmt.Errorf("unable to get column types: %w", err)
232 | }
233 |
234 | var out []any
235 | for results.Next() {
236 | err := results.Scan(values...)
237 | if err != nil {
238 | return nil, fmt.Errorf("unable to parse row: %w", err)
239 | }
240 | vMap := make(map[string]any)
241 | for i, name := range cols {
242 | val := rawValues[i]
243 | if val == nil {
244 | vMap[name] = nil
245 | continue
246 | }
247 |
248 | vMap[name], err = mysqlcommon.ConvertToType(colTypes[i], val)
249 | if err != nil {
250 | return nil, fmt.Errorf("errors encountered when converting values: %w", err)
251 | }
252 | }
253 | out = append(out, vMap)
254 | }
255 |
256 | if err := results.Err(); err != nil {
257 | return nil, fmt.Errorf("errors encountered during row iteration: %w", err)
258 | }
259 |
260 | return out, nil
261 | }
262 |
263 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
264 | return tools.ParseParams(t.allParams, data, claims)
265 | }
266 |
267 | func (t Tool) Manifest() tools.Manifest {
268 | return t.manifest
269 | }
270 |
271 | func (t Tool) McpManifest() tools.McpManifest {
272 | return t.mcpManifest
273 | }
274 |
275 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
276 | return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
277 | }
278 |
279 | func (t Tool) RequiresClientAuthorization() bool {
280 | return false
281 | }
282 |
```
--------------------------------------------------------------------------------
/internal/tools/firestore/firestorevalidaterules/firestorevalidaterules.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 firestorevalidaterules
16 |
17 | import (
18 | "context"
19 | "fmt"
20 | "strings"
21 |
22 | yaml "github.com/goccy/go-yaml"
23 | "github.com/googleapis/genai-toolbox/internal/sources"
24 | firestoreds "github.com/googleapis/genai-toolbox/internal/sources/firestore"
25 | "github.com/googleapis/genai-toolbox/internal/tools"
26 | "google.golang.org/api/firebaserules/v1"
27 | )
28 |
29 | const kind string = "firestore-validate-rules"
30 |
31 | // Parameter keys
32 | const (
33 | sourceKey = "source"
34 | )
35 |
36 | func init() {
37 | if !tools.Register(kind, newConfig) {
38 | panic(fmt.Sprintf("tool kind %q already registered", kind))
39 | }
40 | }
41 |
42 | func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (tools.ToolConfig, error) {
43 | actual := Config{Name: name}
44 | if err := decoder.DecodeContext(ctx, &actual); err != nil {
45 | return nil, err
46 | }
47 | return actual, nil
48 | }
49 |
50 | type compatibleSource interface {
51 | FirebaseRulesClient() *firebaserules.Service
52 | GetProjectId() string
53 | }
54 |
55 | // validate compatible sources are still compatible
56 | var _ compatibleSource = &firestoreds.Source{}
57 |
58 | var compatibleSources = [...]string{firestoreds.SourceKind}
59 |
60 | type Config struct {
61 | Name string `yaml:"name" validate:"required"`
62 | Kind string `yaml:"kind" validate:"required"`
63 | Source string `yaml:"source" validate:"required"`
64 | Description string `yaml:"description" validate:"required"`
65 | AuthRequired []string `yaml:"authRequired"`
66 | }
67 |
68 | // validate interface
69 | var _ tools.ToolConfig = Config{}
70 |
71 | func (cfg Config) ToolConfigKind() string {
72 | return kind
73 | }
74 |
75 | func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
76 | // verify source exists
77 | rawS, ok := srcs[cfg.Source]
78 | if !ok {
79 | return nil, fmt.Errorf("no source named %q configured", cfg.Source)
80 | }
81 |
82 | // verify the source is compatible
83 | s, ok := rawS.(compatibleSource)
84 | if !ok {
85 | return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
86 | }
87 |
88 | // Create parameters
89 | parameters := createParameters()
90 | mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, parameters)
91 |
92 | // finish tool setup
93 | t := Tool{
94 | Name: cfg.Name,
95 | Kind: kind,
96 | Parameters: parameters,
97 | AuthRequired: cfg.AuthRequired,
98 | RulesClient: s.FirebaseRulesClient(),
99 | ProjectId: s.GetProjectId(),
100 | manifest: tools.Manifest{Description: cfg.Description, Parameters: parameters.Manifest(), AuthRequired: cfg.AuthRequired},
101 | mcpManifest: mcpManifest,
102 | }
103 | return t, nil
104 | }
105 |
106 | // createParameters creates the parameter definitions for the tool
107 | func createParameters() tools.Parameters {
108 | sourceParameter := tools.NewStringParameter(
109 | sourceKey,
110 | "The Firestore Rules source code to validate",
111 | )
112 |
113 | return tools.Parameters{sourceParameter}
114 | }
115 |
116 | // validate interface
117 | var _ tools.Tool = Tool{}
118 |
119 | type Tool struct {
120 | Name string `yaml:"name"`
121 | Kind string `yaml:"kind"`
122 | AuthRequired []string `yaml:"authRequired"`
123 | Parameters tools.Parameters `yaml:"parameters"`
124 |
125 | RulesClient *firebaserules.Service
126 | ProjectId string
127 | manifest tools.Manifest
128 | mcpManifest tools.McpManifest
129 | }
130 |
131 | // Issue represents a validation issue in the rules
132 | type Issue struct {
133 | SourcePosition SourcePosition `json:"sourcePosition"`
134 | Description string `json:"description"`
135 | Severity string `json:"severity"`
136 | }
137 |
138 | // SourcePosition represents the location of an issue in the source
139 | type SourcePosition struct {
140 | FileName string `json:"fileName,omitempty"`
141 | Line int64 `json:"line"` // 1-based
142 | Column int64 `json:"column"` // 1-based
143 | CurrentOffset int64 `json:"currentOffset"` // 0-based, inclusive start
144 | EndOffset int64 `json:"endOffset"` // 0-based, exclusive end
145 | }
146 |
147 | // ValidationResult represents the result of rules validation
148 | type ValidationResult struct {
149 | Valid bool `json:"valid"`
150 | IssueCount int `json:"issueCount"`
151 | FormattedIssues string `json:"formattedIssues,omitempty"`
152 | RawIssues []Issue `json:"rawIssues,omitempty"`
153 | }
154 |
155 | func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
156 | mapParams := params.AsMap()
157 |
158 | // Get source parameter
159 | source, ok := mapParams[sourceKey].(string)
160 | if !ok || source == "" {
161 | return nil, fmt.Errorf("invalid or missing '%s' parameter", sourceKey)
162 | }
163 |
164 | // Create test request
165 | testRequest := &firebaserules.TestRulesetRequest{
166 | Source: &firebaserules.Source{
167 | Files: []*firebaserules.File{
168 | {
169 | Name: "firestore.rules",
170 | Content: source,
171 | },
172 | },
173 | },
174 | // We don't need test cases for validation only
175 | TestSuite: &firebaserules.TestSuite{
176 | TestCases: []*firebaserules.TestCase{},
177 | },
178 | }
179 |
180 | // Call the test API
181 | projectName := fmt.Sprintf("projects/%s", t.ProjectId)
182 | response, err := t.RulesClient.Projects.Test(projectName, testRequest).Context(ctx).Do()
183 | if err != nil {
184 | return nil, fmt.Errorf("failed to validate rules: %w", err)
185 | }
186 |
187 | // Process the response
188 | result := t.processValidationResponse(response, source)
189 |
190 | return result, nil
191 | }
192 |
193 | func (t Tool) processValidationResponse(response *firebaserules.TestRulesetResponse, source string) ValidationResult {
194 | if len(response.Issues) == 0 {
195 | return ValidationResult{
196 | Valid: true,
197 | IssueCount: 0,
198 | FormattedIssues: "✓ No errors detected. Rules are valid.",
199 | }
200 | }
201 |
202 | // Convert issues to our format
203 | issues := make([]Issue, len(response.Issues))
204 | for i, issue := range response.Issues {
205 | issues[i] = Issue{
206 | Description: issue.Description,
207 | Severity: issue.Severity,
208 | SourcePosition: SourcePosition{
209 | FileName: issue.SourcePosition.FileName,
210 | Line: issue.SourcePosition.Line,
211 | Column: issue.SourcePosition.Column,
212 | CurrentOffset: issue.SourcePosition.CurrentOffset,
213 | EndOffset: issue.SourcePosition.EndOffset,
214 | },
215 | }
216 | }
217 |
218 | // Format issues
219 | formattedIssues := t.formatRulesetIssues(issues, source)
220 |
221 | return ValidationResult{
222 | Valid: false,
223 | IssueCount: len(issues),
224 | FormattedIssues: formattedIssues,
225 | RawIssues: issues,
226 | }
227 | }
228 |
229 | // formatRulesetIssues formats validation issues into a human-readable string with code snippets
230 | func (t Tool) formatRulesetIssues(issues []Issue, rulesSource string) string {
231 | sourceLines := strings.Split(rulesSource, "\n")
232 | var formattedOutput []string
233 |
234 | formattedOutput = append(formattedOutput, fmt.Sprintf("Found %d issue(s) in rules source:\n", len(issues)))
235 |
236 | for _, issue := range issues {
237 | issueString := fmt.Sprintf("%s: %s [Ln %d, Col %d]",
238 | issue.Severity,
239 | issue.Description,
240 | issue.SourcePosition.Line,
241 | issue.SourcePosition.Column)
242 |
243 | if issue.SourcePosition.Line > 0 {
244 | lineIndex := int(issue.SourcePosition.Line - 1) // 0-based index
245 | if lineIndex >= 0 && lineIndex < len(sourceLines) {
246 | errorLine := sourceLines[lineIndex]
247 | issueString += fmt.Sprintf("\n```\n%s", errorLine)
248 |
249 | // Add carets if we have column and offset information
250 | if issue.SourcePosition.Column > 0 &&
251 | issue.SourcePosition.CurrentOffset >= 0 &&
252 | issue.SourcePosition.EndOffset > issue.SourcePosition.CurrentOffset {
253 |
254 | startColumn := int(issue.SourcePosition.Column - 1) // 0-based
255 | errorTokenLength := int(issue.SourcePosition.EndOffset - issue.SourcePosition.CurrentOffset)
256 |
257 | if startColumn >= 0 && errorTokenLength > 0 && startColumn <= len(errorLine) {
258 | padding := strings.Repeat(" ", startColumn)
259 | carets := strings.Repeat("^", errorTokenLength)
260 | issueString += fmt.Sprintf("\n%s%s", padding, carets)
261 | }
262 | }
263 | issueString += "\n```"
264 | }
265 | }
266 |
267 | formattedOutput = append(formattedOutput, issueString)
268 | }
269 |
270 | return strings.Join(formattedOutput, "\n\n")
271 | }
272 |
273 | func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
274 | return tools.ParseParams(t.Parameters, data, claims)
275 | }
276 |
277 | func (t Tool) Manifest() tools.Manifest {
278 | return t.manifest
279 | }
280 |
281 | func (t Tool) McpManifest() tools.McpManifest {
282 | return t.mcpManifest
283 | }
284 |
285 | func (t Tool) Authorized(verifiedAuthServices []string) bool {
286 | return tools.IsAuthorized(t.AuthRequired, verifiedAuthServices)
287 | }
288 |
289 | func (t Tool) RequiresClientAuthorization() bool {
290 | return false
291 | }
292 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/cloud_sql_mysql_admin_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: "Cloud SQL for MySQL Admin using MCP"
3 | type: docs
4 | weight: 4
5 | description: >
6 | Create and manage Cloud SQL for MySQL (Admin) using Toolbox.
7 | ---
8 |
9 | This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your
10 | developer assistant tools to create and manage Cloud SQL for MySQL instance,
11 | database and users:
12 |
13 | * [Cursor][cursor]
14 | * [Windsurf][windsurf] (Codium)
15 | * [Visual Studio Code][vscode] (Copilot)
16 | * [Cline][cline] (VS Code extension)
17 | * [Claude desktop][claudedesktop]
18 | * [Claude code][claudecode]
19 | * [Gemini CLI][geminicli]
20 | * [Gemini Code Assist][geminicodeassist]
21 |
22 | [toolbox]: https://github.com/googleapis/genai-toolbox
23 | [cursor]: #configure-your-mcp-client
24 | [windsurf]: #configure-your-mcp-client
25 | [vscode]: #configure-your-mcp-client
26 | [cline]: #configure-your-mcp-client
27 | [claudedesktop]: #configure-your-mcp-client
28 | [claudecode]: #configure-your-mcp-client
29 | [geminicli]: #configure-your-mcp-client
30 | [geminicodeassist]: #configure-your-mcp-client
31 |
32 | ## Before you begin
33 |
34 | 1. In the Google Cloud console, on the [project selector
35 | page](https://console.cloud.google.com/projectselector2/home/dashboard),
36 | select or create a Google Cloud project.
37 |
38 | 1. [Make sure that billing is enabled for your Google Cloud
39 | project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
40 |
41 | 1. Grant the necessary IAM roles to the user that will be running the MCP
42 | server. The tools available will depend on the roles granted:
43 | * `roles/cloudsql.viewer`: Provides read-only access to resources.
44 | * `get_instance`
45 | * `list_instances`
46 | * `list_databases`
47 | * `wait_for_operation`
48 | * `roles/cloudsql.editor`: Provides permissions to manage existing resources.
49 | * All `viewer` tools
50 | * `create_database`
51 | * `roles/cloudsql.admin`: Provides full control over all resources.
52 | * All `editor` and `viewer` tools
53 | * `create_instance`
54 | * `create_user`
55 |
56 | ## Install MCP Toolbox
57 |
58 | 1. Download the latest version of Toolbox as a binary. Select the [correct
59 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
60 | to your OS and CPU architecture. You are required to use Toolbox version
61 | V0.15.0+:
62 |
63 | <!-- {x-release-please-start-version} -->
64 | {{< tabpane persist=header >}}
65 | {{< tab header="linux/amd64" lang="bash" >}}
66 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/linux/amd64/toolbox
67 | {{< /tab >}}
68 |
69 | {{< tab header="darwin/arm64" lang="bash" >}}
70 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/arm64/toolbox
71 | {{< /tab >}}
72 |
73 | {{< tab header="darwin/amd64" lang="bash" >}}
74 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/amd64/toolbox
75 | {{< /tab >}}
76 |
77 | {{< tab header="windows/amd64" lang="bash" >}}
78 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/windows/amd64/toolbox.exe
79 | {{< /tab >}}
80 | {{< /tabpane >}}
81 | <!-- {x-release-please-end} -->
82 |
83 | 1. Make the binary executable:
84 |
85 | ```bash
86 | chmod +x toolbox
87 | ```
88 |
89 | 1. Verify the installation:
90 |
91 | ```bash
92 | ./toolbox --version
93 | ```
94 |
95 | ## Configure your MCP Client
96 |
97 | {{< tabpane text=true >}}
98 | {{% tab header="Claude code" lang="en" %}}
99 |
100 | 1. Install [Claude
101 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
102 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
103 | 1. Add the following configuration and save:
104 |
105 | ```json
106 | {
107 | "mcpServers": {
108 | "cloud-sql-mysql-admin": {
109 | "command": "./PATH/TO/toolbox",
110 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
111 | "env": {
112 | }
113 | }
114 | }
115 | }
116 | ```
117 |
118 | 1. Restart Claude code to apply the new configuration.
119 | {{% /tab %}}
120 |
121 | {{% tab header="Claude desktop" lang="en" %}}
122 |
123 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
124 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
125 | 1. Add the following configuration and save:
126 |
127 | ```json
128 | {
129 | "mcpServers": {
130 | "cloud-sql-mysql-admin": {
131 | "command": "./PATH/TO/toolbox",
132 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
133 | "env": {
134 | }
135 | }
136 | }
137 | }
138 | ```
139 |
140 | 1. Restart Claude desktop.
141 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
142 | new MCP server available.
143 | {{% /tab %}}
144 |
145 | {{% tab header="Cline" lang="en" %}}
146 |
147 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap
148 | the **MCP Servers** icon.
149 | 1. Tap Configure MCP Servers to open the configuration file.
150 | 1. Add the following configuration and save:
151 |
152 | ```json
153 | {
154 | "mcpServers": {
155 | "cloud-sql-mysql-admin": {
156 | "command": "./PATH/TO/toolbox",
157 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
158 | "env": {
159 | }
160 | }
161 | }
162 | }
163 | ```
164 |
165 | 1. You should see a green active status after the server is successfully
166 | connected.
167 | {{% /tab %}}
168 |
169 | {{% tab header="Cursor" lang="en" %}}
170 |
171 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
172 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
173 | 1. Add the following configuration and save:
174 |
175 | ```json
176 | {
177 | "mcpServers": {
178 | "cloud-sql-mysql-admin": {
179 | "command": "./PATH/TO/toolbox",
180 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
181 | "env": {
182 | }
183 | }
184 | }
185 | }
186 | ```
187 |
188 | 1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
189 | Settings > MCP**. You should see a green active status after the server is
190 | successfully connected.
191 | {{% /tab %}}
192 |
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 |
195 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 | create a `.vscode` directory in your project root if it doesn't exist.
197 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1. Add the following configuration and save:
199 |
200 | ```json
201 | {
202 | "servers": {
203 | "cloud-sql-mysql-admin": {
204 | "command": "./PATH/TO/toolbox",
205 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
206 | "env": {
207 | }
208 | }
209 | }
210 | }
211 | ```
212 |
213 | {{% /tab %}}
214 |
215 | {{% tab header="Windsurf" lang="en" %}}
216 |
217 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 | Cascade assistant.
219 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1. Add the following configuration and save:
221 |
222 | ```json
223 | {
224 | "mcpServers": {
225 | "cloud-sql-mysql-admin": {
226 | "command": "./PATH/TO/toolbox",
227 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
228 | "env": {
229 | }
230 | }
231 | }
232 | }
233 | ```
234 |
235 | {{% /tab %}}
236 |
237 | {{% tab header="Gemini CLI" lang="en" %}}
238 |
239 | 1. Install the [Gemini
240 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
241 | 1. In your working directory, create a folder named `.gemini`. Within it,
242 | create a `settings.json` file.
243 | 1. Add the following configuration and save:
244 |
245 | ```json
246 | {
247 | "mcpServers": {
248 | "cloud-sql-mysql-admin": {
249 | "command": "./PATH/TO/toolbox",
250 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
251 | "env": {
252 | }
253 | }
254 | }
255 | }
256 | ```
257 | {{% /tab %}}
258 |
259 | {{% tab header="Gemini Code Assist" lang="en" %}}
260 |
261 | 1. Install the [Gemini Code
262 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
263 | extension in Visual Studio Code.
264 | 1. Enable Agent Mode in Gemini Code Assist chat.
265 | 1. In your working directory, create a folder named `.gemini`. Within it,
266 | create a `settings.json` file.
267 | 1. Add the following configuration and save:
268 |
269 | ```json
270 | {
271 | "mcpServers": {
272 | "cloud-sql-mysql-admin": {
273 | "command": "./PATH/TO/toolbox",
274 | "args": ["--prebuilt","cloud-sql-mysql-admin","--stdio"],
275 | "env": {
276 | }
277 | }
278 | }
279 | }
280 | ```
281 | {{% /tab %}}
282 | {{< /tabpane >}}
283 |
284 | ## Use Tools
285 |
286 | Your AI tool is now connected to Cloud SQL for MySQL using MCP.
287 |
288 | The `cloud-sql-mysql-admin` server provides tools for managing your Cloud SQL
289 | instances and interacting with your database:
290 | * **create_instance**: Creates a new Cloud SQL for MySQL instance.
291 | * **get_instance**: Gets information about a Cloud SQL instance.
292 | * **list_instances**: Lists Cloud SQL instances in a project.
293 | * **create_database**: Creates a new database in a Cloud SQL instance.
294 | * **list_databases**: Lists all databases for a Cloud SQL instance.
295 | * **create_user**: Creates a new user in a Cloud SQL instance.
296 | * **wait_for_operation**: Waits for a Cloud SQL operation to complete.
297 |
298 | {{< notice note >}}
299 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
300 | will adapt to the tools available, so this shouldn't affect most users.
301 | {{< /notice >}}
302 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/cloud_sql_mssql_admin_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: "Cloud SQL for SQL Server Admin using MCP"
3 | type: docs
4 | weight: 5
5 | description: >
6 | Create and manage Cloud SQL for SQL Server (Admin) using Toolbox.
7 | ---
8 |
9 | This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your
10 | developer assistant tools to create and manage Cloud SQL for SQL Server
11 | instance, database and users:
12 |
13 | * [Cursor][cursor]
14 | * [Windsurf][windsurf] (Codium)
15 | * [Visual Studio Code][vscode] (Copilot)
16 | * [Cline][cline] (VS Code extension)
17 | * [Claude desktop][claudedesktop]
18 | * [Claude code][claudecode]
19 | * [Gemini CLI][geminicli]
20 | * [Gemini Code Assist][geminicodeassist]
21 |
22 | [toolbox]: https://github.com/googleapis/genai-toolbox
23 | [cursor]: #configure-your-mcp-client
24 | [windsurf]: #configure-your-mcp-client
25 | [vscode]: #configure-your-mcp-client
26 | [cline]: #configure-your-mcp-client
27 | [claudedesktop]: #configure-your-mcp-client
28 | [claudecode]: #configure-your-mcp-client
29 | [geminicli]: #configure-your-mcp-client
30 | [geminicodeassist]: #configure-your-mcp-client
31 |
32 | ## Before you begin
33 |
34 | 1. In the Google Cloud console, on the [project selector
35 | page](https://console.cloud.google.com/projectselector2/home/dashboard),
36 | select or create a Google Cloud project.
37 |
38 | 1. [Make sure that billing is enabled for your Google Cloud
39 | project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
40 |
41 | 1. Grant the necessary IAM roles to the user that will be running the MCP
42 | server. The tools available will depend on the roles granted:
43 | * `roles/cloudsql.viewer`: Provides read-only access to resources.
44 | * `get_instance`
45 | * `list_instances`
46 | * `list_databases`
47 | * `wait_for_operation`
48 | * `roles/cloudsql.editor`: Provides permissions to manage existing resources.
49 | * All `viewer` tools
50 | * `create_database`
51 | * `roles/cloudsql.admin`: Provides full control over all resources.
52 | * All `editor` and `viewer` tools
53 | * `create_instance`
54 | * `create_user`
55 |
56 | ## Install MCP Toolbox
57 |
58 | 1. Download the latest version of Toolbox as a binary. Select the [correct
59 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
60 | to your OS and CPU architecture. You are required to use Toolbox version
61 | V0.15.0+:
62 |
63 | <!-- {x-release-please-start-version} -->
64 | {{< tabpane persist=header >}}
65 | {{< tab header="linux/amd64" lang="bash" >}}
66 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/linux/amd64/toolbox
67 | {{< /tab >}}
68 |
69 | {{< tab header="darwin/arm64" lang="bash" >}}
70 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/arm64/toolbox
71 | {{< /tab >}}
72 |
73 | {{< tab header="darwin/amd64" lang="bash" >}}
74 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/amd64/toolbox
75 | {{< /tab >}}
76 |
77 | {{< tab header="windows/amd64" lang="bash" >}}
78 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/windows/amd64/toolbox.exe
79 | {{< /tab >}}
80 | {{< /tabpane >}}
81 | <!-- {x-release-please-end} -->
82 |
83 | 1. Make the binary executable:
84 |
85 | ```bash
86 | chmod +x toolbox
87 | ```
88 |
89 | 1. Verify the installation:
90 |
91 | ```bash
92 | ./toolbox --version
93 | ```
94 |
95 | ## Configure your MCP Client
96 |
97 | {{< tabpane text=true >}}
98 | {{% tab header="Claude code" lang="en" %}}
99 |
100 | 1. Install [Claude
101 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
102 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
103 | 1. Add the following configuration and save:
104 |
105 | ```json
106 | {
107 | "mcpServers": {
108 | "cloud-sql-mssql-admin": {
109 | "command": "./PATH/TO/toolbox",
110 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
111 | "env": {
112 | }
113 | }
114 | }
115 | }
116 | ```
117 |
118 | 1. Restart Claude code to apply the new configuration.
119 | {{% /tab %}}
120 |
121 | {{% tab header="Claude desktop" lang="en" %}}
122 |
123 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
124 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
125 | 1. Add the following configuration and save:
126 |
127 | ```json
128 | {
129 | "mcpServers": {
130 | "cloud-sql-mssql-admin": {
131 | "command": "./PATH/TO/toolbox",
132 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
133 | "env": {
134 | }
135 | }
136 | }
137 | }
138 | ```
139 |
140 | 1. Restart Claude desktop.
141 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
142 | new MCP server available.
143 | {{% /tab %}}
144 |
145 | {{% tab header="Cline" lang="en" %}}
146 |
147 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap
148 | the **MCP Servers** icon.
149 | 1. Tap Configure MCP Servers to open the configuration file.
150 | 1. Add the following configuration and save:
151 |
152 | ```json
153 | {
154 | "mcpServers": {
155 | "cloud-sql-mssql-admin": {
156 | "command": "./PATH/TO/toolbox",
157 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
158 | "env": {
159 | }
160 | }
161 | }
162 | }
163 | ```
164 |
165 | 1. You should see a green active status after the server is successfully
166 | connected.
167 | {{% /tab %}}
168 |
169 | {{% tab header="Cursor" lang="en" %}}
170 |
171 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
172 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
173 | 1. Add the following configuration and save:
174 |
175 | ```json
176 | {
177 | "mcpServers": {
178 | "cloud-sql-mssql-admin": {
179 | "command": "./PATH/TO/toolbox",
180 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
181 | "env": {
182 | }
183 | }
184 | }
185 | }
186 | ```
187 |
188 | 1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
189 | Settings > MCP**. You should see a green active status after the server is
190 | successfully connected.
191 | {{% /tab %}}
192 |
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 |
195 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 | create a `.vscode` directory in your project root if it doesn't exist.
197 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1. Add the following configuration and save:
199 |
200 | ```json
201 | {
202 | "servers": {
203 | "cloud-sql-mssql-admin": {
204 | "command": "./PATH/TO/toolbox",
205 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
206 | "env": {
207 | }
208 | }
209 | }
210 | }
211 | ```
212 |
213 | {{% /tab %}}
214 |
215 | {{% tab header="Windsurf" lang="en" %}}
216 |
217 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 | Cascade assistant.
219 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1. Add the following configuration and save:
221 |
222 | ```json
223 | {
224 | "mcpServers": {
225 | "cloud-sql-mssql-admin": {
226 | "command": "./PATH/TO/toolbox",
227 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
228 | "env": {
229 | }
230 | }
231 | }
232 | }
233 | ```
234 |
235 | {{% /tab %}}
236 |
237 | {{% tab header="Gemini CLI" lang="en" %}}
238 |
239 | 1. Install the [Gemini
240 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
241 | 1. In your working directory, create a folder named `.gemini`. Within it,
242 | create a `settings.json` file.
243 | 1. Add the following configuration and save:
244 |
245 | ```json
246 | {
247 | "mcpServers": {
248 | "cloud-sql-mssql-admin": {
249 | "command": "./PATH/TO/toolbox",
250 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
251 | "env": {
252 | }
253 | }
254 | }
255 | }
256 | ```
257 | {{% /tab %}}
258 |
259 | {{% tab header="Gemini Code Assist" lang="en" %}}
260 |
261 | 1. Install the [Gemini Code
262 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
263 | extension in Visual Studio Code.
264 | 1. Enable Agent Mode in Gemini Code Assist chat.
265 | 1. In your working directory, create a folder named `.gemini`. Within it,
266 | create a `settings.json` file.
267 | 1. Add the following configuration and save:
268 |
269 | ```json
270 | {
271 | "mcpServers": {
272 | "cloud-sql-mssql-admin": {
273 | "command": "./PATH/TO/toolbox",
274 | "args": ["--prebuilt","cloud-sql-mssql-admin","--stdio"],
275 | "env": {
276 | }
277 | }
278 | }
279 | }
280 | ```
281 | {{% /tab %}}
282 | {{< /tabpane >}}
283 |
284 | ## Use Tools
285 |
286 | Your AI tool is now connected to Cloud SQL for SQL Server using MCP.
287 |
288 | The `cloud-sql-mssql-admin` server provides tools for managing your Cloud SQL
289 | instances and interacting with your database:
290 | * **create_instance**: Creates a new Cloud SQL for SQL Server instance.
291 | * **get_instance**: Gets information about a Cloud SQL instance.
292 | * **list_instances**: Lists Cloud SQL instances in a project.
293 | * **create_database**: Creates a new database in a Cloud SQL instance.
294 | * **list_databases**: Lists all databases for a Cloud SQL instance.
295 | * **create_user**: Creates a new user in a Cloud SQL instance.
296 | * **wait_for_operation**: Waits for a Cloud SQL operation to complete.
297 |
298 | {{< notice note >}}
299 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
300 | will adapt to the tools available, so this shouldn't affect most users.
301 | {{< /notice >}}
302 |
```
--------------------------------------------------------------------------------
/tests/cloudsql/cloudsql_wait_for_operation_test.go:
--------------------------------------------------------------------------------
```go
1 | // Copyright 2025 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package cloudsql
16 |
17 | import (
18 | "bytes"
19 | "context"
20 | "encoding/json"
21 | "fmt"
22 | "io"
23 | "net/http"
24 | "net/http/httptest"
25 | "net/url"
26 | "reflect"
27 | "regexp"
28 | "strings"
29 | "sync"
30 | "testing"
31 | "time"
32 |
33 | "github.com/googleapis/genai-toolbox/internal/testutils"
34 | "github.com/googleapis/genai-toolbox/tests"
35 |
36 | _ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlwaitforoperation"
37 | )
38 |
39 | var (
40 | cloudsqlWaitToolKind = "cloud-sql-wait-for-operation"
41 | )
42 |
43 | type waitForOperationTransport struct {
44 | transport http.RoundTripper
45 | url *url.URL
46 | }
47 |
48 | func (t *waitForOperationTransport) RoundTrip(req *http.Request) (*http.Response, error) {
49 | if strings.HasPrefix(req.URL.String(), "https://sqladmin.googleapis.com") {
50 | req.URL.Scheme = t.url.Scheme
51 | req.URL.Host = t.url.Host
52 | }
53 | return t.transport.RoundTrip(req)
54 | }
55 |
56 | type cloudsqlOperation struct {
57 | Name string `json:"name"`
58 | Status string `json:"status"`
59 | TargetLink string `json:"targetLink"`
60 | OperationType string `json:"operationType"`
61 | Error *struct {
62 | Errors []struct {
63 | Code string `json:"code"`
64 | Message string `json:"message"`
65 | } `json:"errors"`
66 | } `json:"error,omitempty"`
67 | }
68 |
69 | type cloudsqlInstance struct {
70 | Region string `json:"region"`
71 | DatabaseVersion string `json:"databaseVersion"`
72 | }
73 |
74 | type cloudsqlHandler struct {
75 | mu sync.Mutex
76 | operations map[string]*cloudsqlOperation
77 | instances map[string]*cloudsqlInstance
78 | t *testing.T
79 | }
80 |
81 | func (h *cloudsqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
82 | h.mu.Lock()
83 | defer h.mu.Unlock()
84 |
85 | if !strings.Contains(r.UserAgent(), "genai-toolbox/") {
86 | h.t.Errorf("User-Agent header not found")
87 | }
88 |
89 | if match, _ := regexp.MatchString("/v1/projects/p1/operations/.*", r.URL.Path); match {
90 | parts := regexp.MustCompile("/").Split(r.URL.Path, -1)
91 | opName := parts[len(parts)-1]
92 |
93 | op, ok := h.operations[opName]
94 | if !ok {
95 | http.NotFound(w, r)
96 | return
97 | }
98 |
99 | if op.Status != "DONE" {
100 | op.Status = "DONE"
101 | }
102 |
103 | w.Header().Set("Content-Type", "application/json")
104 | if err := json.NewEncoder(w).Encode(op); err != nil {
105 | http.Error(w, err.Error(), http.StatusInternalServerError)
106 | }
107 | } else if match, _ := regexp.MatchString("/v1/projects/p1/instances/.*", r.URL.Path); match {
108 | parts := regexp.MustCompile("/").Split(r.URL.Path, -1)
109 | instanceName := parts[len(parts)-1]
110 |
111 | instance, ok := h.instances[instanceName]
112 | if !ok {
113 | http.NotFound(w, r)
114 | return
115 | }
116 | w.Header().Set("Content-Type", "application/json")
117 | if err := json.NewEncoder(w).Encode(instance); err != nil {
118 | http.Error(w, err.Error(), http.StatusInternalServerError)
119 | }
120 | } else {
121 | http.NotFound(w, r)
122 | }
123 | }
124 |
125 | func TestCloudSQLWaitToolEndpoints(t *testing.T) {
126 | h := &cloudsqlHandler{
127 | operations: map[string]*cloudsqlOperation{
128 | "op1": {Name: "op1", Status: "PENDING", OperationType: "CREATE_DATABASE"},
129 | "op2": {Name: "op2", Status: "PENDING", OperationType: "CREATE_DATABASE", Error: &struct {
130 | Errors []struct {
131 | Code string `json:"code"`
132 | Message string `json:"message"`
133 | } `json:"errors"`
134 | }{
135 | Errors: []struct {
136 | Code string `json:"code"`
137 | Message string `json:"message"`
138 | }{
139 | {Code: "ERROR_CODE", Message: "failed"},
140 | },
141 | }},
142 | "op3": {Name: "op3", Status: "PENDING", OperationType: "CREATE"},
143 | },
144 | instances: map[string]*cloudsqlInstance{
145 | "i1": {Region: "r1", DatabaseVersion: "POSTGRES_13"},
146 | },
147 | t: t,
148 | }
149 | server := httptest.NewServer(h)
150 | defer server.Close()
151 |
152 | h.operations["op1"].TargetLink = "https://sqladmin.googleapis.com/v1/projects/p1/instances/i1/databases/d1"
153 | h.operations["op2"].TargetLink = "https://sqladmin.googleapis.com/v1/projects/p1/instances/i2/databases/d2"
154 | h.operations["op3"].TargetLink = "https://sqladmin.googleapis.com/v1/projects/p1/instances/i1"
155 |
156 | serverURL, err := url.Parse(server.URL)
157 | if err != nil {
158 | t.Fatalf("failed to parse server URL: %v", err)
159 | }
160 |
161 | originalTransport := http.DefaultClient.Transport
162 | if originalTransport == nil {
163 | originalTransport = http.DefaultTransport
164 | }
165 | http.DefaultClient.Transport = &waitForOperationTransport{
166 | transport: originalTransport,
167 | url: serverURL,
168 | }
169 | t.Cleanup(func() {
170 | http.DefaultClient.Transport = originalTransport
171 | })
172 |
173 | ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
174 | defer cancel()
175 |
176 | var args []string
177 |
178 | toolsFile := getCloudSQLWaitToolsConfig()
179 | cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
180 | if err != nil {
181 | t.Fatalf("command initialization returned an error: %s", err)
182 | }
183 | defer cleanup()
184 |
185 | waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
186 | defer cancel()
187 | out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out)
188 | if err != nil {
189 | t.Logf("toolbox command logs: \n%s", out)
190 | t.Fatalf("toolbox didn't start successfully: %s", err)
191 | }
192 |
193 | tcs := []struct {
194 | name string
195 | toolName string
196 | body string
197 | want string
198 | expectError bool
199 | wantSubstring bool
200 | }{
201 | {
202 | name: "successful operation",
203 | toolName: "wait-for-op1",
204 | body: `{"project": "p1", "operation": "op1"}`,
205 | want: "Your Cloud SQL resource is ready",
206 | wantSubstring: true,
207 | },
208 | {
209 | name: "failed operation",
210 | toolName: "wait-for-op2",
211 | body: `{"project": "p1", "operation": "op2"}`,
212 | expectError: true,
213 | },
214 | {
215 | name: "non-database create operation",
216 | toolName: "wait-for-op3",
217 | body: `{"project": "p1", "operation": "op3"}`,
218 | want: `{"name":"op3","status":"DONE","targetLink":"` + h.operations["op3"].TargetLink + `","operationType":"CREATE"}`,
219 | },
220 | }
221 |
222 | for _, tc := range tcs {
223 | t.Run(tc.name, func(t *testing.T) {
224 | api := fmt.Sprintf("http://127.0.0.1:5000/api/tool/%s/invoke", tc.toolName)
225 | req, err := http.NewRequest(http.MethodPost, api, bytes.NewBufferString(tc.body))
226 | if err != nil {
227 | t.Fatalf("unable to create request: %s", err)
228 | }
229 | req.Header.Add("Content-type", "application/json")
230 | resp, err := http.DefaultClient.Do(req)
231 | if err != nil {
232 | t.Fatalf("unable to send request: %s", err)
233 | }
234 | defer resp.Body.Close()
235 |
236 | if tc.expectError {
237 | if resp.StatusCode == http.StatusOK {
238 | t.Fatal("expected error but got status 200")
239 | }
240 | return
241 | }
242 |
243 | if resp.StatusCode != http.StatusOK {
244 | bodyBytes, _ := io.ReadAll(resp.Body)
245 | t.Fatalf("response status code is not 200, got %d: %s", resp.StatusCode, string(bodyBytes))
246 | }
247 |
248 | if tc.wantSubstring {
249 | var result struct {
250 | Result string `json:"result"`
251 | }
252 | if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
253 | t.Fatalf("failed to decode response: %v", err)
254 | }
255 |
256 | if !bytes.Contains([]byte(result.Result), []byte(tc.want)) {
257 | t.Fatalf("unexpected result: got %q, want substring %q", result.Result, tc.want)
258 | }
259 | return
260 | }
261 |
262 | var result struct {
263 | Result string `json:"result"`
264 | }
265 | if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
266 | t.Fatalf("failed to decode response: %v", err)
267 | }
268 |
269 | var tempString string
270 | if err := json.Unmarshal([]byte(result.Result), &tempString); err != nil {
271 | t.Fatalf("failed to unmarshal outer JSON string: %v", err)
272 | }
273 |
274 | var got, want map[string]any
275 | if err := json.Unmarshal([]byte(tempString), &got); err != nil {
276 | t.Fatalf("failed to unmarshal inner JSON object: %v", err)
277 | }
278 |
279 | if err := json.Unmarshal([]byte(tc.want), &want); err != nil {
280 | t.Fatalf("failed to unmarshal want: %v", err)
281 | }
282 |
283 | if !reflect.DeepEqual(got, want) {
284 | t.Fatalf("unexpected result: got %+v, want %+v", got, want)
285 | }
286 | })
287 | }
288 | }
289 |
290 | func getCloudSQLWaitToolsConfig() map[string]any {
291 | return map[string]any{
292 | "sources": map[string]any{
293 | "my-cloud-sql-source": map[string]any{
294 | "kind": "cloud-sql-admin",
295 | },
296 | },
297 | "tools": map[string]any{
298 | "wait-for-op1": map[string]any{
299 | "kind": cloudsqlWaitToolKind,
300 | "source": "my-cloud-sql-source",
301 | "description": "wait for op1",
302 | },
303 | "wait-for-op2": map[string]any{
304 | "kind": cloudsqlWaitToolKind,
305 | "source": "my-cloud-sql-source",
306 | "description": "wait for op2",
307 | },
308 | "wait-for-op3": map[string]any{
309 | "kind": cloudsqlWaitToolKind,
310 | "source": "my-cloud-sql-source",
311 | "description": "wait for op3",
312 | },
313 | },
314 | }
315 | }
316 |
```
--------------------------------------------------------------------------------
/tests/oceanbase/oceanbase_integration_test.go:
--------------------------------------------------------------------------------
```go
1 | // Copyright 2025 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package oceanbase
16 |
17 | import (
18 | "context"
19 | "database/sql"
20 | "fmt"
21 | "os"
22 | "regexp"
23 | "strings"
24 | "testing"
25 | "time"
26 |
27 | "github.com/google/uuid"
28 | "github.com/googleapis/genai-toolbox/internal/testutils"
29 | "github.com/googleapis/genai-toolbox/tests"
30 |
31 | _ "github.com/go-sql-driver/mysql"
32 | )
33 |
34 | var (
35 | OceanBaseSourceKind = "oceanbase"
36 | OceanBaseToolKind = "oceanbase-sql"
37 | OceanBaseDatabase = os.Getenv("OCEANBASE_DATABASE")
38 | OceanBaseHost = os.Getenv("OCEANBASE_HOST")
39 | OceanBasePort = os.Getenv("OCEANBASE_PORT")
40 | OceanBaseUser = os.Getenv("OCEANBASE_USER")
41 | OceanBasePass = os.Getenv("OCEANBASE_PASSWORD")
42 | )
43 |
44 | func getOceanBaseVars(t *testing.T) map[string]any {
45 | switch "" {
46 | case OceanBaseDatabase:
47 | t.Fatal("'OCEANBASE_DATABASE' not set")
48 | case OceanBaseHost:
49 | t.Fatal("'OCEANBASE_HOST' not set")
50 | case OceanBasePort:
51 | t.Fatal("'OCEANBASE_PORT' not set")
52 | case OceanBaseUser:
53 | t.Fatal("'OCEANBASE_USER' not set")
54 | case OceanBasePass:
55 | t.Fatal("'OCEANBASE_PASSWORD' not set")
56 | }
57 |
58 | return map[string]any{
59 | "kind": OceanBaseSourceKind,
60 | "host": OceanBaseHost,
61 | "port": OceanBasePort,
62 | "database": OceanBaseDatabase,
63 | "user": OceanBaseUser,
64 | "password": OceanBasePass,
65 | }
66 | }
67 |
68 | // Copied over from oceanbase.go
69 | func initOceanBaseConnectionPool(host, port, user, pass, dbname string) (*sql.DB, error) {
70 | dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", user, pass, host, port, dbname)
71 |
72 | // Interact with the driver directly as you normally would
73 | pool, err := sql.Open("mysql", dsn)
74 | if err != nil {
75 | return nil, fmt.Errorf("sql.Open: %w", err)
76 | }
77 | return pool, nil
78 | }
79 |
80 | func TestOceanBaseToolEndpoints(t *testing.T) {
81 | sourceConfig := getOceanBaseVars(t)
82 | ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
83 | defer cancel()
84 |
85 | var args []string
86 |
87 | pool, err := initOceanBaseConnectionPool(OceanBaseHost, OceanBasePort, OceanBaseUser, OceanBasePass, OceanBaseDatabase)
88 | if err != nil {
89 | t.Fatalf("unable to create OceanBase connection pool: %s", err)
90 | }
91 |
92 | // create table name with UUID
93 | tableNameParam := "param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
94 | tableNameAuth := "auth_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
95 | tableNameTemplateParam := "template_param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
96 |
97 | // set up data for param tool
98 | createParamTableStmt, insertParamTableStmt, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, paramTestParams := getOceanBaseParamToolInfo(tableNameParam)
99 | teardownTable1 := setupOceanBaseTable(t, ctx, pool, createParamTableStmt, insertParamTableStmt, tableNameParam, paramTestParams)
100 | defer teardownTable1(t)
101 |
102 | // set up data for auth tool
103 | createAuthTableStmt, insertAuthTableStmt, authToolStmt, authTestParams := getOceanBaseAuthToolInfo(tableNameAuth)
104 | teardownTable2 := setupOceanBaseTable(t, ctx, pool, createAuthTableStmt, insertAuthTableStmt, tableNameAuth, authTestParams)
105 | defer teardownTable2(t)
106 |
107 | // Write config into a file and pass it to command
108 | toolsFile := tests.GetToolsConfig(sourceConfig, OceanBaseToolKind, paramToolStmt, idParamToolStmt, nameParamToolStmt, arrayToolStmt, authToolStmt)
109 | toolsFile = addOceanBaseExecuteSqlConfig(t, toolsFile)
110 | tmplSelectCombined, tmplSelectFilterCombined := getOceanBaseTmplToolStatement()
111 | toolsFile = tests.AddTemplateParamConfig(t, toolsFile, OceanBaseToolKind, tmplSelectCombined, tmplSelectFilterCombined, "")
112 |
113 | cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
114 | if err != nil {
115 | t.Fatalf("command initialization returned an error: %s", err)
116 | }
117 | defer cleanup()
118 |
119 | waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
120 | defer cancel()
121 | out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out)
122 | if err != nil {
123 | t.Logf("toolbox command logs: \n%s", out)
124 | t.Fatalf("toolbox didn't start successfully: %s", err)
125 | }
126 |
127 | // Get configs for tests
128 | select1Want, mcpMyFailToolWant, createTableStatement, mcpSelect1Want := getOceanBaseWants()
129 |
130 | // Run tests
131 | tests.RunToolGetTest(t)
132 | tests.RunToolInvokeTest(t, select1Want, tests.DisableArrayTest())
133 | tests.RunMCPToolCallMethod(t, mcpMyFailToolWant, mcpSelect1Want)
134 | tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
135 | tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam)
136 | }
137 |
138 | // OceanBase specific parameter tool info
139 | func getOceanBaseParamToolInfo(tableName string) (string, string, string, string, string, string, []any) {
140 | createStatement := fmt.Sprintf("CREATE TABLE %s (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255));", tableName)
141 | insertStatement := fmt.Sprintf("INSERT INTO %s (name) VALUES (?), (?), (?), (?);", tableName)
142 | toolStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ? OR name = ?;", tableName)
143 | idParamStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ?;", tableName)
144 | nameParamStatement := fmt.Sprintf("SELECT * FROM %s WHERE name = ?;", tableName)
145 | arrayToolStatement := fmt.Sprintf("SELECT * FROM %s WHERE id = ANY(?) AND name = ANY(?);", tableName)
146 | params := []any{"Alice", "Jane", "Sid", nil}
147 | return createStatement, insertStatement, toolStatement, idParamStatement, nameParamStatement, arrayToolStatement, params
148 | }
149 |
150 | // OceanBase specific auth tool info
151 | func getOceanBaseAuthToolInfo(tableName string) (string, string, string, []any) {
152 | createStatement := fmt.Sprintf("CREATE TABLE %s (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255));", tableName)
153 | insertStatement := fmt.Sprintf("INSERT INTO %s (name, email) VALUES (?, ?), (?, ?)", tableName)
154 | toolStatement := fmt.Sprintf("SELECT name FROM %s WHERE email = ?;", tableName)
155 | params := []any{"Alice", tests.ServiceAccountEmail, "Jane", "[email protected]"}
156 | return createStatement, insertStatement, toolStatement, params
157 | }
158 |
159 | // OceanBase specific template tool statements
160 | func getOceanBaseTmplToolStatement() (string, string) {
161 | tmplSelectCombined := "SELECT * FROM {{.tableName}} WHERE id = ?"
162 | tmplSelectFilterCombined := "SELECT * FROM {{.tableName}} WHERE {{.columnFilter}} = ?"
163 | return tmplSelectCombined, tmplSelectFilterCombined
164 | }
165 |
166 | // OceanBase specific expected results
167 | func getOceanBaseWants() (string, string, string, string) {
168 | select1Want := "[{\"1\":1}]"
169 | mcpMyFailToolWant := `{"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to execute query: Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near 'SELEC 1;' at line 1"}],"isError":true}}`
170 | createTableStatement := `"CREATE TABLE t (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255))"`
171 | mcpSelect1Want := `{"jsonrpc":"2.0","id":"invoke my-auth-required-tool","result":{"content":[{"type":"text","text":"{\"1\":1}"}]}}`
172 | return select1Want, mcpMyFailToolWant, createTableStatement, mcpSelect1Want
173 | }
174 |
175 | // Add OceanBase Execute SQL configuration
176 | func addOceanBaseExecuteSqlConfig(t *testing.T, config map[string]any) map[string]any {
177 | tools, ok := config["tools"].(map[string]any)
178 | if !ok {
179 | t.Fatalf("unable to get tools from config")
180 | }
181 | tools["my-exec-sql-tool"] = map[string]any{
182 | "kind": "oceanbase-execute-sql",
183 | "source": "my-instance",
184 | "description": "Tool to execute sql",
185 | }
186 | tools["my-auth-exec-sql-tool"] = map[string]any{
187 | "kind": "oceanbase-execute-sql",
188 | "source": "my-instance",
189 | "description": "Tool to execute sql",
190 | "authRequired": []string{
191 | "my-google-auth",
192 | },
193 | }
194 | config["tools"] = tools
195 | return config
196 | }
197 |
198 | // Setup OceanBase table
199 | func setupOceanBaseTable(t *testing.T, ctx context.Context, pool *sql.DB, createStatement, insertStatement, tableName string, params []any) func(*testing.T) {
200 | err := pool.PingContext(ctx)
201 | if err != nil {
202 | t.Fatalf("unable to connect to test database: %s", err)
203 | }
204 |
205 | // Create table
206 | _, err = pool.QueryContext(ctx, createStatement)
207 | if err != nil {
208 | t.Fatalf("unable to create test table %s: %s", tableName, err)
209 | }
210 |
211 | // Insert test data
212 | _, err = pool.QueryContext(ctx, insertStatement, params...)
213 | if err != nil {
214 | t.Fatalf("unable to insert test data: %s", err)
215 | }
216 |
217 | return func(t *testing.T) {
218 | // tear down test
219 | _, err = pool.ExecContext(ctx, fmt.Sprintf("DROP TABLE %s;", tableName))
220 | if err != nil {
221 | t.Errorf("Teardown failed: %s", err)
222 | }
223 | }
224 | }
225 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/cloud_sql_pg_admin_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: "Cloud SQL for PostgreSQL Admin using MCP"
3 | type: docs
4 | weight: 3
5 | description: >
6 | Create and manage Cloud SQL for PostgreSQL (Admin) using Toolbox.
7 | ---
8 |
9 | This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your
10 | developer assistant tools to create and manage Cloud SQL for PostgreSQL
11 | instance, database and users:
12 |
13 | * [Cursor][cursor]
14 | * [Windsurf][windsurf] (Codium)
15 | * [Visual Studio Code][vscode] (Copilot)
16 | * [Cline][cline] (VS Code extension)
17 | * [Claude desktop][claudedesktop]
18 | * [Claude code][claudecode]
19 | * [Gemini CLI][geminicli]
20 | * [Gemini Code Assist][geminicodeassist]
21 |
22 | [toolbox]: https://github.com/googleapis/genai-toolbox
23 | [cursor]: #configure-your-mcp-client
24 | [windsurf]: #configure-your-mcp-client
25 | [vscode]: #configure-your-mcp-client
26 | [cline]: #configure-your-mcp-client
27 | [claudedesktop]: #configure-your-mcp-client
28 | [claudecode]: #configure-your-mcp-client
29 | [geminicli]: #configure-your-mcp-client
30 | [geminicodeassist]: #configure-your-mcp-client
31 |
32 | ## Before you begin
33 |
34 | 1. In the Google Cloud console, on the [project selector
35 | page](https://console.cloud.google.com/projectselector2/home/dashboard),
36 | select or create a Google Cloud project.
37 |
38 | 1. [Make sure that billing is enabled for your Google Cloud
39 | project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
40 |
41 | 1. Grant the necessary IAM roles to the user that will be running the MCP
42 | server. The tools available will depend on the roles granted:
43 | * `roles/cloudsql.viewer`: Provides read-only access to resources.
44 | * `get_instance`
45 | * `list_instances`
46 | * `list_databases`
47 | * `wait_for_operation`
48 | * `roles/cloudsql.editor`: Provides permissions to manage existing resources.
49 | * All `viewer` tools
50 | * `create_database`
51 | * `roles/cloudsql.admin`: Provides full control over all resources.
52 | * All `editor` and `viewer` tools
53 | * `create_instance`
54 | * `create_user`
55 |
56 | ## Install MCP Toolbox
57 |
58 | 1. Download the latest version of Toolbox as a binary. Select the [correct
59 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
60 | to your OS and CPU architecture. You are required to use Toolbox version
61 | V0.15.0+:
62 |
63 | <!-- {x-release-please-start-version} -->
64 | {{< tabpane persist=header >}}
65 | {{< tab header="linux/amd64" lang="bash" >}}
66 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/linux/amd64/toolbox
67 | {{< /tab >}}
68 |
69 | {{< tab header="darwin/arm64" lang="bash" >}}
70 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/arm64/toolbox
71 | {{< /tab >}}
72 |
73 | {{< tab header="darwin/amd64" lang="bash" >}}
74 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/darwin/amd64/toolbox
75 | {{< /tab >}}
76 |
77 | {{< tab header="windows/amd64" lang="bash" >}}
78 | curl -O https://storage.googleapis.com/genai-toolbox/v0.15.0/windows/amd64/toolbox.exe
79 | {{< /tab >}}
80 | {{< /tabpane >}}
81 | <!-- {x-release-please-end} -->
82 |
83 | 1. Make the binary executable:
84 |
85 | ```bash
86 | chmod +x toolbox
87 | ```
88 |
89 | 1. Verify the installation:
90 |
91 | ```bash
92 | ./toolbox --version
93 | ```
94 |
95 | ## Configure your MCP Client
96 |
97 | {{< tabpane text=true >}}
98 | {{% tab header="Claude code" lang="en" %}}
99 |
100 | 1. Install [Claude
101 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
102 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
103 | 1. Add the following configuration and save:
104 |
105 | ```json
106 | {
107 | "mcpServers": {
108 | "cloud-sql-postgres-admin": {
109 | "command": "./PATH/TO/toolbox",
110 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
111 | "env": {
112 | }
113 | }
114 | }
115 | }
116 | ```
117 |
118 | 1. Restart Claude code to apply the new configuration.
119 | {{% /tab %}}
120 |
121 | {{% tab header="Claude desktop" lang="en" %}}
122 |
123 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
124 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
125 | 1. Add the following configuration and save:
126 |
127 | ```json
128 | {
129 | "mcpServers": {
130 | "cloud-sql-postgres-admin": {
131 | "command": "./PATH/TO/toolbox",
132 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
133 | "env": {
134 | }
135 | }
136 | }
137 | }
138 | ```
139 |
140 | 1. Restart Claude desktop.
141 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
142 | new MCP server available.
143 | {{% /tab %}}
144 |
145 | {{% tab header="Cline" lang="en" %}}
146 |
147 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap
148 | the **MCP Servers** icon.
149 | 1. Tap Configure MCP Servers to open the configuration file.
150 | 1. Add the following configuration and save:
151 |
152 | ```json
153 | {
154 | "mcpServers": {
155 | "cloud-sql-postgres-admin": {
156 | "command": "./PATH/TO/toolbox",
157 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
158 | "env": {
159 | }
160 | }
161 | }
162 | }
163 | ```
164 |
165 | 1. You should see a green active status after the server is successfully
166 | connected.
167 | {{% /tab %}}
168 |
169 | {{% tab header="Cursor" lang="en" %}}
170 |
171 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
172 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
173 | 1. Add the following configuration and save:
174 |
175 | ```json
176 | {
177 | "mcpServers": {
178 | "cloud-sql-postgres-admin": {
179 | "command": "./PATH/TO/toolbox",
180 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
181 | "env": {
182 | }
183 | }
184 | }
185 | }
186 | ```
187 |
188 | 1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
189 | Settings > MCP**. You should see a green active status after the server is
190 | successfully connected.
191 | {{% /tab %}}
192 |
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 |
195 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 | create a `.vscode` directory in your project root if it doesn't exist.
197 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1. Add the following configuration and save:
199 |
200 | ```json
201 | {
202 | "servers": {
203 | "cloud-sql-postgres-admin": {
204 | "command": "./PATH/TO/toolbox",
205 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
206 | "env": {
207 | }
208 | }
209 | }
210 | }
211 | ```
212 |
213 | {{% /tab %}}
214 |
215 | {{% tab header="Windsurf" lang="en" %}}
216 |
217 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 | Cascade assistant.
219 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1. Add the following configuration and save:
221 |
222 | ```json
223 | {
224 | "mcpServers": {
225 | "cloud-sql-postgres-admin": {
226 | "command": "./PATH/TO/toolbox",
227 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
228 | "env": {
229 | }
230 | }
231 | }
232 | }
233 | ```
234 |
235 | {{% /tab %}}
236 |
237 | {{% tab header="Gemini CLI" lang="en" %}}
238 |
239 | 1. Install the [Gemini
240 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
241 | 1. In your working directory, create a folder named `.gemini`. Within it,
242 | create a `settings.json` file.
243 | 1. Add the following configuration and save:
244 |
245 | ```json
246 | {
247 | "mcpServers": {
248 | "cloud-sql-postgres-admin": {
249 | "command": "./PATH/TO/toolbox",
250 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
251 | "env": {
252 | }
253 | }
254 | }
255 | }
256 | ```
257 | {{% /tab %}}
258 |
259 | {{% tab header="Gemini Code Assist" lang="en" %}}
260 |
261 | 1. Install the [Gemini Code
262 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
263 | extension in Visual Studio Code.
264 | 1. Enable Agent Mode in Gemini Code Assist chat.
265 | 1. In your working directory, create a folder named `.gemini`. Within it,
266 | create a `settings.json` file.
267 | 1. Add the following configuration and save:
268 |
269 | ```json
270 | {
271 | "mcpServers": {
272 | "cloud-sql-postgres-admin": {
273 | "command": "./PATH/TO/toolbox",
274 | "args": ["--prebuilt","cloud-sql-postgres-admin","--stdio"],
275 | "env": {
276 | }
277 | }
278 | }
279 | }
280 | ```
281 | {{% /tab %}}
282 | {{< /tabpane >}}
283 |
284 | ## Use Tools
285 |
286 | Your AI tool is now connected to Cloud SQL for PostgreSQL using MCP.
287 |
288 | The `cloud-sql-postgres-admin` server provides tools for managing your Cloud SQL
289 | instances and interacting with your database:
290 | * **create_instance**: Creates a new Cloud SQL for PostgreSQL instance.
291 | * **get_instance**: Gets information about a Cloud SQL instance.
292 | * **list_instances**: Lists Cloud SQL instances in a project.
293 | * **create_database**: Creates a new database in a Cloud SQL instance.
294 | * **list_databases**: Lists all databases for a Cloud SQL instance.
295 | * **create_user**: Creates a new user in a Cloud SQL instance.
296 | * **wait_for_operation**: Waits for a Cloud SQL operation to complete.
297 |
298 | {{< notice note >}}
299 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
300 | will adapt to the tools available, so this shouldn't affect most users.
301 | {{< /notice >}}
302 |
```
--------------------------------------------------------------------------------
/docs/en/resources/authServices/_index.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: "AuthServices"
3 | type: docs
4 | weight: 1
5 | description: >
6 | AuthServices represent services that handle authentication and authorization.
7 | ---
8 |
9 | AuthServices represent services that handle authentication and authorization. It
10 | can primarily be used by [Tools](../tools/) in two different ways:
11 |
12 | - [**Authorized Invocation**][auth-invoke] is when a tool
13 | is validated by the auth service before the call can be invoked. Toolbox
14 | will reject any calls that fail to validate or have an invalid token.
15 | - [**Authenticated Parameters**][auth-params] replace the value of a parameter
16 | with a field from an [OIDC][openid-claims] claim. Toolbox will automatically
17 | resolve the ID token provided by the client and replace the parameter in the
18 | tool call.
19 |
20 | [openid-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
21 | [auth-invoke]: ../tools/#authorized-invocations
22 | [auth-params]: ../tools/#authenticated-parameters
23 |
24 | ## Example
25 |
26 | The following configurations are placed at the top level of a `tools.yaml` file.
27 |
28 | {{< notice tip >}}
29 | If you are accessing Toolbox with multiple applications, each
30 | application should register their own Client ID even if they use the same
31 | "kind" of auth provider.
32 | {{< /notice >}}
33 |
34 | ```yaml
35 | authServices:
36 | my_auth_app_1:
37 | kind: google
38 | clientId: ${YOUR_CLIENT_ID_1}
39 | my_auth_app_2:
40 | kind: google
41 | clientId: ${YOUR_CLIENT_ID_2}
42 | ```
43 |
44 | {{< notice tip >}}
45 | Use environment variable replacement with the format ${ENV_NAME}
46 | instead of hardcoding your secrets into the configuration file.
47 | {{< /notice >}}
48 |
49 | After you've configured an `authService` you'll, need to reference it in the
50 | configuration for each tool that should use it:
51 |
52 | - **Authorized Invocations** for authorizing a tool call, [use the
53 | `authRequired` field in a tool config][auth-invoke]
54 | - **Authenticated Parameters** for using the value from a OIDC claim, [use the
55 | `authServices` field in a parameter config][auth-params]
56 |
57 | ## Specifying ID Tokens from Clients
58 |
59 | After [configuring](#example) your `authServices` section, use a Toolbox SDK to
60 | add your ID tokens to the header of a Tool invocation request. When specifying a
61 | token you will provide a function (that returns an id). This function is called
62 | when the tool is invoked. This allows you to cache and refresh the ID token as
63 | needed.
64 |
65 | The primary method for providing these getters is via the `auth_token_getters`
66 | parameter when loading tools, or the `add_auth_token_getter`() /
67 | `add_auth_token_getters()` methods on a loaded tool object.
68 |
69 | ### Specifying tokens during load
70 |
71 | #### Python
72 |
73 | Use the [Python SDK](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main).
74 |
75 | {{< tabpane persist=header >}}
76 | {{< tab header="Core" lang="Python" >}}
77 | import asyncio
78 | from toolbox_core import ToolboxClient
79 |
80 | async def get_auth_token():
81 | # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
82 | # This example just returns a placeholder. Replace with your actual token retrieval.
83 | return "YOUR_ID_TOKEN" # Placeholder
84 |
85 | async def main():
86 | async with ToolboxClient("<http://127.0.0.1:5000>") as toolbox:
87 | auth_tool = await toolbox.load_tool(
88 | "get_sensitive_data",
89 | auth_token_getters={"my_auth_app_1": get_auth_token}
90 | )
91 | result = await auth_tool(param="value")
92 | print(result)
93 |
94 | if **name** == "**main**":
95 | asyncio.run(main())
96 | {{< /tab >}}
97 | {{< tab header="LangChain" lang="Python" >}}
98 | import asyncio
99 | from toolbox_langchain import ToolboxClient
100 |
101 | async def get_auth_token():
102 | # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
103 | # This example just returns a placeholder. Replace with your actual token retrieval.
104 | return "YOUR_ID_TOKEN" # Placeholder
105 |
106 | async def main():
107 | toolbox = ToolboxClient("<http://127.0.0.1:5000>")
108 |
109 | auth_tool = await toolbox.aload_tool(
110 | "get_sensitive_data",
111 | auth_token_getters={"my_auth_app_1": get_auth_token}
112 | )
113 | result = await auth_tool.ainvoke({"param": "value"})
114 | print(result)
115 |
116 | if **name** == "**main**":
117 | asyncio.run(main())
118 | {{< /tab >}}
119 | {{< tab header="Llamaindex" lang="Python" >}}
120 | import asyncio
121 | from toolbox_llamaindex import ToolboxClient
122 |
123 | async def get_auth_token():
124 | # ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
125 | # This example just returns a placeholder. Replace with your actual token retrieval.
126 | return "YOUR_ID_TOKEN" # Placeholder
127 |
128 | async def main():
129 | toolbox = ToolboxClient("<http://127.0.0.1:5000>")
130 |
131 | auth_tool = await toolbox.aload_tool(
132 | "get_sensitive_data",
133 | auth_token_getters={"my_auth_app_1": get_auth_token}
134 | )
135 | # result = await auth_tool.acall(param="value")
136 | # print(result.content)
137 |
138 | if **name** == "**main**":
139 | asyncio.run(main()){{< /tab >}}
140 | {{< /tabpane >}}
141 |
142 | #### Javascript/Typescript
143 |
144 | Use the [JS SDK](https://github.com/googleapis/mcp-toolbox-sdk-js/tree/main).
145 |
146 | ```javascript
147 | import { ToolboxClient } from '@toolbox-sdk/core';
148 |
149 | async function getAuthToken() {
150 | // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
151 | // This example just returns a placeholder. Replace with your actual token retrieval.
152 | return "YOUR_ID_TOKEN" // Placeholder
153 | }
154 |
155 | const URL = 'http://127.0.0.1:5000';
156 | let client = new ToolboxClient(URL);
157 | const authTool = await client.loadTool("my-tool", {"my_auth_app_1": getAuthToken});
158 | const result = await authTool({param:"value"});
159 | console.log(result);
160 | print(result)
161 | ```
162 |
163 | #### Go
164 |
165 | Use the [Go SDK](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main).
166 |
167 | ```go
168 | import "github.com/googleapis/mcp-toolbox-sdk-go/core"
169 | import "fmt"
170 |
171 | func getAuthToken() string {
172 | // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
173 | // This example just returns a placeholder. Replace with your actual token retrieval.
174 | return "YOUR_ID_TOKEN" // Placeholder
175 | }
176 |
177 | func main() {
178 | URL := 'http://127.0.0.1:5000'
179 | client, err := core.NewToolboxClient(URL)
180 | if err != nil {
181 | log.Fatalf("Failed to create Toolbox client: %v", err)
182 | }
183 | dynamicTokenSource := core.NewCustomTokenSource(getAuthToken)
184 | authTool, err := client.LoadTool(
185 | "my-tool",
186 | ctx,
187 | core.WithAuthTokenSource("my_auth_app_1", dynamicTokenSource))
188 | if err != nil {
189 | log.Fatalf("Failed to load tool: %v", err)
190 | }
191 | inputs := map[string]any{"param": "value"}
192 | result, err := authTool.Invoke(ctx, inputs)
193 | if err != nil {
194 | log.Fatalf("Failed to invoke tool: %v", err)
195 | }
196 | fmt.Println(result)
197 | }
198 | ```
199 |
200 | ### Specifying tokens for existing tools
201 |
202 | #### Python
203 |
204 | Use the [Python
205 | SDK](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main).
206 |
207 | {{< tabpane persist=header >}}
208 | {{< tab header="Core" lang="Python" >}}
209 | tools = await toolbox.load_toolset()
210 |
211 | # for a single token
212 |
213 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
214 |
215 | # OR, if multiple tokens are needed
216 |
217 | authorized_tool = tools[0].add_auth_token_getters({
218 | "my_auth1": get_auth1_token,
219 | "my_auth2": get_auth2_token,
220 | })
221 | {{< /tab >}}
222 | {{< tab header="LangChain" lang="Python" >}}
223 | tools = toolbox.load_toolset()
224 |
225 | # for a single token
226 |
227 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
228 |
229 | # OR, if multiple tokens are needed
230 |
231 | authorized_tool = tools[0].add_auth_token_getters({
232 | "my_auth1": get_auth1_token,
233 | "my_auth2": get_auth2_token,
234 | })
235 | {{< /tab >}}
236 | {{< tab header="Llamaindex" lang="Python" >}}
237 | tools = toolbox.load_toolset()
238 |
239 | # for a single token
240 |
241 | authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
242 |
243 | # OR, if multiple tokens are needed
244 |
245 | authorized_tool = tools[0].add_auth_token_getters({
246 | "my_auth1": get_auth1_token,
247 | "my_auth2": get_auth2_token,
248 | })
249 | {{< /tab >}}
250 | {{< /tabpane >}}
251 |
252 | #### Javascript/Typescript
253 |
254 | Use the [JS SDK](https://github.com/googleapis/mcp-toolbox-sdk-js/tree/main).
255 |
256 | ```javascript
257 | const URL = 'http://127.0.0.1:5000';
258 | let client = new ToolboxClient(URL);
259 | let tool = await client.loadTool("my-tool")
260 |
261 | // for a single token
262 | const authorizedTool = tool.addAuthTokenGetter("my_auth", get_auth_token)
263 |
264 | // OR, if multiple tokens are needed
265 | const multiAuthTool = tool.addAuthTokenGetters({
266 | "my_auth_1": getAuthToken1,
267 | "my_auth_2": getAuthToken2,
268 | })
269 |
270 | ```
271 |
272 | #### Go
273 |
274 | Use the [Go SDK](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main).
275 |
276 | ```go
277 | import "github.com/googleapis/mcp-toolbox-sdk-go/core"
278 |
279 | func main() {
280 | URL := 'http://127.0.0.1:5000'
281 | client, err := core.NewToolboxClient(URL)
282 | if err != nil {
283 | log.Fatalf("Failed to create Toolbox client: %v", err)
284 | }
285 | tool, err := client.LoadTool("my-tool", ctx))
286 | if err != nil {
287 | log.Fatalf("Failed to load tool: %v", err)
288 | }
289 | dynamicTokenSource1 := core.NewCustomTokenSource(getAuthToken1)
290 | dynamicTokenSource2 := core.NewCustomTokenSource(getAuthToken1)
291 |
292 | // For a single token
293 | authTool, err := tool.ToolFrom(
294 | core.WithAuthTokenSource("my-auth", dynamicTokenSource),
295 | )
296 |
297 | // OR, if multiple tokens are needed
298 | authTool, err := tool.ToolFrom(
299 | core.WithAuthTokenSource("my-auth_1", dynamicTokenSource1),
300 | core.WithAuthTokenSource("my-auth_2", dynamicTokenSource2),
301 | )
302 | }
303 | ```
304 |
305 | ## Kinds of Auth Services
306 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/neo4j_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: Neo4j using MCP
3 | type: docs
4 | weight: 2
5 | description: "Connect your IDE to Neo4j using Toolbox."
6 | ---
7 |
8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
9 | an open protocol for connecting Large Language Models (LLMs) to data sources
10 | like Neo4j. This guide covers how to use [MCP Toolbox for Databases][toolbox] to
11 | expose your developer assistant tools to a Neo4j instance:
12 |
13 | * [Cursor][cursor]
14 | * [Windsurf][windsurf] (Codium)
15 | * [Visual Studio Code][vscode] (Copilot)
16 | * [Cline][cline] (VS Code extension)
17 | * [Claude desktop][claudedesktop]
18 | * [Claude code][claudecode]
19 | * [Gemini CLI][geminicli]
20 | * [Gemini Code Assist][geminicodeassist]
21 |
22 | [toolbox]: https://github.com/googleapis/genai-toolbox
23 | [cursor]: #configure-your-mcp-client
24 | [windsurf]: #configure-your-mcp-client
25 | [vscode]: #configure-your-mcp-client
26 | [cline]: #configure-your-mcp-client
27 | [claudedesktop]: #configure-your-mcp-client
28 | [claudecode]: #configure-your-mcp-client
29 | [geminicli]: #configure-your-mcp-client
30 | [geminicodeassist]: #configure-your-mcp-client
31 |
32 | ## Set up the database
33 |
34 | 1. [Create or select a Neo4j
35 | instance.](https://neo4j.com/cloud/platform/aura-graph-database/)
36 |
37 | ## Install MCP Toolbox
38 |
39 | 1. Download the latest version of Toolbox as a binary. Select the [correct
40 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
41 | to your OS and CPU architecture. You are required to use Toolbox version
42 | v0.15.0+:
43 |
44 | <!-- {x-release-please-start-version} -->
45 | {{< tabpane persist=header >}}
46 | {{< tab header="linux/amd64" lang="bash" >}}
47 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
48 | {{< /tab >}}
49 |
50 | {{< tab header="darwin/arm64" lang="bash" >}}
51 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
52 | {{< /tab >}}
53 |
54 | {{< tab header="darwin/amd64" lang="bash" >}}
55 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
56 | {{< /tab >}}
57 |
58 | {{< tab header="windows/amd64" lang="bash" >}}
59 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
60 | {{< /tab >}}
61 | {{< /tabpane >}}
62 | <!-- {x-release-please-end} -->
63 |
64 | 1. Make the binary executable:
65 |
66 | ```bash
67 | chmod +x toolbox
68 | ```
69 |
70 | 1. Verify the installation:
71 |
72 | ```bash
73 | ./toolbox --version
74 | ```
75 |
76 | ## Configure your MCP Client
77 |
78 | {{< tabpane text=true >}}
79 | {{% tab header="Claude code" lang="en" %}}
80 |
81 | 1. Install [Claude
82 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
83 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
84 | 1. Add the following configuration, replace the environment variables with your
85 | values, and save:
86 |
87 | ```json
88 | {
89 | "mcpServers": {
90 | "neo4j": {
91 | "command": "./PATH/TO/toolbox",
92 | "args": ["--prebuilt","neo4j","--stdio"],
93 | "env": {
94 | "NEO4J_URI": "",
95 | "NEO4J_DATABASE": "",
96 | "NEO4J_USERNAME": "",
97 | "NEO4J_PASSWORD": ""
98 | }
99 | }
100 | }
101 | }
102 | ```
103 |
104 | 1. Restart Claude code to apply the new configuration.
105 | {{% /tab %}}
106 | {{% tab header="Claude desktop" lang="en" %}}
107 |
108 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
109 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
110 | 1. Add the following configuration, replace the environment variables with your
111 | values, and save:
112 |
113 | ```json
114 | {
115 | "mcpServers": {
116 | "neo4j": {
117 | "command": "./PATH/TO/toolbox",
118 | "args": ["--prebuilt","neo4j","--stdio"],
119 | "env": {
120 | "NEO4J_URI": "",
121 | "NEO4J_DATABASE": "",
122 | "NEO4J_USERNAME": "",
123 | "NEO4J_PASSWORD": ""
124 | }
125 | }
126 | }
127 | }
128 | ```
129 |
130 | 1. Restart Claude desktop.
131 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
132 | new MCP server available.
133 | {{% /tab %}}
134 | {{% tab header="Cline" lang="en" %}}
135 |
136 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and
137 | tap the **MCP Servers** icon.
138 | 1. Tap Configure MCP Servers to open the configuration file.
139 | 1. Add the following configuration, replace the environment variables with your
140 | values, and save:
141 |
142 | ```json
143 | {
144 | "mcpServers": {
145 | "neo4j": {
146 | "command": "./PATH/TO/toolbox",
147 | "args": ["--prebuilt","neo4j","--stdio"],
148 | "env": {
149 | "NEO4J_URI": "",
150 | "NEO4J_DATABASE": "",
151 | "NEO4J_USERNAME": "",
152 | "NEO4J_PASSWORD": ""
153 | }
154 | }
155 | }
156 | }
157 | ```
158 |
159 | 1. You should see a green active status after the server is successfully connected.
160 | {{% /tab %}}
161 | {{% tab header="Cursor" lang="en" %}}
162 |
163 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
164 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
165 | 1. Add the following configuration, replace the environment variables with your values, and save:
166 |
167 | ```json
168 | {
169 | "mcpServers": {
170 | "neo4j": {
171 | "command": "./PATH/TO/toolbox",
172 | "args": ["--prebuilt","neo4j","--stdio"],
173 | "env": {
174 | "NEO4J_URI": "",
175 | "NEO4J_DATABASE": "",
176 | "NEO4J_USERNAME": "",
177 | "NEO4J_PASSWORD": ""
178 | }
179 | }
180 | }
181 | }
182 | ```
183 |
184 | 1. Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
185 | Settings > MCP**. You should see a green active status after the server is
186 | successfully connected.
187 | {{% /tab %}}
188 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
189 |
190 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
191 | create a `.vscode` directory in your project root if it doesn't exist.
192 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
193 | 1. Add the following configuration, replace the environment variables with your
194 | values, and save:
195 |
196 | ```json
197 | {
198 | "mcp" : {
199 | "servers": {
200 | "neo4j": {
201 | "command": "./PATH/TO/toolbox",
202 | "args": ["--prebuilt","neo4j","--stdio"],
203 | "env": {
204 | "NEO4J_URI": "",
205 | "NEO4J_DATABASE": "",
206 | "NEO4J_USERNAME": "",
207 | "NEO4J_PASSWORD": ""
208 | }
209 | }
210 | }
211 | }
212 | }
213 | ```
214 | {{% /tab %}}
215 | {{% tab header="Windsurf" lang="en" %}}
216 |
217 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
218 | Cascade assistant.
219 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
220 | 1. Add the following configuration, replace the environment variables with your
221 | values, and save:
222 |
223 | ```json
224 | {
225 | "mcpServers": {
226 | "neo4j": {
227 | "command": "./PATH/TO/toolbox",
228 | "args": ["--prebuilt","neo4j","--stdio"],
229 | "env": {
230 | "NEO4J_URI": "",
231 | "NEO4J_DATABASE": "",
232 | "NEO4J_USERNAME": "",
233 | "NEO4J_PASSWORD": ""
234 | }
235 | }
236 | }
237 | }
238 | ```
239 | {{% /tab %}}
240 | {{% tab header="Gemini CLI" lang="en" %}}
241 |
242 | 1. Install the [Gemini
243 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
244 | 1. In your working directory, create a folder named `.gemini`. Within it,
245 | create a `settings.json` file.
246 | 1. Add the following configuration, replace the environment variables with your
247 | values, and then save:
248 |
249 | ```json
250 | {
251 | "mcpServers": {
252 | "neo4j": {
253 | "command": "./PATH/TO/toolbox",
254 | "args": ["--prebuilt","neo4j","--stdio"],
255 | "env": {
256 | "NEO4J_URI": "",
257 | "NEO4J_DATABASE": "",
258 | "NEO4J_USERNAME": "",
259 | "NEO4J_PASSWORD": ""
260 | }
261 | }
262 | }
263 | }
264 | ```
265 | {{% /tab %}}
266 | {{% tab header="Gemini Code Assist" lang="en" %}}
267 |
268 | 1. Install the [Gemini Code
269 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
270 | extension in Visual Studio Code.
271 | 1. Enable Agent Mode in Gemini Code Assist chat.
272 | 1. In your working directory, create a folder named `.gemini`. Within it,
273 | create a `settings.json` file.
274 | 1. Add the following configuration, replace the environment variables with your
275 | values, and then save:
276 |
277 | ```json
278 | {
279 | "mcpServers": {
280 | "neo4j": {
281 | "command": "./PATH/TO/toolbox",
282 | "args": ["--prebuilt","neo4j","--stdio"],
283 | "env": {
284 | "NEO4J_URI": "",
285 | "NEO4J_DATABASE": "",
286 | "NEO4J_USERNAME": "",
287 | "NEO4J_PASSWORD": ""
288 | }
289 | }
290 | }
291 | }
292 | ```
293 | {{% /tab %}}
294 | {{< /tabpane >}}
295 |
296 | ## Use Tools
297 |
298 | Your AI tool is now connected to Neo4j using MCP. Try asking your AI assistant
299 | to get the graph schema or execute Cypher statements.
300 |
301 | The following tools are available to the LLM:
302 |
303 | 1. **get_schema**: extracts the complete database schema, including details
304 | about node labels, relationships, properties, constraints, and indexes.
305 | 1. **execute_cypher**: executes any arbitrary Cypher statement.
306 |
307 | {{< notice note >}}
308 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
309 | will adapt to the tools available, so this shouldn't affect most users.
310 | {{< /notice >}}
311 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/mysql_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: MySQL using MCP
3 | type: docs
4 | weight: 2
5 | description: "Connect your IDE to MySQL using Toolbox."
6 | ---
7 |
8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
9 | an open protocol for connecting Large Language Models (LLMs) to data sources
10 | like MySQL. This guide covers how to use [MCP Toolbox for Databases][toolbox] to
11 | expose your developer assistant tools to a MySQL instance:
12 |
13 | * [Cursor][cursor]
14 | * [Windsurf][windsurf] (Codium)
15 | * [Visual Studio Code][vscode] (Copilot)
16 | * [Cline][cline] (VS Code extension)
17 | * [Claude desktop][claudedesktop]
18 | * [Claude code][claudecode]
19 | * [Gemini CLI][geminicli]
20 | * [Gemini Code Assist][geminicodeassist]
21 |
22 | [toolbox]: https://github.com/googleapis/genai-toolbox
23 | [cursor]: #configure-your-mcp-client
24 | [windsurf]: #configure-your-mcp-client
25 | [vscode]: #configure-your-mcp-client
26 | [cline]: #configure-your-mcp-client
27 | [claudedesktop]: #configure-your-mcp-client
28 | [claudecode]: #configure-your-mcp-client
29 | [geminicli]: #configure-your-mcp-client
30 | [geminicodeassist]: #configure-your-mcp-client
31 |
32 | ## Set up the database
33 |
34 | 1. [Create or select a MySQL instance.](https://dev.mysql.com/downloads/installer/)
35 |
36 | ## Install MCP Toolbox
37 |
38 | 1. Download the latest version of Toolbox as a binary. Select the [correct
39 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
40 | to your OS and CPU architecture. You are required to use Toolbox version
41 | V0.10.0+:
42 |
43 | <!-- {x-release-please-start-version} -->
44 | {{< tabpane persist=header >}}
45 | {{< tab header="linux/amd64" lang="bash" >}}
46 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
47 | {{< /tab >}}
48 |
49 | {{< tab header="darwin/arm64" lang="bash" >}}
50 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
51 | {{< /tab >}}
52 |
53 | {{< tab header="darwin/amd64" lang="bash" >}}
54 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
55 | {{< /tab >}}
56 |
57 | {{< tab header="windows/amd64" lang="bash" >}}
58 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
59 | {{< /tab >}}
60 | {{< /tabpane >}}
61 | <!-- {x-release-please-end} -->
62 |
63 | 1. Make the binary executable:
64 |
65 | ```bash
66 | chmod +x toolbox
67 | ```
68 |
69 | 1. Verify the installation:
70 |
71 | ```bash
72 | ./toolbox --version
73 | ```
74 |
75 | ## Configure your MCP Client
76 |
77 | {{< tabpane text=true >}}
78 | {{% tab header="Claude code" lang="en" %}}
79 |
80 | 1. Install [Claude
81 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
82 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
83 | 1. Add the following configuration, replace the environment variables with your
84 | values, and save:
85 |
86 | ```json
87 | {
88 | "mcpServers": {
89 | "mysql": {
90 | "command": "./PATH/TO/toolbox",
91 | "args": ["--prebuilt", "mysql", "--stdio"],
92 | "env": {
93 | "MYSQL_HOST": "",
94 | "MYSQL_PORT": "",
95 | "MYSQL_DATABASE": "",
96 | "MYSQL_USER": "",
97 | "MYSQL_PASSWORD": ""
98 | }
99 | }
100 | }
101 | }
102 | ```
103 |
104 | 1. Restart Claude code to apply the new configuration.
105 | {{% /tab %}}
106 | {{% tab header="Claude desktop" lang="en" %}}
107 |
108 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
109 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
110 | 1. Add the following configuration, replace the environment variables with your
111 | values, and save:
112 |
113 | ```json
114 | {
115 | "mcpServers": {
116 | "mysql": {
117 | "command": "./PATH/TO/toolbox",
118 | "args": ["--prebuilt", "mysql", "--stdio"],
119 | "env": {
120 | "MYSQL_HOST": "",
121 | "MYSQL_PORT": "",
122 | "MYSQL_DATABASE": "",
123 | "MYSQL_USER": "",
124 | "MYSQL_PASSWORD": ""
125 | }
126 | }
127 | }
128 | }
129 | ```
130 |
131 | 1. Restart Claude desktop.
132 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
133 | new MCP server available.
134 | {{% /tab %}}
135 | {{% tab header="Cline" lang="en" %}}
136 |
137 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and
138 | tap the **MCP Servers** icon.
139 | 1. Tap Configure MCP Servers to open the configuration file.
140 | 1. Add the following configuration, replace the environment variables with your
141 | values, and save:
142 |
143 | ```json
144 | {
145 | "mcpServers": {
146 | "mysql": {
147 | "command": "./PATH/TO/toolbox",
148 | "args": ["--prebuilt", "mysql", "--stdio"],
149 | "env": {
150 | "MYSQL_HOST": "",
151 | "MYSQL_PORT": "",
152 | "MYSQL_DATABASE": "",
153 | "MYSQL_USER": "",
154 | "MYSQL_PASSWORD": ""
155 | }
156 | }
157 | }
158 | }
159 | ```
160 |
161 | 1. You should see a green active status after the server is successfully
162 | connected.
163 | {{% /tab %}}
164 | {{% tab header="Cursor" lang="en" %}}
165 |
166 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
167 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
168 | 1. Add the following configuration, replace the environment variables with your
169 | values, and save:
170 |
171 | ```json
172 | {
173 | "mcpServers": {
174 | "mysql": {
175 | "command": "./PATH/TO/toolbox",
176 | "args": ["--prebuilt", "mysql", "--stdio"],
177 | "env": {
178 | "MYSQL_HOST": "",
179 | "MYSQL_PORT": "",
180 | "MYSQL_DATABASE": "",
181 | "MYSQL_USER": "",
182 | "MYSQL_PASSWORD": ""
183 | }
184 | }
185 | }
186 | }
187 | ```
188 |
189 | 1. Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
190 | Settings > MCP**. You should see a green active status after the server is
191 | successfully connected.
192 | {{% /tab %}}
193 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
194 |
195 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
196 | create a `.vscode` directory in your project root if it doesn't exist.
197 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
198 | 1. Add the following configuration, replace the environment variables with your
199 | values, and save:
200 |
201 | ```json
202 | {
203 | "servers": {
204 | "mysql": {
205 | "command": "./PATH/TO/toolbox",
206 | "args": ["--prebuilt","mysql","--stdio"],
207 | "env": {
208 | "MYSQL_HOST": "",
209 | "MYSQL_PORT": "",
210 | "MYSQL_DATABASE": "",
211 | "MYSQL_USER": "",
212 | "MYSQL_PASSWORD": ""
213 | }
214 | }
215 | }
216 | }
217 | ```
218 | {{% /tab %}}
219 | {{% tab header="Windsurf" lang="en" %}}
220 |
221 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
222 | Cascade assistant.
223 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
224 | 1. Add the following configuration, replace the environment variables with your
225 | values, and save:
226 |
227 | ```json
228 | {
229 | "mcpServers": {
230 | "mysql": {
231 | "command": "./PATH/TO/toolbox",
232 | "args": ["--prebuilt","mysql","--stdio"],
233 | "env": {
234 | "MYSQL_HOST": "",
235 | "MYSQL_PORT": "",
236 | "MYSQL_DATABASE": "",
237 | "MYSQL_USER": "",
238 | "MYSQL_PASSWORD": ""
239 | }
240 | }
241 | }
242 | }
243 | ```
244 | {{% /tab %}}
245 | {{% tab header="Gemini CLI" lang="en" %}}
246 |
247 | 1. Install the [Gemini
248 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
249 | 1. In your working directory, create a folder named `.gemini`. Within it,
250 | create a `settings.json` file.
251 | 1. Add the following configuration, replace the environment variables with your
252 | values, and then save:
253 |
254 | ```json
255 | {
256 | "mcpServers": {
257 | "mysql": {
258 | "command": "./PATH/TO/toolbox",
259 | "args": ["--prebuilt","mysql","--stdio"],
260 | "env": {
261 | "MYSQL_HOST": "",
262 | "MYSQL_PORT": "",
263 | "MYSQL_DATABASE": "",
264 | "MYSQL_USER": "",
265 | "MYSQL_PASSWORD": ""
266 | }
267 | }
268 | }
269 | }
270 | ```
271 | {{% /tab %}}
272 | {{% tab header="Gemini Code Assist" lang="en" %}}
273 |
274 | 1. Install the [Gemini Code
275 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
276 | extension in Visual Studio Code.
277 | 1. Enable Agent Mode in Gemini Code Assist chat.
278 | 1. In your working directory, create a folder named `.gemini`. Within it,
279 | create a `settings.json` file.
280 | 1. Add the following configuration, replace the environment variables with your
281 | values, and then save:
282 |
283 | ```json
284 | {
285 | "mcpServers": {
286 | "mysql": {
287 | "command": "./PATH/TO/toolbox",
288 | "args": ["--prebuilt","mysql","--stdio"],
289 | "env": {
290 | "MYSQL_HOST": "",
291 | "MYSQL_PORT": "",
292 | "MYSQL_DATABASE": "",
293 | "MYSQL_USER": "",
294 | "MYSQL_PASSWORD": ""
295 | }
296 | }
297 | }
298 | }
299 | ```
300 | {{% /tab %}}
301 | {{< /tabpane >}}
302 |
303 | ## Use Tools
304 |
305 | Your AI tool is now connected to MySQL using MCP. Try asking your AI assistant
306 | to list tables, create a table, or define and execute other SQL statements.
307 |
308 | The following tools are available to the LLM:
309 |
310 | 1. **list_tables**: lists tables and descriptions
311 | 1. **execute_sql**: execute any SQL statement
312 |
313 | {{< notice note >}}
314 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
315 | will adapt to the tools available, so this shouldn't affect most users.
316 | {{< /notice >}}
317 |
```
--------------------------------------------------------------------------------
/docs/en/how-to/connect-ide/mssql_mcp.md:
--------------------------------------------------------------------------------
```markdown
1 | ---
2 | title: SQL Server using MCP
3 | type: docs
4 | weight: 2
5 | description: "Connect your IDE to SQL Server using Toolbox."
6 | ---
7 |
8 | [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is
9 | an open protocol for connecting Large Language Models (LLMs) to data sources
10 | like SQL Server. This guide covers how to use [MCP Toolbox for
11 | Databases][toolbox] to expose your developer assistant tools to a SQL Server
12 | instance:
13 |
14 | * [Cursor][cursor]
15 | * [Windsurf][windsurf] (Codium)
16 | * [Visual Studio Code][vscode] (Copilot)
17 | * [Cline][cline] (VS Code extension)
18 | * [Claude desktop][claudedesktop]
19 | * [Claude code][claudecode]
20 | * [Gemini CLI][geminicli]
21 | * [Gemini Code Assist][geminicodeassist]
22 |
23 | [toolbox]: https://github.com/googleapis/genai-toolbox
24 | [cursor]: #configure-your-mcp-client
25 | [windsurf]: #configure-your-mcp-client
26 | [vscode]: #configure-your-mcp-client
27 | [cline]: #configure-your-mcp-client
28 | [claudedesktop]: #configure-your-mcp-client
29 | [claudecode]: #configure-your-mcp-client
30 | [geminicli]: #configure-your-mcp-client
31 | [geminicodeassist]: #configure-your-mcp-client
32 |
33 | ## Set up the database
34 |
35 | 1. [Create or select a SQL Server
36 | instance.](https://www.microsoft.com/en-us/sql-server/sql-server-downloads)
37 |
38 | ## Install MCP Toolbox
39 |
40 | 1. Download the latest version of Toolbox as a binary. Select the [correct
41 | binary](https://github.com/googleapis/genai-toolbox/releases) corresponding
42 | to your OS and CPU architecture. You are required to use Toolbox version
43 | V0.10.0+:
44 |
45 | <!-- {x-release-please-start-version} -->
46 | {{< tabpane persist=header >}}
47 | {{< tab header="linux/amd64" lang="bash" >}}
48 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/linux/amd64/toolbox
49 | {{< /tab >}}
50 |
51 | {{< tab header="darwin/arm64" lang="bash" >}}
52 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/arm64/toolbox
53 | {{< /tab >}}
54 |
55 | {{< tab header="darwin/amd64" lang="bash" >}}
56 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/darwin/amd64/toolbox
57 | {{< /tab >}}
58 |
59 | {{< tab header="windows/amd64" lang="bash" >}}
60 | curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/windows/amd64/toolbox.exe
61 | {{< /tab >}}
62 | {{< /tabpane >}}
63 | <!-- {x-release-please-end} -->
64 |
65 | 1. Make the binary executable:
66 |
67 | ```bash
68 | chmod +x toolbox
69 | ```
70 |
71 | 1. Verify the installation:
72 |
73 | ```bash
74 | ./toolbox --version
75 | ```
76 |
77 | ## Configure your MCP Client
78 |
79 | {{< tabpane text=true >}}
80 | {{% tab header="Claude code" lang="en" %}}
81 |
82 | 1. Install [Claude
83 | Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
84 | 1. Create a `.mcp.json` file in your project root if it doesn't exist.
85 | 1. Add the following configuration, replace the environment variables with your
86 | values, and save:
87 |
88 | ```json
89 | {
90 | "mcpServers": {
91 | "sqlserver": {
92 | "command": "./PATH/TO/toolbox",
93 | "args": ["--prebuilt","mssql","--stdio"],
94 | "env": {
95 | "MSSQL_HOST": "",
96 | "MSSQL_PORT": "",
97 | "MSSQL_DATABASE": "",
98 | "MSSQL_USER": "",
99 | "MSSQL_PASSWORD": ""
100 | }
101 | }
102 | }
103 | }
104 | ```
105 |
106 | 1. Restart Claude code to apply the new configuration.
107 | {{% /tab %}}
108 | {{% tab header="Claude desktop" lang="en" %}}
109 |
110 | 1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
111 | 1. Under the Developer tab, tap Edit Config to open the configuration file.
112 | 1. Add the following configuration, replace the environment variables with your
113 | values, and save:
114 |
115 | ```json
116 | {
117 | "mcpServers": {
118 | "sqlserver": {
119 | "command": "./PATH/TO/toolbox",
120 | "args": ["--prebuilt","mssql","--stdio"],
121 | "env": {
122 | "MSSQL_HOST": "",
123 | "MSSQL_PORT": "",
124 | "MSSQL_DATABASE": "",
125 | "MSSQL_USER": "",
126 | "MSSQL_PASSWORD": ""
127 | }
128 | }
129 | }
130 | }
131 | ```
132 |
133 | 1. Restart Claude desktop.
134 | 1. From the new chat screen, you should see a hammer (MCP) icon appear with the
135 | new MCP server available.
136 | {{% /tab %}}
137 | {{% tab header="Cline" lang="en" %}}
138 |
139 | 1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and
140 | tap the **MCP Servers** icon.
141 | 1. Tap Configure MCP Servers to open the configuration file.
142 | 1. Add the following configuration, replace the environment variables with your
143 | values, and save:
144 |
145 | ```json
146 | {
147 | "mcpServers": {
148 | "sqlserver": {
149 | "command": "./PATH/TO/toolbox",
150 | "args": ["--prebuilt","mssql","--stdio"],
151 | "env": {
152 | "MSSQL_HOST": "",
153 | "MSSQL_PORT": "",
154 | "MSSQL_DATABASE": "",
155 | "MSSQL_USER": "",
156 | "MSSQL_PASSWORD": ""
157 | }
158 | }
159 | }
160 | }
161 | ```
162 |
163 | 1. You should see a green active status after the server is successfully
164 | connected.
165 | {{% /tab %}}
166 | {{% tab header="Cursor" lang="en" %}}
167 |
168 | 1. Create a `.cursor` directory in your project root if it doesn't exist.
169 | 1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
170 | 1. Add the following configuration, replace the environment variables with your
171 | values, and save:
172 |
173 | ```json
174 | {
175 | "mcpServers": {
176 | "sqlserver": {
177 | "command": "./PATH/TO/toolbox",
178 | "args": ["--prebuilt","mssql","--stdio"],
179 | "env": {
180 | "MSSQL_HOST": "",
181 | "MSSQL_PORT": "",
182 | "MSSQL_DATABASE": "",
183 | "MSSQL_USER": "",
184 | "MSSQL_PASSWORD": ""
185 | }
186 | }
187 | }
188 | }
189 | ```
190 |
191 | 1. Open [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor
192 | Settings > MCP**. You should see a green active status after the server is
193 | successfully connected.
194 | {{% /tab %}}
195 | {{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
196 |
197 | 1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and
198 | create a `.vscode` directory in your project root if it doesn't exist.
199 | 1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
200 | 1. Add the following configuration, replace the environment variables with your
201 | values, and save:
202 |
203 | ```json
204 | {
205 | "servers": {
206 | "mssql": {
207 | "command": "./PATH/TO/toolbox",
208 | "args": ["--prebuilt","mssql","--stdio"],
209 | "env": {
210 | "MSSQL_HOST": "",
211 | "MSSQL_PORT": "",
212 | "MSSQL_DATABASE": "",
213 | "MSSQL_USER": "",
214 | "MSSQL_PASSWORD": ""
215 | }
216 | }
217 | }
218 | }
219 | ```
220 | {{% /tab %}}
221 | {{% tab header="Windsurf" lang="en" %}}
222 |
223 | 1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the
224 | Cascade assistant.
225 | 1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
226 | 1. Add the following configuration, replace the environment variables with your
227 | values, and save:
228 |
229 | ```json
230 | {
231 | "mcpServers": {
232 | "sqlserver": {
233 | "command": "./PATH/TO/toolbox",
234 | "args": ["--prebuilt","mssql","--stdio"],
235 | "env": {
236 | "MSSQL_HOST": "",
237 | "MSSQL_PORT": "",
238 | "MSSQL_DATABASE": "",
239 | "MSSQL_USER": "",
240 | "MSSQL_PASSWORD": ""
241 | }
242 | }
243 | }
244 | }
245 | ```
246 | {{% /tab %}}
247 | {{% tab header="Gemini CLI" lang="en" %}}
248 |
249 | 1. Install the [Gemini
250 | CLI](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#quickstart).
251 | 1. In your working directory, create a folder named `.gemini`. Within it,
252 | create a `settings.json` file.
253 | 1. Add the following configuration, replace the environment variables with your
254 | values, and then save:
255 |
256 | ```json
257 | {
258 | "mcpServers": {
259 | "sqlserver": {
260 | "command": "./PATH/TO/toolbox",
261 | "args": ["--prebuilt","mssql","--stdio"],
262 | "env": {
263 | "MSSQL_HOST": "",
264 | "MSSQL_PORT": "",
265 | "MSSQL_DATABASE": "",
266 | "MSSQL_USER": "",
267 | "MSSQL_PASSWORD": ""
268 | }
269 | }
270 | }
271 | }
272 | ```
273 | {{% /tab %}}
274 | {{% tab header="Gemini Code Assist" lang="en" %}}
275 |
276 | 1. Install the [Gemini Code
277 | Assist](https://marketplace.visualstudio.com/items?itemName=Google.geminicodeassist)
278 | extension in Visual Studio Code.
279 | 1. Enable Agent Mode in Gemini Code Assist chat.
280 | 1. In your working directory, create a folder named `.gemini`. Within it,
281 | create a `settings.json` file.
282 | 1. Add the following configuration, replace the environment variables with your
283 | values, and then save:
284 |
285 | ```json
286 | {
287 | "mcpServers": {
288 | "sqlserver": {
289 | "command": "./PATH/TO/toolbox",
290 | "args": ["--prebuilt","mssql","--stdio"],
291 | "env": {
292 | "MSSQL_HOST": "",
293 | "MSSQL_PORT": "",
294 | "MSSQL_DATABASE": "",
295 | "MSSQL_USER": "",
296 | "MSSQL_PASSWORD": ""
297 | }
298 | }
299 | }
300 | }
301 | ```
302 | {{% /tab %}}
303 | {{< /tabpane >}}
304 |
305 | ## Use Tools
306 |
307 | Your AI tool is now connected to SQL Server using MCP. Try asking your AI
308 | assistant to list tables, create a table, or define and execute other SQL
309 | statements.
310 |
311 | The following tools are available to the LLM:
312 |
313 | 1. **list_tables**: lists tables and descriptions
314 | 1. **execute_sql**: execute any SQL statement
315 |
316 | {{< notice note >}}
317 | Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs
318 | will adapt to the tools available, so this shouldn't affect most users.
319 | {{< /notice >}}
320 |
```