Compare commits

...

58 Commits

Author SHA1 Message Date
Wenxin Du
e26368b88e Merge branch 'main' into blog 2025-06-23 12:57:35 -04:00
duwenxin
1d5a8986e2 rename file 2025-06-23 12:57:16 -04:00
Wenxin Du
7b571b17e3 Update docs/en/about/contactus.md
Co-authored-by: Averi Kitsch <akitsch@google.com>
2025-06-23 12:55:36 -04:00
Wenxin Du
c2b3f5df19 Update docs/en/about/contactus.md
Co-authored-by: Averi Kitsch <akitsch@google.com>
2025-06-23 12:55:28 -04:00
Wenxin Du
1d658c3b14 docs: Add guide for writing integration tests (#737)
Detailed instruction for writing integration tests.
2025-06-23 09:36:46 -07:00
duwenxin
1dd567f430 nit 2025-06-20 19:44:44 -04:00
duwenxin
6c13e8fa9b docs: Add blogs and contacts instruction to doc page 2025-06-20 19:42:22 -04:00
Wenxin Du
fd300dc606 feat: Add support for HTTP Tool pathParams (#726)
Allow users to specify dynamic path for HTTP tools.

fix: https://github.com/googleapis/genai-toolbox/issues/680
2025-06-20 14:53:49 -04:00
Yuan
4827771b78 feat: add support for optional parameters (#617)
Add a `default` field to parameters, that enables users to specify a
default value.

e.g.

```
  parameters:
    - name: name
      type: string
      default: "some-default-value"
      description: The name of the hotel.
```
if this parameter is invoked without specifying `name`, the parameter
would default to "some-default-value"


For parameter manifest, there will be an additional `Required` field.
The default `Required` field is true. If a `default` value is presented,
`Required: false`. Array parameter's item's `Required` field will
inherit the array's `Required` field.

Fixes #475
2025-06-20 10:46:59 -07:00
dependabot[bot]
a8df414b11 chore(deps): bump github.com/go-chi/chi/v5 from 5.2.1 to 5.2.2 (#734)
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from
5.2.1 to 5.2.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/go-chi/chi/releases">github.com/go-chi/chi/v5's
releases</a>.</em></p>
<blockquote>
<h2>v5.2.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Use strings.Cut in a few places by <a
href="https://github.com/JRaspass"><code>@​JRaspass</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/971">go-chi/chi#971</a></li>
<li>Fix non-constant format strings in t.Fatalf by <a
href="https://github.com/JRaspass"><code>@​JRaspass</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/972">go-chi/chi#972</a></li>
<li>Apply fieldalignment fixes to optimize struct memory layout by <a
href="https://github.com/pixel365"><code>@​pixel365</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/974">go-chi/chi#974</a></li>
<li>go 1.24 by <a
href="https://github.com/pkieltyka"><code>@​pkieltyka</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/977">go-chi/chi#977</a></li>
<li>chore: delint ioutil usage by <a
href="https://github.com/costela"><code>@​costela</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/962">go-chi/chi#962</a></li>
<li>Fixed typo in Router interface definition by <a
href="https://github.com/mithileshgupta12"><code>@​mithileshgupta12</code></a>
in <a
href="https://redirect.github.com/go-chi/chi/pull/958">go-chi/chi#958</a></li>
<li>Add support for TinyGo by <a
href="https://github.com/efraimbart"><code>@​efraimbart</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/978">go-chi/chi#978</a></li>
<li>Exclude middleware/profiler.go in TinyGo, as there's no
net/http/pprof pkg by <a
href="https://github.com/cxjava"><code>@​cxjava</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/982">go-chi/chi#982</a></li>
<li>Make use of strings.Cut by <a
href="https://github.com/scop"><code>@​scop</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/1005">go-chi/chi#1005</a></li>
<li>Change install command format to code block by <a
href="https://github.com/sglkc"><code>@​sglkc</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/1001">go-chi/chi#1001</a></li>
<li>Correct documentation by <a
href="https://github.com/mrdomino"><code>@​mrdomino</code></a> in <a
href="https://redirect.github.com/go-chi/chi/pull/992">go-chi/chi#992</a></li>
</ul>
<h2>Security fix</h2>
<ul>
<li>Fixes <a
href="https://github.com/go-chi/chi/security/advisories/GHSA-vrw8-fxc6-2r93">GHSA-vrw8-fxc6-2r93</a>
- &quot;Host Header Injection Leads to Open Redirect in
RedirectSlashes&quot; <a
href="1be7ad938c">commit</a>
<ul>
<li>a lower-severity Open Redirect that can't be exploited in browser or
email client, as it requires manipulation of a Host header</li>
<li>reported by Anuraag Baishya, <a
href="https://github.com/anuraagbaishya"><code>@​anuraagbaishya</code></a>.
Thank you!</li>
</ul>
</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/pixel365"><code>@​pixel365</code></a>
made their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/974">go-chi/chi#974</a></li>
<li><a
href="https://github.com/mithileshgupta12"><code>@​mithileshgupta12</code></a>
made their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/958">go-chi/chi#958</a></li>
<li><a
href="https://github.com/efraimbart"><code>@​efraimbart</code></a> made
their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/978">go-chi/chi#978</a></li>
<li><a href="https://github.com/cxjava"><code>@​cxjava</code></a> made
their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/982">go-chi/chi#982</a></li>
<li><a href="https://github.com/sglkc"><code>@​sglkc</code></a> made
their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/1001">go-chi/chi#1001</a></li>
<li><a href="https://github.com/mrdomino"><code>@​mrdomino</code></a>
made their first contribution in <a
href="https://redirect.github.com/go-chi/chi/pull/992">go-chi/chi#992</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/go-chi/chi/compare/v5.2.1...v5.2.2">https://github.com/go-chi/chi/compare/v5.2.1...v5.2.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="23c395f852"><code>23c395f</code></a>
Correct documentation (<a
href="https://redirect.github.com/go-chi/chi/issues/992">#992</a>)</li>
<li><a
href="5516d147c1"><code>5516d14</code></a>
docs: change install code to code block (<a
href="https://redirect.github.com/go-chi/chi/issues/1001">#1001</a>)</li>
<li><a
href="e235052c10"><code>e235052</code></a>
Make use of strings.Cut (<a
href="https://redirect.github.com/go-chi/chi/issues/1005">#1005</a>)</li>
<li><a
href="1be7ad938c"><code>1be7ad9</code></a>
Merge commit from fork</li>
<li><a
href="d7034fdfda"><code>d7034fd</code></a>
Exclude profiler when use tinygo (<a
href="https://redirect.github.com/go-chi/chi/issues/982">#982</a>)</li>
<li><a
href="d04703412f"><code>d047034</code></a>
support tinygo (<a
href="https://redirect.github.com/go-chi/chi/issues/978">#978</a>)</li>
<li><a
href="fe2c065bc0"><code>fe2c065</code></a>
Fixed the typo (<a
href="https://redirect.github.com/go-chi/chi/issues/958">#958</a>)</li>
<li><a
href="1aae5b2d2d"><code>1aae5b2</code></a>
chore: delint ioutil usage (<a
href="https://redirect.github.com/go-chi/chi/issues/962">#962</a>)</li>
<li><a
href="c6225e35a4"><code>c6225e3</code></a>
go 1.24 (<a
href="https://redirect.github.com/go-chi/chi/issues/977">#977</a>)</li>
<li><a
href="e846b8304c"><code>e846b83</code></a>
Apply fieldalignment fixes to optimize struct memory layout (<a
href="https://redirect.github.com/go-chi/chi/issues/974">#974</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/go-chi/chi/compare/v5.2.1...v5.2.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/go-chi/chi/v5&package-manager=go_modules&previous-version=5.2.1&new-version=5.2.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/googleapis/genai-toolbox/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-20 17:29:12 +00:00
Yuan
0bf4ebabf1 ci: increase releases vCPU (#731)
As Toolbox add more dependencies, the release time is taking longer (due
to longer binary building time). This PR increases vCPU for the
continuous release and versioned release.
2025-06-19 23:14:51 -07:00
Yuan
67964d939f fix(postgres,mssql,cloudsqlmssql)!: encode source connection url for sources (#727)
Have to encode special character in connection url. Only needed for
`postgres`, `mssql`, `cloud-sql-mssql` sources.

Fixes #717
2025-06-18 15:32:46 -07:00
Mend Renovate
f77c829271 chore(deps): update module google.golang.org/api to v0.238.0 (#728)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[google.golang.org/api](https://redirect.github.com/googleapis/google-api-go-client)
| `v0.237.0` -> `v0.238.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/google.golang.org%2fapi/v0.238.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/google.golang.org%2fapi/v0.238.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/google.golang.org%2fapi/v0.237.0/v0.238.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/google.golang.org%2fapi/v0.237.0/v0.238.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>googleapis/google-api-go-client
(google.golang.org/api)</summary>

###
[`v0.238.0`](https://redirect.github.com/googleapis/google-api-go-client/releases/tag/v0.238.0)

[Compare
Source](https://redirect.github.com/googleapis/google-api-go-client/compare/v0.237.0...v0.238.0)

##### Features

- **all:** Auto-regenerate discovery clients
([#&#8203;3192](https://redirect.github.com/googleapis/google-api-go-client/issues/3192))
([3ad3118](3ad311895f))
- **all:** Auto-regenerate discovery clients
([#&#8203;3196](https://redirect.github.com/googleapis/google-api-go-client/issues/3196))
([8cb55ce](8cb55ce504))
- **all:** Auto-regenerate discovery clients
([#&#8203;3197](https://redirect.github.com/googleapis/google-api-go-client/issues/3197))
([98994c4](98994c4004))
- **all:** Auto-regenerate discovery clients
([#&#8203;3198](https://redirect.github.com/googleapis/google-api-go-client/issues/3198))
([5824597](582459736e))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNjAuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-18 21:52:47 +00:00
Mend Renovate
d2977ed1ba chore(deps): update module github.com/googlecloudplatform/opentelemetry-operations-go/exporter/metric to v0.53.0 (#729)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go)
| `v0.52.0` -> `v0.53.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2fmetric/v0.53.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2fmetric/v0.53.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2fmetric/v0.52.0/v0.53.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2fmetric/v0.52.0/v0.53.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>GoogleCloudPlatform/opentelemetry-operations-go
(github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric)</summary>

###
[`v0.53.0`](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go/releases/tag/v0.53.0):
v1.29.0/v0.53.0

[Compare
Source](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go/compare/v0.52.0...v0.53.0)

##### What's Changed

- exporter/metric: add WithMetricClient option by
[@&#8203;enocom](https://redirect.github.com/enocom) in
[https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1033](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1033)
- go.mod: use go 1.23 by
[@&#8203;braydonk](https://redirect.github.com/braydonk) in
[https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1048](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1048)

##### New Contributors

- [@&#8203;enocom](https://redirect.github.com/enocom) made their first
contribution in
[https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1033](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go/pull/1033)

**Full Changelog**:
https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/compare/v0.52.0...v0.53.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42MC4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjAuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-18 21:47:07 +00:00
Mend Renovate
52e8bf4de1 chore(deps): update module github.com/googlecloudplatform/opentelemetry-operations-go/exporter/trace to v1.29.0 (#730)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace](https://redirect.github.com/GoogleCloudPlatform/opentelemetry-operations-go)
| `v1.28.0` -> `v1.29.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2ftrace/v1.29.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2ftrace/v1.29.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2ftrace/v1.28.0/v1.29.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fGoogleCloudPlatform%2fopentelemetry-operations-go%2fexporter%2ftrace/v1.28.0/v1.29.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC42MC4xIiwidXBkYXRlZEluVmVyIjoiNDAuNjAuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-18 21:40:08 +00:00
Yuan
a3aaf93525 docs: update template parameter docs for tools (#706)
documentation for #535
2025-06-18 14:34:41 -07:00
AlexTalreja
9197186b8b feat(tools/couchbase): add templateParameters field for couchbase (#723)
Add templateParameters to support non-filter parameters and DDL
statements.

Part of https://github.com/googleapis/genai-toolbox/issues/535
2025-06-18 21:27:41 +00:00
Yuan
e3844ff76d ci: add macos and windows unit tests (#675) 2025-06-18 14:22:00 -07:00
Yuan
ef6e3f1c32 chore: support linux/arm64 platform for Docker (#724)
Built Toolbox as a multi-platform container.

Fix #686
2025-06-18 18:49:00 +00:00
Yuan
f5f771b0f3 feat(tools/bigquery): add templateParameters field for bigquery (#699)
Add templateParameters to support non-filter parameters and DDL
statements.

Part of #535
2025-06-18 10:19:23 -07:00
Yuan
12b6636a9b refactor: update template param integration test to use options (#707) 2025-06-18 17:00:47 +00:00
Yuan
d51dbc759b fix: do not listen from port for stdio (#719)
Fix #711
2025-06-17 11:35:04 -07:00
Wenxin Du
4055b0c356 feat: Support disable SSL verification for HTTP Source (#674)
Fix issue: https://github.com/googleapis/genai-toolbox/issues/661
2025-06-16 17:22:09 -04:00
Yuan
65dba4cabc chore: update to get version from ServerConfig (#718) 2025-06-16 11:26:51 -07:00
Mend Renovate
447cda2daf chore(deps): update module google.golang.org/api to v0.237.0 (#710)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[google.golang.org/api](https://redirect.github.com/googleapis/google-api-go-client)
| `v0.236.0` -> `v0.237.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/google.golang.org%2fapi/v0.237.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/google.golang.org%2fapi/v0.237.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/google.golang.org%2fapi/v0.236.0/v0.237.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/google.golang.org%2fapi/v0.236.0/v0.237.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>googleapis/google-api-go-client
(google.golang.org/api)</summary>

###
[`v0.237.0`](https://redirect.github.com/googleapis/google-api-go-client/releases/tag/v0.237.0)

[Compare
Source](https://redirect.github.com/googleapis/google-api-go-client/compare/v0.236.0...v0.237.0)

##### Features

- **all:** Auto-regenerate discovery clients
([#&#8203;3182](https://redirect.github.com/googleapis/google-api-go-client/issues/3182))
([bb1dc77](bb1dc7764b))
- **all:** Auto-regenerate discovery clients
([#&#8203;3184](https://redirect.github.com/googleapis/google-api-go-client/issues/3184))
([7c6dc44](7c6dc440ad))
- **all:** Auto-regenerate discovery clients
([#&#8203;3185](https://redirect.github.com/googleapis/google-api-go-client/issues/3185))
([ea78c84](ea78c84457))
- **all:** Auto-regenerate discovery clients
([#&#8203;3186](https://redirect.github.com/googleapis/google-api-go-client/issues/3186))
([5f2f220](5f2f220ef6))
- **all:** Auto-regenerate discovery clients
([#&#8203;3187](https://redirect.github.com/googleapis/google-api-go-client/issues/3187))
([ec0e2c4](ec0e2c41f2))
- **all:** Auto-regenerate discovery clients
([#&#8203;3189](https://redirect.github.com/googleapis/google-api-go-client/issues/3189))
([a03f9f0](a03f9f0966))
- **all:** Auto-regenerate discovery clients
([#&#8203;3190](https://redirect.github.com/googleapis/google-api-go-client/issues/3190))
([0022bde](0022bde6ee))
- **all:** Auto-regenerate discovery clients
([#&#8203;3191](https://redirect.github.com/googleapis/google-api-go-client/issues/3191))
([1540497](1540497246))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-13 14:05:16 -07:00
Mend Renovate
c54ef61fc6 chore(deps): update module github.com/go-sql-driver/mysql to v1.9.3 (#709)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[github.com/go-sql-driver/mysql](https://redirect.github.com/go-sql-driver/mysql)
| `v1.9.2` -> `v1.9.3` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgo-sql-driver%2fmysql/v1.9.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fgo-sql-driver%2fmysql/v1.9.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fgo-sql-driver%2fmysql/v1.9.2/v1.9.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgo-sql-driver%2fmysql/v1.9.2/v1.9.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>go-sql-driver/mysql (github.com/go-sql-driver/mysql)</summary>

###
[`v1.9.3`](https://redirect.github.com/go-sql-driver/mysql/releases/tag/v1.9.3)

[Compare
Source](https://redirect.github.com/go-sql-driver/mysql/compare/v1.9.2...v1.9.3)

#### What's Changed

- \[1.9] test stability improvement. by
[@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1699](https://redirect.github.com/go-sql-driver/mysql/pull/1699)
- \[1.9] Transaction Commit/Rollback returns conn's cached error by
[@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1702](https://redirect.github.com/go-sql-driver/mysql/pull/1702)
- backport benchmark_test by
[@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1706](https://redirect.github.com/go-sql-driver/mysql/pull/1706)
- \[1.9] optimize readPacket
([#&#8203;1705](https://redirect.github.com/go-sql-driver/mysql/issues/1705))
by [@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1707](https://redirect.github.com/go-sql-driver/mysql/pull/1707)
- \[1.9] fix PING on compressed connections by
[@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1723](https://redirect.github.com/go-sql-driver/mysql/pull/1723)
- release v1.9.3 by
[@&#8203;methane](https://redirect.github.com/methane) in
[https://github.com/go-sql-driver/mysql/pull/1725](https://redirect.github.com/go-sql-driver/mysql/pull/1725)

**Full Changelog**:
https://github.com/go-sql-driver/mysql/compare/v1.9.2...v1.9.3

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-13 17:42:24 +00:00
Mend Renovate
eb98cdc7d1 chore(deps): update module github.com/redis/go-redis/v9 to v9.10.0 (#700)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[github.com/redis/go-redis/v9](https://redirect.github.com/redis/go-redis)
| `v9.9.0` -> `v9.10.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fredis%2fgo-redis%2fv9/v9.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/github.com%2fredis%2fgo-redis%2fv9/v9.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/github.com%2fredis%2fgo-redis%2fv9/v9.9.0/v9.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fredis%2fgo-redis%2fv9/v9.9.0/v9.10.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>redis/go-redis (github.com/redis/go-redis/v9)</summary>

###
[`v9.10.0`](https://redirect.github.com/redis/go-redis/releases/tag/v9.10.0):
9.10.0

[Compare
Source](https://redirect.github.com/redis/go-redis/compare/v9.9.0...v9.10.0)

Experimental support for [vector
sets](https://redis.io/docs/latest/develop/data-types/vector-sets/)!

#### 🚀 Highlights

`go-redis` now supports [vector
sets](https://redis.io/docs/latest/develop/data-types/vector-sets/).
This data type is marked as "in preview" in Redis and its support in
`go-redis` is marked as experimental. You can find examples in the
documentation and in the `doctests` folder.

### Changes

#### 🚀 New Features

- feat: support vectorset
([#&#8203;3375](https://redirect.github.com/redis/go-redis/pull/3375))
[@&#8203;fukua95](https://redirect.github.com/fukua95)

#### 🧰 Maintenance

- Add the missing NewFloatSliceResult for testing
([#&#8203;3393](https://redirect.github.com/redis/go-redis/pull/3393))
- DOC-5078 vector set examples
([#&#8203;3394](https://redirect.github.com/redis/go-redis/pull/3394))

#### Contributors

We'd like to thank all the contributors who worked on this release!


[@&#8203;AndBobsYourUncle](https://redirect.github.com/AndBobsYourUncle),
[@&#8203;andy-stark-redis](https://redirect.github.com/andy-stark-redis),
[@&#8203;fukua95](https://redirect.github.com/fukua95) and
[@&#8203;ndyakov](https://redirect.github.com/ndyakov)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40OC41IiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-12 14:38:03 -07:00
Yuan
1c067715fa feat(tools/bigtable): add templateParameters field for bigtable (#692)
Add templateParameters to support non-filter parameters and DDL
statements.

Added a new argument `ignoreInsert` at integration test. Bigtable only
allow `SELECT` statement. This is used to filter insert statement for
bigtable.

Part of #535
2025-06-12 21:18:32 +00:00
Averi Kitsch
cb87f765a6 docs: redirect dev assist docs to official cloud documentation (#676) 2025-06-12 21:09:51 +00:00
Kurtis Van Gent
a982314900 chore(ci/cd): add bigquery folks to blunderbuss (#705)
Adds the BigQuery folks to the blunderbuss config. Blunderbuss will
randomly assign one of the listed folks when 'product: bigquery' label
is added.
2025-06-12 14:56:18 -06:00
Wenxin Du
054ec198b9 feat: Add Valkey Source and Tool (#532) 2025-06-11 23:17:32 -04:00
Wenxin Du
f0aef29b0c feat: Add Redis Source and Tool (#519)
1. Added Redis Source and Tool
2. Moved some integration test helpers from tools.go to common.go
3. Make auth integration test want an input variable
2025-06-11 22:47:27 -04:00
Yuan
075dfa47e1 feat(tools/spanner): add templateParameters field for spanner (#691)
Add `templateParameters` to support non-filter parameters and DDL
statements.

Added a new argument `ignoreDdl` at integration test. Admin client is
needed to execute ddl statement in spanner. Toolbox does not use admin
client.

Part of #535
2025-06-11 23:54:13 +00:00
Mend Renovate
ad62d14cd5 chore(deps): update module cloud.google.com/go/cloudsqlconn to v1.17.2 (#694)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[cloud.google.com/go/cloudsqlconn](https://redirect.github.com/googlecloudplatform/cloud-sql-go-connector)
| `v1.17.1` -> `v1.17.2` |
[![age](https://developer.mend.io/api/mc/badges/age/go/cloud.google.com%2fgo%2fcloudsqlconn/v1.17.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/cloud.google.com%2fgo%2fcloudsqlconn/v1.17.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/cloud.google.com%2fgo%2fcloudsqlconn/v1.17.1/v1.17.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/cloud.google.com%2fgo%2fcloudsqlconn/v1.17.1/v1.17.2?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>googlecloudplatform/cloud-sql-go-connector
(cloud.google.com/go/cloudsqlconn)</summary>

###
[`v1.17.2`](https://redirect.github.com/GoogleCloudPlatform/cloud-sql-go-connector/releases/tag/v1.17.2)

[Compare
Source](https://redirect.github.com/googlecloudplatform/cloud-sql-go-connector/compare/v1.17.1...v1.17.2)

##### Bug Fixes

- reduce the number of memory allocations and the latency overhead.
([#&#8203;983](https://redirect.github.com/GoogleCloudPlatform/cloud-sql-go-connector/issues/983))
([cb641f2](cb641f223e))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40OC41IiwidXBkYXRlZEluVmVyIjoiNDAuNDguNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-11 21:40:22 +00:00
Wenxin Du
5d183b0efe ci: Enable label-controlled docs preview (#516)
Allow external contributors to preview doc changes
2025-06-11 17:33:36 -04:00
Mend Renovate
904d04bc45 chore(deps): update module cloud.google.com/go/alloydbconn to v1.15.3 (#698)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[cloud.google.com/go/alloydbconn](https://redirect.github.com/googlecloudplatform/alloydb-go-connector)
| `v1.15.2` -> `v1.15.3` |
[![age](https://developer.mend.io/api/mc/badges/age/go/cloud.google.com%2fgo%2falloydbconn/v1.15.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/cloud.google.com%2fgo%2falloydbconn/v1.15.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/cloud.google.com%2fgo%2falloydbconn/v1.15.2/v1.15.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/cloud.google.com%2fgo%2falloydbconn/v1.15.2/v1.15.3?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>googlecloudplatform/alloydb-go-connector
(cloud.google.com/go/alloydbconn)</summary>

###
[`v1.15.3`](https://redirect.github.com/GoogleCloudPlatform/alloydb-go-connector/releases/tag/v1.15.3)

[Compare
Source](https://redirect.github.com/googlecloudplatform/alloydb-go-connector/compare/v1.15.2...v1.15.3)

##### Bug Fixes

- reduce the number of memory allocations and latency overhead
([#&#8203;686](https://redirect.github.com/GoogleCloudPlatform/alloydb-go-connector/issues/686))
([274ce04](274ce04953))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40OC41IiwidXBkYXRlZEluVmVyIjoiNDAuNDguNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-11 14:20:50 -07:00
AlexTalreja
75e254c0a4 feat(tools/sqlitesql): add templateParameters field for sqlitesql (#687)
Add templateParameters to support non-filter parameters and DDL
statements.

Part of https://github.com/googleapis/genai-toolbox/issues/535
2025-06-10 13:08:52 -07:00
Yuan
850b32c5b0 docs(tools/alloydbainl): update broken links (#688)
Fixes #631
2025-06-10 11:25:12 -07:00
Anubhav Dhawan
927ef3c508 docs: Add toolbox-core examples to quickstart guide (#642)
## Description
This PR enhances our documentation by integrating `toolbox-core` code
snippets into the quickstart examples on the docsite.

## Context
Previously, our client-facing documentation primarily showcased agent
implementations using third-party frameworks like LangChain, LlamaIndex,
and ADK. This created a documentation gap, as there were no baseline
examples demonstrating how to use our foundational `toolbox-core` SDK
directly. Users who wanted to build a custom integration without a
specific framework had no direct reference in the guides.

## Changes
This PR introduces a new "Core" tab to all relevant code examples within
the auth services and local quickstart (with BigQuery) documentations.

---------

Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-10 18:30:39 +05:30
Yuan
15d3c45159 ci: update generate release table shell script (#685) 2025-06-09 21:32:51 -07:00
release-please[bot]
714d990c34 chore(main): release 0.7.0 (#640)
🤖 I have created a release *beep* *boop*
---


##
[0.7.0](https://github.com/googleapis/genai-toolbox/compare/v0.6.0...v0.7.0)
(2025-06-10)


### Features

* Add templateParameters field for mssqlsql
([#671](https://github.com/googleapis/genai-toolbox/issues/671))
([b81fc6a](b81fc6aa6c))
* Add templateParameters field for mysqlsql
([#663](https://github.com/googleapis/genai-toolbox/issues/663))
([0a08d2c](0a08d2c15d))
* **metrics:** Add user agent for prebuilt tools
([#669](https://github.com/googleapis/genai-toolbox/issues/669))
([29aa0a7](29aa0a70da))
* **tools/postgressql:** Add templateParameters field
([#615](https://github.com/googleapis/genai-toolbox/issues/615))
([b763469](b76346993f))


### Bug Fixes

* Improve versionString
([#658](https://github.com/googleapis/genai-toolbox/issues/658))
([cf96f4c](cf96f4c249))
* **server/stdio:** Notifications should not return a response
([#638](https://github.com/googleapis/genai-toolbox/issues/638))
([69d047a](69d047af46))
* **tools/mysqlsql:** Handled the null value for string case in mysqlsql
tools ([#641](https://github.com/googleapis/genai-toolbox/issues/641))
([ef94648](ef94648455))
* Update path library
([#678](https://github.com/googleapis/genai-toolbox/issues/678))
([4998f82](4998f82852)),
closes [#662](https://github.com/googleapis/genai-toolbox/issues/662)

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
2025-06-09 17:15:26 -07:00
Yuan
e6c2fb324b ci: add extra files in release please config (#684)
Adding extra files for release please automatic files version updates.

removed "docs/en/how-to/deploy_gke.md" since it was updated to use the
`latest` version by default.
2025-06-09 23:13:55 +00:00
Kurtis Van Gent
cf96f4c249 fix: improve versionString (#658)
Reduces complexity of the version string calculation and fixes the ci/cd
pipeline to pass the correct parameters.

---------

Co-authored-by: Averi Kitsch <akitsch@google.com>
Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-09 15:31:42 -07:00
Mend Renovate
8569c6b59f chore(deps): update module modernc.org/sqlite to v1.38.0 (#681)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) | `v1.37.1` ->
`v1.38.0` |
[![age](https://developer.mend.io/api/mc/badges/age/go/modernc.org%2fsqlite/v1.38.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/go/modernc.org%2fsqlite/v1.38.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/go/modernc.org%2fsqlite/v1.37.1/v1.38.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/go/modernc.org%2fsqlite/v1.37.1/v1.38.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>cznic/sqlite (modernc.org/sqlite)</summary>

###
[`v1.38.0`](https://gitlab.com/cznic/sqlite/compare/v1.37.1...v1.38.0)

[Compare
Source](https://gitlab.com/cznic/sqlite/compare/v1.37.1...v1.38.0)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40OC41IiwidXBkYXRlZEluVmVyIjoiNDAuNDguNSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: Yuan <45984206+Yuan325@users.noreply.github.com>
2025-06-09 22:04:16 +00:00
Yuan
44d41a4888 chore: add .exe suffix to windows binary (#682) 2025-06-09 13:52:28 -07:00
Yuan
4998f82852 fix: update path library (#678)
Using filepath.Join for embed filenames will not respect Windows
filepaths. https://github.com/golang/go/issues/44305

Fix #662
2025-06-09 10:00:26 -07:00
Yuan
b81fc6aa6c feat: add templateParameters field for mssqlsql (#671)
Add `templateParameters to support non-filter parameters and DDL
statements.

Part of https://github.com/googleapis/genai-toolbox/issues/535
2025-06-06 13:18:37 -07:00
Averi Kitsch
29aa0a70da feat(metrics): add user agent for prebuilt tools (#669)
Append "+prebuilt.<source>" to the user agent for tracking the prebuilt
tools usage. This is set before the server is initialized and the user
agent is set on the client.

Using the period to stay consistent with our other appended metadata
like "binary.linux"
2025-06-06 09:49:25 -07:00
Yuan
5638ef520a chore: fix typos in tests (#672) 2025-06-06 14:43:57 +00:00
AlexTalreja
2f42de9507 docs: add templateParameters to postgres documentation (#657) 2025-06-05 17:33:58 -07:00
Yuan
0a08d2c15d feat: add templateParameters field for mysqlsql (#663)
Add `templateParameters to support non-filter parameters and DDL
statements.

Part of #535
2025-06-05 21:37:30 +00:00
Yuan
71250e1ced test: add templateParam postgres-sql tests to other pg source (#664)
Add the template parameters integration test to `postgres` source and
`cloudsql-postgres` source.
2025-06-05 21:33:35 +00:00
Mend Renovate
702dbc355b chore(deps): update dependency go to v1.24.4 (#666)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [go](https://go.dev/)
([source](https://redirect.github.com/golang/go)) | toolchain | patch |
`1.24.3` -> `1.24.4` |

---

### Release Notes

<details>
<summary>golang/go (go)</summary>

###
[`v1.24.4`](https://redirect.github.com/golang/go/compare/go1.24.3...go1.24.4)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/googleapis/genai-toolbox).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC40MC4zIiwidXBkYXRlZEluVmVyIjoiNDAuNDAuMyIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->
2025-06-05 14:23:09 -07:00
Kurtis Van Gent
ef0cbdb4bf docs: fix SQL capitalization (#667) 2025-06-05 20:01:17 +00:00
Yuan
518a0e4c70 refactor(tools/http): dedup to use GetParams (#659) 2025-06-05 10:54:08 -07:00
Yuan
d7ba2736eb refactor: concatenate template parameters and parameters (#660)
Refactor this to dedup from other tools.
2025-06-05 09:01:45 -07:00
Yuan
33ae70ec02 docs: add llms-full.txt (#656)
Generating a `/llms-full.txt` to provide LLM-friendly content (that
doesn't require navigation). For more information, checkout
https://llmstxt.org/.


Preview:
https://googleapis.github.io/genai-toolbox/previews/PR-656/llms-full.txt
2025-06-04 16:00:48 -07:00
Kurtis Van Gent
1c9ad5ea24 refactor: implement dynamic source registration (#614)
This commit refactors the source configuration and loading mechanism to
use a dynamic registration pattern. Each source package now registers
itself with a central registry via its init() function.

The server configuration code uses this registry to decode and
initialize sources, decoupling it from specific source implementations
and simplifying the addition of new sources.

Key changes:
- Introduced `sources.Register()` and `newConfig()` constructor in each
source package.
- Moved source package imports to `cmd/root.go` as blank imports to
trigger `init()` functions for self-registration.
- Removed direct imports of specific source packages from
`internal/server/config.go`.
- Renamed `SourceKind` constants to `Kind` within each source package.
- Updated tests to use the new `Kind` constants and reflect registration
changes.

---------

Co-authored-by: Yuan Teoh <yuanteoh@google.com>
2025-06-04 14:23:57 -07:00
133 changed files with 5187 additions and 2521 deletions

View File

@@ -17,15 +17,8 @@ steps:
waitFor: ['-']
script: |
#!/usr/bin/env bash
docker buildx build --build-arg METADATA_TAGS=$(git rev-parse HEAD) -t ${_DOCKER_URI}:$REF_NAME .
- id: "push-docker"
name: "gcr.io/cloud-builders/docker"
waitFor:
- "build-docker"
script: |
#!/usr/bin/env bash
docker push ${_DOCKER_URI}:$REF_NAME
docker buildx create --name container-builder --driver docker-container --bootstrap --use
docker buildx build --platform linux/amd64,linux/arm64 --build-arg COMMIT_SHA=$(git rev-parse HEAD) -t ${_DOCKER_URI}:$REF_NAME --push .
- id: "install-dependencies"
name: golang:1
@@ -50,7 +43,7 @@ steps:
script: |
#!/usr/bin/env bash
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.linux.amd64.$REF_NAME" -o toolbox.linux.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.linux.amd64
- id: "store-linux-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -72,7 +65,7 @@ steps:
script: |
#!/usr/bin/env bash
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.darwin.arm64.$REF_NAME" -o toolbox.darwin.arm64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.arm64
- id: "store-darwin-arm64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -94,7 +87,7 @@ steps:
script: |
#!/usr/bin/env bash
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.darwin.amd64.$REF_NAME" -o toolbox.darwin.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.amd64
- id: "store-darwin-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -116,7 +109,7 @@ steps:
script: |
#!/usr/bin/env bash
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.windows.amd64.$REF_NAME" -o toolbox.windows.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.windows.amd64
- id: "store-windows-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -124,12 +117,13 @@ steps:
- "build-windows-amd64"
script: |
#!/usr/bin/env bash
gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$REF_NAME/windows/amd64/toolbox
gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$REF_NAME/windows/amd64/toolbox.exe
options:
automapSubstitutions: true
dynamicSubstitutions: true
logging: CLOUD_LOGGING_ONLY # Necessary for custom service account
machineType: 'E2_HIGHCPU_32'
substitutions:
_REGION: us-central1

View File

@@ -36,7 +36,12 @@ do
ARCH=$(echo "$file_key" | cut -d '.' -f 2)
# Get release URL
URL="https://storage.googleapis.com/genai-toolbox/$VERSION/$OS/$ARCH/toolbox"
if [ "$OS" = 'windows' ];
then
URL="https://storage.googleapis.com/genai-toolbox/$VERSION/$OS/$ARCH/toolbox.exe"
else
URL="https://storage.googleapis.com/genai-toolbox/$VERSION/$OS/$ARCH/toolbox"
fi
curl "$URL" --fail --output toolbox || exit 1

View File

@@ -332,6 +332,39 @@ steps:
- -c
- |
./couchbase.test -test.v
- id: "redis"
name : golang:1
waitFor: ["compile-test-binary"]
entrypoint: /bin/bash
env:
- "GOPATH=/gopath"
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
secretEnv: ["REDIS_ADDRESS", "REDIS_PASS", "CLIENT_ID"]
volumes:
- name: "go"
path: "/gopath"
args:
- -c
- |
./redis.test -test.v
- id: "valkey"
name : golang:1
waitFor: ["compile-test-binary"]
entrypoint: /bin/bash
env:
- "GOPATH=/gopath"
- "VALKEY_DATABASE=$_VALKEY_DATABASE"
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
secretEnv: ["VALKEY_ADDRESS", "CLIENT_ID"]
volumes:
- name: "go"
path: "/gopath"
args:
- -c
- |
./valkey.test -test.v
availableSecrets:
@@ -380,6 +413,12 @@ availableSecrets:
env: COUCHBASE_USER
- versionName: projects/$PROJECT_ID/secrets/couchbase_pass/versions/latest
env: COUCHBASE_PASS
- versionName: projects/$PROJECT_ID/secrets/memorystore_redis_address/versions/latest
env: REDIS_ADDRESS
- versionName: projects/$PROJECT_ID/secrets/memorystore_redis_pass/versions/latest
env: REDIS_PASS
- versionName: projects/$PROJECT_ID/secrets/memorystore_valkey_address/versions/latest
env: VALKEY_ADDRESS
options:
@@ -411,4 +450,4 @@ substitutions:
_MSSQL_PORT: "1433"
_DGRAPHURL: "https://play.dgraph.io"
_COUCHBASE_BUCKET: "couchbase-bucket"
_COUCHBASE_SCOPE: "couchbase-scope"
_COUCHBASE_SCOPE: "couchbase-scope"

View File

@@ -18,19 +18,13 @@ steps:
script: |
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
docker buildx build --build-arg METADATA_TAGS=$(git rev-parse HEAD) -t ${_DOCKER_URI}:$VERSION -t ${_DOCKER_URI}:latest .
docker buildx create --name container-builder --driver docker-container --bootstrap --use
- id: "push-docker"
name: "gcr.io/cloud-builders/docker"
waitFor:
- "build-docker"
script: |
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
docker push ${_DOCKER_URI}:$VERSION
export TAGS="-t ${_DOCKER_URI}:$VERSION"
if [[ $_PUSH_LATEST == 'true' ]]; then
docker push ${_DOCKER_URI}:latest
export TAGS="$TAGS -t ${_DOCKER_URI}:latest"
fi
docker buildx build --platform linux/amd64,linux/arm64 --build-arg BUILD_TYPE=container.release --build-arg COMMIT_SHA=$(git rev-parse HEAD) $TAGS --push .
- id: "install-dependencies"
name: golang:1
@@ -56,7 +50,7 @@ steps:
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.linux.amd64.$VERSION.$(git rev-parse HEAD)" -o toolbox.linux.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.linux.amd64
- id: "store-linux-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -80,7 +74,7 @@ steps:
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.darwin.arm64.$VERSION.$(git rev-parse HEAD)" -o toolbox.darwin.arm64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.arm64
- id: "store-darwin-arm64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -104,7 +98,7 @@ steps:
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.darwin.amd64.$VERSION.$(git rev-parse HEAD)" -o toolbox.darwin.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.amd64
- id: "store-darwin-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -128,7 +122,7 @@ steps:
#!/usr/bin/env bash
export VERSION=$(cat ./cmd/version.txt)
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=binary.windows.amd64.$VERSION.$(git rev-parse HEAD)" -o toolbox.windows.amd64
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.windows.amd64
- id: "store-windows-amd64"
name: "gcr.io/cloud-builders/gcloud:latest"
@@ -137,12 +131,13 @@ steps:
script: |
#!/usr/bin/env bash
export VERSION=v$(cat ./cmd/version.txt)
gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$VERSION/windows/amd64/toolbox
gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe
options:
automapSubstitutions: true
dynamicSubstitutions: true
logging: CLOUD_LOGGING_ONLY # Necessary for custom service account
machineType: 'E2_HIGHCPU_32'
substitutions:
_REGION: us-central1

View File

@@ -2,7 +2,14 @@ assign_issues:
- kurtisvg
- Yuan325
- duwenxin99
assign_issues_by:
- labels:
- 'product: bigquery'
to:
- Genesis929
- shobsi
- jiaxunwu
assign_prs:
- kurtisvg
- Yuan325
- duwenxin99
- duwenxin99

10
.github/labels.yaml vendored
View File

@@ -69,6 +69,10 @@
color: 3DED97
description: Label to trigger Github Action tests.
- name: 'docs: deploy-preview'
color: BFDADC
description: Label to trigger Github Action docs preview.
- name: 'status: contribution welcome'
color: 8befd7
description: Status - Contributions welcome.
@@ -80,3 +84,9 @@
- name: 'status: awaiting codeowners'
color: 8befd7
description: Status - Awaiting response from code owners.
# Product Labels
- name: 'product: bigquery'
color: 5065c7
description: Product - Assigned to the BigQuery team.

View File

@@ -21,9 +21,15 @@ extraFiles: [
"docs/en/getting-started/introduction/_index.md",
"docs/en/getting-started/local_quickstart.md",
"docs/en/getting-started/mcp_quickstart/_index.md",
"docs/en/how-to/deploy_gke.md",
"docs/en/samples/bigquery/local_quickstart.md",
"docs/en/samples/bigquery/mcp_quickstart.md",
"docs/en/samples/bigquery/mcp_quickstart/_index.md",
"docs/en/getting-started/colab_quickstart.ipynb",
"docs/en/samples/bigquery/colab_quickstart_bigquery.ipynb",
"docs/en/how-to/connect-ide/bigquery_mcp.md",
"docs/en/how-to/connect-ide/spanner_mcp.md",
"docs/en/how-to/connect-ide/alloydb_pg_mcp.md",
"docs/en/how-to/connect-ide/cloud_sql_mysql_mcp.md",
"docs/en/how-to/connect-ide/cloud_sql_pg_mcp.md",
"docs/en/how-to/connect-ide/postgres_mcp.md",
"docs/en/how-to/connect-ide/cloud_sql_mssql_mcp.md",
]

View File

@@ -31,6 +31,8 @@ branchProtectionRules:
- "header-check"
# - Add required status checks like presubmit tests
- "unit tests (ubuntu-latest)"
- "unit tests (windows-latest)"
- "unit tests (macos-latest)"
- "integration-test-pr (toolbox-testing-438616)"
requiredApprovingReviewCount: 1
requiresCodeOwnerReviews: true

View File

@@ -17,7 +17,7 @@ name: "docs"
permissions:
contents: write
pull-requests: write
# This Workflow depends on 'github.event.number',
# not compatible with branch or manual triggers.
on:
@@ -27,9 +27,19 @@ on:
- 'docs/**'
- 'github/workflows/docs**'
- '.hugo/**'
pull_request_target:
types: [labeled]
paths:
- 'docs/**'
- 'github/workflows/docs**'
- '.hugo/**'
jobs:
preview:
# run job on proper workflow event triggers (skip job for pull_request event
# from forks and only run pull_request_target for "docs: deploy-preview"
# label)
if: "${{ (github.event.action != 'labeled' && github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name) || github.event.label.name == 'docs: deploy-preview' }}"
runs-on: ubuntu-24.04
defaults:
run:
@@ -70,8 +80,6 @@ jobs:
HUGO_RELATIVEURLS: false
- name: Deploy
# If run from a fork, GitHub write operations will fail.
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
@@ -80,8 +88,6 @@ jobs:
commit_message: "stage: PR-${{ github.event.number }}: ${{ github.event.head_commit.message }}"
- name: Comment
# If run from a fork, GitHub write operations will fail.
if: ${{ !github.event.pull_request.head.repo.fork }}
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |

View File

@@ -32,8 +32,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
# os: [macos-latest, windows-latest, ubuntu-latest]
os: [ubuntu-latest]
os: [macos-latest, windows-latest, ubuntu-latest]
fail-fast: false
permissions:
contents: 'read'
@@ -75,7 +74,8 @@ jobs:
- name: Build
run: go build -v ./...
- name: Run tests
- name: Run tests with coverage
if: ${{ runner.os == 'Linux' }}
run: |
source_dir="./internal/sources/*"
tool_dir="./internal/tools/*"
@@ -85,7 +85,13 @@ jobs:
go test -race -cover -coverprofile=coverage.out -v $included_packages
go test -race -v ./internal/sources/... ./internal/tools/... ./internal/auth/...
- name: Run tests without coverage
if: ${{ runner.os != 'Linux' }}
run: |
go test -race -v ./internal/... ./cmd/...
- name: Check coverage
if: ${{ runner.os == 'Linux' }}
run: |
FILE_TO_EXCLUDE="github.com/googleapis/genai-toolbox/internal/server/config.go"
ESCAPED_PATH=$(echo "$FILE_TO_EXCLUDE" | sed 's/\//\\\//g; s/\./\\\./g')

View File

@@ -51,11 +51,16 @@ enableRobotsTXT = true
unsafe= true
[outputFormats]
[outputFormats.TXT]
[outputFormats.LLMS]
mediaType = "text/plain"
baseName = "llms"
isPlainText = true
root = true
[outputFormats.LLMS-FULL]
mediaType = "text/plain"
baseName = "llms-full"
isPlainText = true
root = true
[outputs]
home = ["HTML", "TXT"]
home = ["HTML", "RSS", "LLMS", "LLMS-FULL"]

View File

@@ -0,0 +1,14 @@
{{ .Site.Params.description }}
{{ range .Site.Sections }}
# {{ .Title }}
{{ .Description }}
{{ range .Pages }}
# {{ .Title }}
{{ .Description }}
{{ .RawContent }}
{{ range .Pages }}
# {{ .Title }}
{{ .Description }}
{{ .RawContent }}
{{end }}{{ end }}{{ end }}

View File

@@ -1,5 +1,23 @@
# Changelog
## [0.7.0](https://github.com/googleapis/genai-toolbox/compare/v0.6.0...v0.7.0) (2025-06-10)
### Features
* Add templateParameters field for mssqlsql ([#671](https://github.com/googleapis/genai-toolbox/issues/671)) ([b81fc6a](https://github.com/googleapis/genai-toolbox/commit/b81fc6aa6ccdfbc15676fee4d87041d9ad9682fa))
* Add templateParameters field for mysqlsql ([#663](https://github.com/googleapis/genai-toolbox/issues/663)) ([0a08d2c](https://github.com/googleapis/genai-toolbox/commit/0a08d2c15dcbec18bb556f4dc49792ba0c69db46))
* **metrics:** Add user agent for prebuilt tools ([#669](https://github.com/googleapis/genai-toolbox/issues/669)) ([29aa0a7](https://github.com/googleapis/genai-toolbox/commit/29aa0a70da3c2eb409a38993b3782da8bec7cb85))
* **tools/postgressql:** Add templateParameters field ([#615](https://github.com/googleapis/genai-toolbox/issues/615)) ([b763469](https://github.com/googleapis/genai-toolbox/commit/b76346993f298b4f7493a51405d0a287bacce05f))
### Bug Fixes
* Improve versionString ([#658](https://github.com/googleapis/genai-toolbox/issues/658)) ([cf96f4c](https://github.com/googleapis/genai-toolbox/commit/cf96f4c249f0692e3eb19fc56c794ca6a3079307))
* **server/stdio:** Notifications should not return a response ([#638](https://github.com/googleapis/genai-toolbox/issues/638)) ([69d047a](https://github.com/googleapis/genai-toolbox/commit/69d047af46f1ec00f236db8a978a7a7627217fd2))
* **tools/mysqlsql:** Handled the null value for string case in mysqlsql tools ([#641](https://github.com/googleapis/genai-toolbox/issues/641)) ([ef94648](https://github.com/googleapis/genai-toolbox/commit/ef94648455c3b20adda4f8cff47e70ddccac8c06))
* Update path library ([#678](https://github.com/googleapis/genai-toolbox/issues/678)) ([4998f82](https://github.com/googleapis/genai-toolbox/commit/4998f8285287b5daddd0043540f2cf871e256db5)), closes [#662](https://github.com/googleapis/genai-toolbox/issues/662)
## [0.6.0](https://github.com/googleapis/genai-toolbox/compare/v0.5.0...v0.6.0) (2025-05-28)

View File

@@ -41,6 +41,48 @@
### Testing
#### Writing Tests
New contributions should be added with both unit tests and integration tests.
- Unit tests are in the same package as the source code.
- Integration tests are in the `/tests` directory, under its dedicated package
named after its source. We have several pre-defined integration test suites
in the `/tests/tool.go` that are **required** to be run as long as your code contains related
features:
1. [RunToolGetTest][tool-get]: tests for the `GET` endpoint that returns the
tool's manifest.
2. [RunToolInvokeTest][tool-call]: tests for tool calling through the native
Toolbox endpoints.
3. [RunMCPToolCallMethod][mcp-call]: tests tool calling through the MCP
endpoints.
4. (Optional) [RunExecuteSqlToolInvokeTest][execute-sql]: tests an
`execute-sql` tool for any source. Only run this test if you are adding an
`execute-sql` tool.
5. (Optional) [RunToolInvokeWithTemplateParameters][temp-param]: tests for [template
parameters][temp-param-doc]. Only run this test if template parameters apply to your tool.
[tool-get]:
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L31
[tool-call]:
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L79>
[mcp-call]:
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L554
[execute-sql]:
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L431>
[temp-param]:
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L297>
[temp-param-doc]:
https://googleapis.github.io/genai-toolbox/resources/tools/#template-parameters
#### Running Tests
- Run the lint check:
```bash
@@ -80,6 +122,44 @@
automatically. For external contributors, ask the Toolbox
maintainers to trigger the testing workflows on your PR.
## Developing Documentation
Follow these steps to run a Hugo server for local preview:
1. [Install Hugo](https://gohugo.io/installation/macos/) version 0.146.0+.
1. Move into the `.hugo` directory
```bash
cd .hugo
```
1. Install dependencies
```bash
npm ci
```
1. Run the server
```bash
hugo server
```
### PR documentation preview
- For contributors:
- Ask a repo owner to run the preview deployment workflow on your PR. The preview link
will be commented under your PR automatically.
- For maintainers:
- Inspect the proposed changes in the PR and ensure that it does not contain
malicious code changes. You should be especially alert to any proposed changes in the
`.github/workflows/` directory that affect workflow files.
- After you make sure the changes are safe, apply the `docs: deploy-preview`
label to the PR to deploy documentation preview.
## Compile the app locally
### Compile Toolbox binary
@@ -130,27 +210,6 @@
docker run -d toolbox:dev
```
## Developing Documentation
1. [Install Hugo](https://gohugo.io/installation/macos/) version 0.146.0+.
1. Move into the `.hugo` directory
```bash
cd .hugo
```
1. Install dependencies
```bash
npm ci
```
1. Run the server
```bash
hugo server
```
## Developing Toolbox SDKs
Please refer to the [SDK developer guide](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/DEVELOPER.md)

View File

@@ -13,18 +13,19 @@
# limitations under the License.
# Use the latest stable golang 1.x to compile to a binary
FROM --platform=$BUILDPLATFORM golang:1 as build
FROM --platform=$BUILDPLATFORM golang:1 AS build
WORKDIR /go/src/genai-toolbox
COPY . .
ARG TARGETOS
ARG TARGETARCH
ARG METADATA_TAGS=dev
ARG BUILD_TYPE="container.dev"
ARG COMMIT_SHA=""
RUN go get ./...
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.metadataString=container.${METADATA_TAGS}"
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=container.${BUILD_TYPE} -X github.com/googleapis/genai-toolbox/cmd.commitSha=${COMMIT_SHA}"
# Final Stage
FROM gcr.io/distroless/static:nonroot

View File

@@ -99,7 +99,7 @@ To install Toolbox as a binary:
<!-- {x-release-please-start-version} -->
```sh
# see releases page for other versions
export VERSION=0.6.0
export VERSION=0.7.0
curl -O https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox
```
@@ -112,7 +112,7 @@ You can also install Toolbox as a container:
```sh
# see releases page for other versions
export VERSION=0.6.0
export VERSION=0.7.0
docker pull us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$VERSION
```
@@ -125,7 +125,7 @@ To install from source, ensure you have the latest version of
[Go installed](https://go.dev/doc/install), and then run the following command:
```sh
go install github.com/googleapis/genai-toolbox@v0.6.0
go install github.com/googleapis/genai-toolbox@v0.7.0
```
<!-- {x-release-please-end} -->

View File

@@ -22,6 +22,7 @@ import (
"os"
"os/signal"
"regexp"
"runtime"
"strings"
"syscall"
"time"
@@ -52,19 +53,43 @@ import (
_ "github.com/googleapis/genai-toolbox/internal/tools/neo4j"
_ "github.com/googleapis/genai-toolbox/internal/tools/postgresexecutesql"
_ "github.com/googleapis/genai-toolbox/internal/tools/postgressql"
_ "github.com/googleapis/genai-toolbox/internal/tools/redis"
_ "github.com/googleapis/genai-toolbox/internal/tools/spanner"
_ "github.com/googleapis/genai-toolbox/internal/tools/spannerexecutesql"
_ "github.com/googleapis/genai-toolbox/internal/tools/sqlitesql"
_ "github.com/googleapis/genai-toolbox/internal/tools/valkey"
"github.com/spf13/cobra"
_ "github.com/googleapis/genai-toolbox/internal/sources/alloydbpg"
_ "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
_ "github.com/googleapis/genai-toolbox/internal/sources/bigtable"
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmssql"
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmysql"
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
_ "github.com/googleapis/genai-toolbox/internal/sources/couchbase"
_ "github.com/googleapis/genai-toolbox/internal/sources/dgraph"
_ "github.com/googleapis/genai-toolbox/internal/sources/http"
_ "github.com/googleapis/genai-toolbox/internal/sources/mssql"
_ "github.com/googleapis/genai-toolbox/internal/sources/mysql"
_ "github.com/googleapis/genai-toolbox/internal/sources/neo4j"
_ "github.com/googleapis/genai-toolbox/internal/sources/postgres"
_ "github.com/googleapis/genai-toolbox/internal/sources/redis"
_ "github.com/googleapis/genai-toolbox/internal/sources/spanner"
_ "github.com/googleapis/genai-toolbox/internal/sources/sqlite"
_ "github.com/googleapis/genai-toolbox/internal/sources/valkey"
)
var (
// versionString indicates the version of this library.
//go:embed version.txt
// versionString stores the full semantic version, including build metadata.
versionString string
// versionNum indicates the numerical part fo the version
//go:embed version.txt
versionNum string
// metadataString indicates additional build or distribution metadata.
metadataString string
buildType string = "dev" // should be one of "dev", "binary", or "container"
// commitSha is the git commit it was built from
commitSha string
)
func init() {
@@ -73,10 +98,11 @@ func init() {
// semanticVersion returns the version of the CLI including a compile-time metadata.
func semanticVersion() string {
v := strings.TrimSpace(versionString)
if metadataString != "" {
v += "+" + metadataString
metadataStrings := []string{buildType, runtime.GOOS, runtime.GOARCH}
if commitSha != "" {
metadataStrings = append(metadataStrings, commitSha)
}
v := strings.TrimSpace(versionNum) + "+" + strings.Join(metadataStrings, ".")
return v
}
@@ -258,7 +284,7 @@ func run(cmd *Command) error {
ctx = util.WithLogger(ctx, cmd.logger)
// Set up OpenTelemetry
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.Version, cmd.cfg.TelemetryOTLP, cmd.cfg.TelemetryGCP, cmd.cfg.TelemetryServiceName)
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.cfg.Version, cmd.cfg.TelemetryOTLP, cmd.cfg.TelemetryGCP, cmd.cfg.TelemetryServiceName)
if err != nil {
errMsg := fmt.Errorf("error setting up OpenTelemetry: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
@@ -289,6 +315,8 @@ func run(cmd *Command) error {
}
logMsg := fmt.Sprint("Using prebuilt tool configuration for ", cmd.prebuiltConfig)
cmd.logger.InfoContext(ctx, logMsg)
// Append prebuilt.source to Version string for the User Agent
cmd.cfg.Version += "+prebuilt." + cmd.prebuiltConfig
} else {
// Set default value of tools-file flag to tools.yaml
if cmd.tools_file == "" {
@@ -324,30 +352,33 @@ func run(cmd *Command) error {
return errMsg
}
err = s.Listen(ctx)
if err != nil {
errMsg := fmt.Errorf("toolbox failed to start listener: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg
}
cmd.logger.InfoContext(ctx, "Server ready to serve!")
// run server in background
srvErr := make(chan error)
go func() {
defer close(srvErr)
if cmd.cfg.Stdio {
if cmd.cfg.Stdio {
go func() {
defer close(srvErr)
err = s.ServeStdio(ctx, cmd.inStream, cmd.outStream)
if err != nil {
srvErr <- err
}
} else {
}()
} else {
err = s.Listen(ctx)
if err != nil {
errMsg := fmt.Errorf("toolbox failed to start listener: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg
}
cmd.logger.InfoContext(ctx, "Server ready to serve!")
go func() {
defer close(srvErr)
err = s.Serve(ctx)
if err != nil {
srvErr <- err
}
}
}()
}()
}
// wait for either the server to error out or the command's context to be canceled
select {

View File

@@ -18,6 +18,7 @@ import (
"bytes"
_ "embed"
"os"
"runtime"
"strings"
"testing"
@@ -37,7 +38,9 @@ import (
func withDefaults(c server.ServerConfig) server.ServerConfig {
data, _ := os.ReadFile("version.txt")
c.Version = strings.TrimSpace(string(data))
version := strings.TrimSpace(string(data)) // Preserving 'data', new var for clarity
c.Version = version + "+" + strings.Join([]string{"dev", runtime.GOOS, runtime.GOARCH}, ".")
if c.Address == "" {
c.Address = "127.0.0.1"
}

View File

@@ -1 +1 @@
0.6.0
0.7.0

23
docs/en/about/blogs.md Normal file
View File

@@ -0,0 +1,23 @@
---
title: "Blogs"
type: docs
weight: 3
description: Toolbox Tuesday blog posts.
---
## Toolbox Tuesday Blogs
Every Tuesday, we post a blog on our [Medium page][medium]. These blogs will be covering
topics, tutorials, or samples that are related to developing with Toolbox.
Follow us and stay tuned!
## Previous Blogs
- [Powering your IDEs build-time agents with MCP Toolbox for Databases][blog1]
- [Using HTTP endpoints as tools with MCP Toolbox for Databases][blog2]
[medium]: https://medium.com/@mcp_toolbox
[blog1]:
https://medium.com/google-cloud/powering-your-ides-build-time-agents-with-mcp-toolbox-for-databases-123f0d837804
[blog2]:
https://medium.com/google-cloud/using-http-endpoints-as-tools-with-mcp-toolbox-for-databases-e93ab75b60cd

22
docs/en/about/contact.md Normal file
View File

@@ -0,0 +1,22 @@
---
title: "Contact Us"
type: docs
weight: 10
description: Contact the Toolbox team.
---
Toolbox is an open source project and we welcome contributions and discussion from the
developer community.
## How to Get in Touch
- If you want to make a contribution, [open an issue][issue] first so that we can agree
on the general design.
- If you found a bug or have ideas for improvements, [open an issue][issue] and
we will reply as soon as possible.
- For any topics, join our [discord server][discord], where we can discuss things in real-time for a faster response.
[issue]: https://github.com/googleapis/genai-toolbox/issues
[discord]: https://discord.com/invite/Dmm69peqjh

View File

@@ -222,7 +222,7 @@
},
"outputs": [],
"source": [
"version = \"0.6.0\" # x-release-please-version\n",
"version = \"0.7.0\" # x-release-please-version\n",
"! curl -O https://storage.googleapis.com/genai-toolbox/v{version}/linux/amd64/toolbox\n",
"\n",
"# Make the binary executable\n",

View File

@@ -73,7 +73,7 @@ To install Toolbox as a binary:
```sh
# see releases page for other versions
export VERSION=0.6.0
export VERSION=0.7.0
curl -O https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox
```
@@ -84,7 +84,7 @@ You can also install Toolbox as a container:
```sh
# see releases page for other versions
export VERSION=0.6.0
export VERSION=0.7.0
docker pull us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$VERSION
```
@@ -95,7 +95,7 @@ To install from source, ensure you have the latest version of
[Go installed](https://go.dev/doc/install), and then run the following command:
```sh
go install github.com/googleapis/genai-toolbox@v0.6.0
go install github.com/googleapis/genai-toolbox@v0.7.0
```
{{% /tab %}}

View File

@@ -138,7 +138,7 @@ In this section, we will download Toolbox, configure our tools in a
<!-- {x-release-please-start-version} -->
```bash
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/$OS/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
```
<!-- {x-release-please-end} -->

View File

@@ -105,7 +105,7 @@ In this section, we will download Toolbox, configure our tools in a
<!-- {x-release-please-start-version} -->
```bash
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/$OS/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
```
<!-- {x-release-please-end} -->

View File

@@ -5,266 +5,9 @@ weight: 2
description: >
Connect your IDE to AlloyDB using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like AlloyDB. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a AlloyDB for Postgres instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the AlloyDB, Compute Engine, Cloud Resource Manager, and Service Networking APIs in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=alloydb.googleapis.com,compute.googleapis.com,cloudresourcemanager.googleapis.com,servicenetworking.googleapis.com).
1. [Create a cluster and its primary instance](https://cloud.google.com/alloydb/docs/quickstart/create-and-connect). These instructions assume that your AlloyDB instance has a [public IP address](https://cloud.google.com/alloydb/docs/connect-public-ip). By default, AlloyDB assigns a private IP address to a new instance. Toolbox will connect securely using the [AlloyDB Language Connectors](https://cloud.google.com/alloydb/docs/language-connectors-overview).
1. Configure the required roles and permissions to complete this task. You will need [Cloud AlloyDB Client](https://cloud.google.com/alloydb/docs/auth-proxy/connect#required-iam-permissions) (`roles/alloydb.client`) and Service Usage Consumer (`roles/serviceusage.serviceUsageConsumer`) roles or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
1. Create or reuse [a database user](https://cloud.google.com/alloydb/docs/database-users/manage-roles) and have the username and password ready.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"alloydb": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","alloydb-postgres","--stdio"],
"env": {
"ALLOYDB_POSTGRES_PROJECT": "your-gcp-project-id",
"ALLOYDB_POSTGRES_REGION": "your-cluster-region",
"ALLOYDB_POSTGRES_CLUSTER": "your-cluster-name",
"ALLOYDB_POSTGRES_INSTANCE": "your-instance-name",
"ALLOYDB_POSTGRES_DATABASE": "your-database-name",
"ALLOYDB_POSTGRES_USER": "your-database-user",
"ALLOYDB_POSTGRES_PASSWORD": "your-database-password"
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to AlloyDB using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute any SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/alloydb/docs/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/alloydb/docs/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -5,235 +5,9 @@ weight: 2
description: >
Connect your IDE to BigQuery using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like BigQuery. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a BigQuery instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the BigQuery API in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=bigquery.googleapis.com&redirect=https://console.cloud.google.com).
1. Configure the required roles and permissions to complete this task. You will need [BigQuery User](https://cloud.google.com/bigquery/docs/access-control) role (`roles/bigquery.user`), BigQuery Data Viewer role(`roles/bigquery.dataViewer`), or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","bigquery","--stdio"],
"env": {
"BIGQUERY_PROJECT": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to BigQuery using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **execute_sql**: execute SQL statement
1. **get_dataset_info**: get dataset metadata
1. **get_table_info**: get table metadata
1. **list_dataset_ids**: list datasets
1. **list_table_ids**: list tables
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/bigquery/docs/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/bigquery/docs/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -3,267 +3,11 @@ title: "Cloud SQL for SQL Server using MCP"
type: docs
weight: 2
description: >
Connect your IDE to Cloud SQl for SQL Server using Toolbox.
Connect your IDE to Cloud SQL for SQL Server using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like Cloud SQL. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a Cloud SQL for SQL Server instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the Cloud SQL Admin API in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin&redirect=https://console.cloud.google.com).
1. [Create or select a Cloud SQL for SQL Server instance](https://cloud.google.com/sql/docs/sqlserver/create-instance). These instructions assume that your Cloud SQL instance has a [public IP address](https://cloud.google.com/sql/docs/sqlserver/configure-ip). By default, Cloud SQL assigns a public IP address to a new instance. Toolbox will connect securely using the [Cloud SQL connectors](https://cloud.google.com/sql/docs/sqlserver/language-connectors).
1. Configure the required roles and permissions to complete this task. You will need [Cloud SQL > Client](https://cloud.google.com/sql/docs/sqlserver/roles-and-permissions#proxy-roles-permissions) role (`roles/cloudsql.client`) or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
1. Create or reuse [a database user](https://cloud.google.com/sql/docs/sqlserver/create-manage-users) and have the username and password ready.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-sqlserver": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mssql","--stdio"],
"env": {
"CLOUD_SQL_MSSQL_PROJECT": "",
"CLOUD_SQL_MSSQL_REGION": "",
"CLOUD_SQL_MSSQL_INSTANCE": "",
"CLOUD_SQL_MSSQL_DATABASE": "",
"CLOUD_SQL_MSSQL_IP_ADDRESS": "",
"CLOUD_SQL_MSSQL_USER": "",
"CLOUD_SQL_MSSQL_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to Cloud SQL for Sql Server using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute any SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/sql/docs/sqlserver/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/sql/docs/sqlserver/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -3,261 +3,11 @@ title: "Cloud SQL for MySQL using MCP"
type: docs
weight: 2
description: >
Connect your IDE to Cloud SQl for MySQL using Toolbox.
Connect your IDE to Cloud SQL for MySQL using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like Cloud SQL. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a Cloud SQL for MySQL instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the Cloud SQL Admin API in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin&redirect=https://console.cloud.google.com).
1. [Create a Cloud SQL for MySQL instance](https://cloud.google.com/sql/docs/mysql/create-instance). These instructions assume that your Cloud SQL instance has a [public IP address](https://cloud.google.com/sql/docs/mysql/configure-ip). By default, Cloud SQL assigns a public IP address to a new instance. Toolbox will connect securely using the [Cloud SQL connectors](https://cloud.google.com/sql/docs/mysql/language-connectors).
1. Configure the required roles and permissions to complete this task. You will need [Cloud SQL > Client](https://cloud.google.com/sql/docs/mysql/roles-and-permissions#proxy-roles-permissions) role (`roles/cloudsql.client`) or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
1. Create or reuse [a database user](https://cloud.google.com/sql/docs/mysql/create-manage-users) and have the username and password ready.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-mysql": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-mysql","--stdio"],
"env": {
"CLOUD_SQL_MYSQL_PROJECT": "",
"CLOUD_SQL_MYSQL_REGION": "",
"CLOUD_SQL_MYSQL_INSTANCE": "",
"CLOUD_SQL_MYSQL_DATABASE": "",
"CLOUD_SQL_MYSQL_USER": "",
"CLOUD_SQL_MYSQL_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to Cloud SQL for MySQL using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute any SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/sql/docs/mysql/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/sql/docs/mysql/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -3,262 +3,11 @@ title: "Cloud SQL for Postgres using MCP"
type: docs
weight: 2
description: >
Connect your IDE to Cloud SQl for Postgres using Toolbox.
Connect your IDE to Cloud SQL for Postgres using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like Cloud SQL. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a Cloud SQL for Postgres instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the Cloud SQL Admin API in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=sqladmin&redirect=https://console.cloud.google.com).
1. [Create or select a Cloud SQL for PostgreSQL instance](https://cloud.google.com/sql/docs/postgres/create-instance). These instructions assume that your Cloud SQL instance has a [public IP address](https://cloud.google.com/sql/docs/postgres/configure-ip). By default, Cloud SQL assigns a public IP address to a new instance. Toolbox will connect securely using the [Cloud SQL connectors](https://cloud.google.com/sql/docs/postgres/language-connectors).
1. Configure the required roles and permissions to complete this task. You will need [Cloud SQL > Client](https://cloud.google.com/sql/docs/postgres/roles-and-permissions#proxy-roles-permissions) role (`roles/cloudsql.client`) or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
1. Create or reuse [a database user](https://cloud.google.com/sql/docs/postgres/create-manage-users) and have the username and password ready.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
```json
{
"mcpServers": {
"cloud-sql-postgres": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","cloud-sql-postgres","--stdio"],
"env": {
"CLOUD_SQL_POSTGRES_PROJECT": "",
"CLOUD_SQL_POSTGRES_REGION": "",
"CLOUD_SQL_POSTGRES_INSTANCE": "",
"CLOUD_SQL_POSTGRES_DATABASE": "",
"CLOUD_SQL_POSTGRES_USER": "",
"CLOUD_SQL_POSTGRES_PASSWORD": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to Cloud SQL for PostgreSQL using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute any SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/sql/docs/postgres/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/sql/docs/postgres/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -44,19 +44,19 @@ This guide can be used with [AlloyDB Omni](https://cloud.google.com/alloydb/omni
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->

View File

@@ -5,354 +5,9 @@ weight: 2
description: >
Connect your IDE to Spanner using Toolbox.
---
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol for connecting Large Language Models (LLMs) to data sources like Spanner. This guide covers how to use [MCP Toolbox for Databases][toolbox] to expose your developer assistant tools to a Spanner instance:
* [Cursor][cursor]
* [Windsurf][windsurf] (Codium)
* [Visual Studio Code ][vscode] (Copilot)
* [Cline][cline] (VS Code extension)
* [Claude desktop][claudedesktop]
* [Claude code][claudecode]
[toolbox]: https://github.com/googleapis/genai-toolbox
[cursor]: #configure-your-mcp-client
[windsurf]: #configure-your-mcp-client
[vscode]: #configure-your-mcp-client
[cline]: #configure-your-mcp-client
[claudedesktop]: #configure-your-mcp-client
[claudecode]: #configure-your-mcp-client
## Before you begin
1. In the Google Cloud console, on the [project selector page](https://console.cloud.google.com/projectselector2/home/dashboard), select or create a Google Cloud project.
1. [Make sure that billing is enabled for your Google Cloud project](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project).
## Set up the database
1. [Enable the Spanner API in the Google Cloud project](https://console.cloud.google.com/flows/enableapi?apiid=spanner.googleapis.com&redirect=https://console.cloud.google.com).
1. [Create or select a Spanner instance and database](https://cloud.google.com/spanner/docs/create-query-database-console).
1. Configure the required roles and permissions to complete this task. You will need [Cloud Spanner Database User](https://cloud.google.com/spanner/docs/iam#roles) role (`roles/spanner.databaseUser`) or equivalent IAM permissions to connect to the instance.
1. Configured [Application Default Credentials (ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) for your environment.
## Install MCP Toolbox
1. Download the latest version of Toolbox as a binary. Select the [correct binary](https://github.com/googleapis/genai-toolbox/releases) corresponding to your OS and CPU architecture. You are required to use Toolbox version V0.6.0+:
<!-- {x-release-please-start-version} -->
{{< tabpane persist=header >}}
{{< tab header="linux/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/linux/amd64/toolbox
{{< /tab >}}
{{< tab header="darwin/arm64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/arm64/toolbox
{{< /tab >}}
{{< tab header="darwin/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/darwin/amd64/toolbox
{{< /tab >}}
{{< tab header="windows/amd64" lang="bash" >}}
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/windows/amd64/toolbox
{{< /tab >}}
{{< /tabpane >}}
<!-- {x-release-please-end} -->
1. Make the binary executable:
```bash
chmod +x toolbox
```
1. Verify the installation:
```bash
./toolbox --version
```
## Configure your MCP Client
{{< tabpane text=true >}}
{{% tab header="Claude code" lang="en" %}}
1. Install [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview).
1. Create a `.mcp.json` file in your project root if it doesn't exist.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": "" }
}
}
}
```
1. Restart Claude code to apply the new configuration.
{{% /tab %}}
{{% tab header="Claude desktop" lang="en" %}}
1. Open [Claude desktop](https://claude.ai/download) and navigate to Settings.
1. Under the Developer tab, tap Edit Config to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
1. Restart Claude desktop.
1. From the new chat screen, you should see a hammer (MCP) icon appear with the new MCP server available.
{{% /tab %}}
{{% tab header="Cline" lang="en" %}}
1. Open the [Cline](https://github.com/cline/cline) extension in VS Code and tap the **MCP Servers** icon.
1. Tap Configure MCP Servers to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
1. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Cursor" lang="en" %}}
1. Create a `.cursor` directory in your project root if it doesn't exist.
1. Create a `.cursor/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
1. [Cursor](https://www.cursor.com/) and navigate to **Settings > Cursor Settings > MCP**. You should see a green active status after the server is successfully connected.
{{% /tab %}}
{{% tab header="Visual Studio Code (Copilot)" lang="en" %}}
1. Open [VS Code](https://code.visualstudio.com/docs/copilot/overview) and create a `.vscode` directory in your project root if it doesn't exist.
1. Create a `.vscode/mcp.json` file if it doesn't exist and open it.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
{{% /tab %}}
{{% tab header="Windsurf" lang="en" %}}
1. Open [Windsurf](https://docs.codeium.com/windsurf) and navigate to the Cascade assistant.
1. Tap on the hammer (MCP) icon, then Configure to open the configuration file.
1. Add the following configuration, replace the environment variables with your values, and save:
Spanner with `googlesql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
Spanner with `postgresql` dialect
```json
{
"mcpServers": {
"spanner": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt","spanner-postgres","--stdio"],
"env": {
"SPANNER_PROJECT": "",
"SPANNER_INSTANCE": "",
"SPANNER_DATABASE": ""
}
}
}
}
```
{{% /tab %}}
{{< /tabpane >}}
## Use Tools
Your AI tool is now connected to Spanner using MCP. Try asking your AI assistant to list tables, create a table, or define and execute other SQL statements.
The following tools are available to the LLM:
1. **list_tables**: lists tables and descriptions
1. **execute_sql**: execute DML SQL statement
1. **execute_sql_dql**: execute DQL SQL statement
{{< notice note >}}
Prebuilt tools are pre-1.0, so expect some tool changes between versions. LLMs will adapt to the tools available, so this shouldn't affect most users.
{{< /notice >}}
<html>
<head>
<link rel="canonical" href="https://cloud.google.com/spanner/docs/pre-built-tools-with-mcp-toolbox"/>
<meta http-equiv="refresh" content="0;url=https://cloud.google.com/spanner/docs/pre-built-tools-with-mcp-toolbox"/>
</head>
</html>

View File

@@ -62,52 +62,104 @@ token you will provide a function (that returns an id). This function is called
when the tool is invoked. This allows you to cache and refresh the ID token as
needed.
The primary method for providing these getters is via the `auth_token_getters` parameter when loading tools, or the `add_auth_token_getter`() / `add_auth_token_getters()` methods on a loaded tool object.
### Specifying tokens during load
{{< tabpane persist=header >}}
{{< tab header="LangChain" lang="Python" >}}
{{< tab header="Core" lang="Python" >}}
import asyncio
from toolbox_core import ToolboxClient
async def get_auth_token():
# ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
# This example just returns a placeholder. Replace with your actual token retrieval.
return "YOUR_ID_TOKEN" # Placeholder
# for a single tool use
async def main():
async with ToolboxClient("http://127.0.0.1:5000") as toolbox:
auth_tool = await toolbox.load_tool(
"get_sensitive_data",
auth_token_getters={"my_auth_app_1": get_auth_token}
)
result = await auth_tool(param="value")
print(result)
authorized_tool = toolbox.load_tool("my-tool-name", auth_tokens={"my_auth": get_auth_token})
if __name__ == "__main__":
asyncio.run(main())
{{< /tab >}}
{{< tab header="LangChain" lang="Python" >}}
import asyncio
from toolbox_langchain import ToolboxClient
# for a toolset use
async def get_auth_token():
# ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
# This example just returns a placeholder. Replace with your actual token retrieval.
return "YOUR_ID_TOKEN" # Placeholder
authorized_tools = toolbox.load_toolset("my-toolset-name", auth_tokens={"my_auth": get_auth_token})
async def main():
toolbox = ToolboxClient("http://127.0.0.1:5000")
auth_tool = await toolbox.aload_tool(
"get_sensitive_data",
auth_token_getters={"my_auth_app_1": get_auth_token}
)
result = await auth_tool.ainvoke({"param": "value"})
print(result)
if __name__ == "__main__":
asyncio.run(main())
{{< /tab >}}
{{< tab header="Llamaindex" lang="Python" >}}
import asyncio
from toolbox_llamaindex import ToolboxClient
async def get_auth_token():
# ... Logic to retrieve ID token (e.g., from local storage, OAuth flow)
# This example just returns a placeholder. Replace with your actual token retrieval.
return "YOUR_ID_TOKEN" # Placeholder
# for a single tool use
async def main():
toolbox = ToolboxClient("http://127.0.0.1:5000")
authorized_tool = toolbox.load_tool("my-tool-name", auth_tokens={"my_auth": get_auth_token})
auth_tool = await toolbox.aload_tool(
"get_sensitive_data",
auth_token_getters={"my_auth_app_1": get_auth_token}
)
# result = await auth_tool.acall(param="value")
# print(result.content)
# for a toolset use
authorized_tools = toolbox.load_toolset("my-toolset-name", auth_tokens={"my_auth": get_auth_token})
{{< /tab >}}
if __name__ == "__main__":
asyncio.run(main()){{< /tab >}}
{{< /tabpane >}}
### Specifying tokens for existing tools
{{< tabpane persist=header >}}
{{< tab header="Core" lang="Python" >}}
tools = await toolbox.load_toolset()
# for a single token
authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
# OR, if multiple tokens are needed
authorized_tool = tools[0].add_auth_token_getters({
"my_auth1": get_auth1_token,
"my_auth2": get_auth2_token,
})
{{< /tab >}}
{{< tab header="LangChain" lang="Python" >}}
tools = toolbox.load_toolset()
# for a single token
auth_tools = [tool.add_auth_token("my_auth", get_auth_token) for tool in tools]
authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
# OR, if multiple tokens are needed
authorized_tool = tools[0].add_auth_tokens({
authorized_tool = tools[0].add_auth_token_getters({
"my_auth1": get_auth1_token,
"my_auth2": get_auth2_token,
})
@@ -117,11 +169,11 @@ tools = toolbox.load_toolset()
# for a single token
auth_tools = [tool.add_auth_token("my_auth", get_auth_token) for tool in tools]
authorized_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token)
# OR, if multiple tokens are needed
authorized_tool = tools[0].add_auth_tokens({
authorized_tool = tools[0].add_auth_token_getters({
"my_auth1": get_auth1_token,
"my_auth2": get_auth2_token,
})

View File

@@ -27,6 +27,7 @@ sources:
queryParams:
param1: value1
param2: value2
# disableSslVerification: false
```
{{< notice tip >}}
@@ -36,12 +37,13 @@ instead of hardcoding your secrets into the configuration file.
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:-----------------:|:------------:|-----------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "http". |
| baseUrl | string | true | The base URL for the HTTP requests (e.g., `https://api.example.com`). |
| timeout | string | false | The timeout for HTTP requests (e.g., "5s", "1m", refer to [ParseDuration][parse-duration-doc] for more examples). Defaults to 30s. |
| headers | map[string]string | false | Default headers to include in the HTTP requests. |
| queryParams | map[string]string | false | Default query parameters to include in the HTTP requests. |
| **field** | **type** | **required** | **description** |
|------------------------|:-----------------:|:------------:|------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "http". |
| baseUrl | string | true | The base URL for the HTTP requests (e.g., `https://api.example.com`). |
| timeout | string | false | The timeout for HTTP requests (e.g., "5s", "1m", refer to [ParseDuration][parse-duration-doc] for more examples). Defaults to 30s. |
| headers | map[string]string | false | Default headers to include in the HTTP requests. |
| queryParams | map[string]string | false | Default query parameters to include in the HTTP requests. |
| disableSslVerification | bool | false | Disable SSL certificate verification. This should only be used for local development. Defaults to `false`. |
[parse-duration-doc]: https://pkg.go.dev/time#ParseDuration

View File

@@ -0,0 +1,90 @@
---
title: "Redis"
linkTitle: "Redis"
type: docs
weight: 1
description: >
Redis is an open-source, in-memory data structure store.
---
## About
Redis is an open-source, in-memory data structure store, used as a database, cache, and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, and geospatial indexes with radius queries.
If you are new to Redis, you can find installation and getting started guides on the [official Redis website](https://redis.io/docs/getting-started/).
## Requirements
### Redis
[AUTH string][auth] is a password for connection to Redis. If you have the `requirepass` directive set in your Redis configuration, incoming client connections must authenticate in order to connect.
Specify your AUTH string in the password field:
```yaml
sources:
my-redis-instance:
kind: redis
address:
- 127.0.0.1
username: ${MY_USER_NAME}
password: ${MY_AUTH_STRING} # Omit this field if you don't have a password.
# database: 0
# clusterEnabled: false
# useGCPIAM: false
```
{{< notice tip >}}
Use environment variable replacement with the format ${ENV_NAME}
instead of hardcoding your secrets into the configuration file.
{{< /notice >}}
### Memorystore For Redis
Memorystore standalone instances support authentication using an [AUTH][auth]
string.
Here is an example tools.yaml config with [AUTH][auth] enabled:
```yaml
sources:
my-redis-cluster-instance:
kind: memorystore-redis
address:
- 127.0.0.1
password: ${MY_AUTH_STRING}
# useGCPIAM: false
# clusterEnabled: false
```
Memorystore Redis Cluster supports IAM authentication instead. Grant your account the
required [IAM role][iam] and make sure to set `useGCPIAM` to `true`.
Here is an example tools.yaml config for Memorystore Redis Cluster instances
using IAM authentication:
```yaml
sources:
my-redis-cluster-instance:
kind: memorystore-redis
address: 127.0.0.1
useGCPIAM: true
clusterEnabled: true
```
[iam]: https://cloud.google.com/memorystore/docs/cluster/about-iam-auth
## Reference
| **field** | **type** | **required** | **description** |
|----------------|:--------:|:------------:|---------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "memorystore-redis". |
| address | string | true | Primary endpoint for the Memorystore Redis instance to connect to. |
| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Redis, leave this field blank |
| password | string | false | If you have [Redis AUTH][auth] enabled, specify the AUTH string here |
| database | int | false | The Redis database to connect to. Not applicable for cluster enabled instances. The default database is `0`. |
| clusterEnabled | bool | false | Set it to `true` if using a Redis Cluster instance. Defaults to `false`. |
| useGCPIAM | string | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. |
[auth]: https://cloud.google.com/memorystore/docs/redis/about-redis-auth

View File

@@ -0,0 +1,64 @@
---
title: "Valkey"
linkTitle: "Valkey"
type: docs
weight: 1
description: >
Valkey is an open-source, in-memory data structure store, forked from Redis.
---
## About
Valkey is an open-source, in-memory data structure store that originated as a fork of Redis. It's designed to be used as a database, cache, and message broker, supporting a wide range of data structures like strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, and geospatial indexes with radius queries.
If you're new to Valkey, you can find installation and getting started guides on the [official Valkey website](https://valkey.io/docs/getting-started/).
## Example
```yaml
sources:
my-valkey-instance:
kind: valkey
address:
- 127.0.0.1
username: ${YOUR_USERNAME}
password: ${YOUR_PASSWORD}
# database: 0
# useGCPIAM: false
# disableCache: false
```
{{< notice tip >}}
Use environment variable replacement with the format ${ENV_NAME}
instead of hardcoding your secrets into the configuration file.
{{< /notice >}}
### IAM Authentication
If you are using GCP's Memorystore for Valkey, you can connect using IAM
authentication. Grant your account the required [IAM role][iam] and set
`useGCPIAM` to `true`:
```yaml
sources:
my-valkey-instance:
kind: valkey
address:
- 127.0.0.1
useGCPIAM: true
```
[iam]: https://cloud.google.com/memorystore/docs/valkey/about-iam-auth
## Reference
| **field** | **type** | **required** | **description** |
|--------------|:--------:|:------------:|----------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "valkey". |
| address | []string | true | Endpoints for the Valkey instance to connect to. |
| username | string | false | If you are using a non-default user, specify the user name here. If you are using Memorystore for Valkey, leave this field blank |
| password | string | false | Password for the Valkey instance |
| database | int | false | The Valkey database to connect to. Not applicable for cluster enabled instances. The default database is `0`. |
| useGCPIAM | bool | false | Set it to `true` if you are using GCP's IAM authentication. Defaults to `false`. |
| disableCache | bool | false | Set it to `true` if you want to enable client-side caching. Defaults to `false`. |

View File

@@ -79,11 +79,12 @@ the parameter.
description: Airline unique 2 letter identifier
```
| **field** | **type** | **required** | **description** |
|-------------|:--------:|:------------:|----------------------------------------------------------------------------|
| name | string | true | Name of the parameter. |
| type | string | true | Must be one of "string", "integer", "float", "boolean" "array" |
| description | string | true | Natural language description of the parameter to describe it to the agent. |
| **field** | **type** | **required** | **description** |
|-------------|:---------------:|:------------:|-----------------------------------------------------------------------------|
| name | string | true | Name of the parameter. |
| type | string | true | Must be one of "string", "integer", "float", "boolean" "array" |
| default | parameter type | false | Default value of the parameter. If provided, the parameter is not required. |
| description | string | true | Natural language description of the parameter to describe it to the agent. |
### Array Parameters
@@ -102,12 +103,17 @@ in the list using the items field:
description: Name of the airline.
```
| **field** | **type** | **required** | **description** |
|-------------|:----------------:|:------------:|----------------------------------------------------------------------------|
| name | string | true | Name of the parameter. |
| type | string | true | Must be "array" |
| description | string | true | Natural language description of the parameter to describe it to the agent. |
| items | parameter object | true | Specify a Parameter object for the type of the values in the array. |
| **field** | **type** | **required** | **description** |
|-------------|:----------------:|:------------:|-----------------------------------------------------------------------------|
| name | string | true | Name of the parameter. |
| type | string | true | Must be "array" |
| default | parameter type | false | Default value of the parameter. If provided, the parameter is not required. |
| description | string | true | Natural language description of the parameter to describe it to the agent. |
| items | parameter object | true | Specify a Parameter object for the type of the values in the array. |
{{< notice note >}}
Items in array should not have a default value. If provided, it will be ignored.
{{< /notice >}}
### Authenticated Parameters
@@ -141,6 +147,58 @@ specific claims within the user's ID token.
| name | string | true | Name of the [authServices](../authservices) used to verify the OIDC auth token. |
| field | string | true | Claim field decoded from the OIDC token used to auto-populate this parameter. |
### Template Parameters
Template parameters types include `string`, `integer`, `float`, `boolean` types. In
most cases, the description will be provided to the LLM as context on specifying
the parameter. Template parameters will be inserted into the SQL statement before
executing the prepared statement. They will be inserted without quotes, so to
insert a string using template parameters, quotes must be explicitly added within
the string.
Template parameter arrays can also be used similarly to basic parameters, and array
items must be strings. Once inserted into the SQL statement, the outer layer of quotes
will be removed. Therefore to insert strings into the SQL statement, a set of quotes
must be explicitly added within the string.
{{< notice warning >}}
Because template parameters can directly replace identifiers, column names, and table names, they are prone to SQL injections. Basic parameters are preferred for performance and safety reasons.
{{< /notice >}}
```yaml
tools:
select_columns_from_table:
kind: postgres-sql
source: my-pg-instance
statement: |
SELECT {{array .columnNames}} FROM {{.tableName}}
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
"columnNames": ["id", "name"]
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
- name: columnNames
type: array
description: The columns to select
items:
name: column
type: string
description: Name of a column to select
```
| **field** | **type** | **required** | **description** |
|-------------|:----------------:|:-------------:|-------------------------------------------------------------------------------------|
| name | string | true | Name of the template parameter. |
| type | string | true | Must be one of "string", "integer", "float", "boolean" "array" |
| description | string | true | Natural language description of the template parameter to describe it to the agent. |
| items | parameter object |true (if array)| Specify a Parameter object for the type of the values in the array (string only). |
## Authorized Invocations
You can require an authorization check for any Tool invocation request by

View File

@@ -30,8 +30,7 @@ database layer.
## Requirements
{{< notice tip >}} AlloyDB AI natural language is currently in gated public
preview. For more information on availability and limitations, please see
[AlloyDB AI natural language
overview](https://cloud.google.com/alloydb/docs/natural-language-questions-overview)
[AlloyDB AI natural language overview](https://cloud.google.com/alloydb/docs/ai/natural-language-overview)
{{< /notice >}}
To enable AlloyDB AI natural language for your AlloyDB cluster, please follow
@@ -39,8 +38,8 @@ the steps listed in the [Generate SQL queries that answer natural language
questions][alloydb-ai-gen-nl], including enabling the extension and configuring
context for your application.
[alloydb-ai-nl-overview]: https://cloud.google.com/alloydb/docs/natural-language-questions-overview
[alloydb-ai-gen-nl]: https://cloud.google.com/alloydb/docs/alloydb/docs/ai/generate-queries-natural-language
[alloydb-ai-nl-overview]: https://cloud.google.com/alloydb/docs/ai/natural-language-overview
[alloydb-ai-gen-nl]: https://cloud.google.com/alloydb/docs/ai/generate-sql-queries-natural-language
## Configuration
@@ -70,7 +69,7 @@ Parameters](../tools/#array-parameters) or Bound Parameters to provide secure
access to queries generated using natural language, as these parameters are not
visible to the LLM.
[alloydb-psv]: https://cloud.google.com/alloydb/docs/ai/use-psvs#parameterized_secure_views
[alloydb-psv]: https://cloud.google.com/alloydb/docs/parameterized-secure-views-overview
## Example

View File

@@ -20,12 +20,16 @@ parameters can be inserted into the query. BigQuery supports both named paramete
(e.g., `@name`) and positional parameters (`?`), but they cannot be mixed in the
same query.
> **Note:** This tool uses [parameterized queries](https://cloud.google.com/bigquery/docs/parameterized-queries) to prevent SQL injections. Query parameters can be used as substitutes for arbitrary expressions. Parameters cannot be used as substitutes for identifiers, column names, table names, or other parts of the query.
[bigquery-googlesql]: https://cloud.google.com/bigquery/docs/reference/standard-sql/
## Example
> **Note:** This tool uses [parameterized
> queries](https://cloud.google.com/bigquery/docs/parameterized-queries) to
> prevent SQL injections. Query parameters can be used as substitutes for
> arbitrary expressions. Parameters cannot be used as substitutes for
> identifiers, column names, table names, or other parts of the query.
```yaml
tools:
# Example: Querying a user table in BigQuery
@@ -59,12 +63,40 @@ tools:
description: Email address of the user
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: bigquery-sql
source: my-bigquery-source
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "bigquery-sql". |
| source | string | true | Name of the source the GoogleSQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | The GoogleSQL statement to execute. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "bigquery-sql". |
| source | string | true | Name of the source the GoogleSQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | The GoogleSQL statement to execute. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -21,15 +21,15 @@ dialect, the specified SQL statement is executed as a [data manipulation
language (DML)][bigtable-googlesql] statements, and specified parameters will
inserted according to their name: e.g. `@name`.
[bigtable-googlesql]: https://cloud.google.com/bigtable/docs/googlesql-overview
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
[bigtable-googlesql]: https://cloud.google.com/bigtable/docs/googlesql-overview
## Example
```yaml
tools:
search_user_by_id_or_name:
@@ -62,15 +62,43 @@ tools:
description: Name of the user
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: bigtable-sql
source: my-bigtable-instance
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "bigtable-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "bigtable-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
## Tips

View File

@@ -17,13 +17,13 @@ database. It's compatible with any of the following sources:
The specified SQL statement is executed as a parameterized statement, and specified
parameters will be used according to their name: e.g. `$id`.
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
## Example
```yaml
tools:
search_products_by_category:
@@ -58,13 +58,41 @@ tools:
description: Maximum price (positive integer)
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: couchbase-sql
source: my-couchbase-instance
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "couchbase-sql". |
| source | string | true | Name of the source the SQL query should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be used with the SQL statement. |
| authRequired| array[string] | false | List of auth services that are required to use this tool. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "couchbase-sql". |
| source | string | true | Name of the source the SQL query should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be used with the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
| authRequired | array[string] | false | List of auth services that are required to use this tool. |

View File

@@ -16,7 +16,12 @@ Toolbox allows you to configure the request URL, method, headers, query paramete
### URL
An HTTP request URL identifies the target the client wants to access.
Toolbox composes the request URL from the HTTP Source's `baseUrl` and the HTTP Tool's `path`.
Toolbox composes the request URL from 3 places:
1. The HTTP Source's `baseUrl`.
2. The HTTP Tool's `path` field.
3. The HTTP Tool's `pathParams` for dynamic path composed during Tool invocation.
For example, the following config allows you to reach different paths of the same server using multiple Tools:
```yaml
@@ -39,6 +44,17 @@ tools:
method: GET
path: /search
description: Tool to search information from the example API
my-dynamic-path-tool:
kind: http
source: my-http-source
method: GET
path: /{{.myPathParam}}/search
description: Tool to reach endpoint based on the input to `myPathParam`
pathParams:
- name: myPathParam
type: string
description: The dynamic path parameter
```

View File

@@ -23,15 +23,15 @@ Server and expects parameters in the SQL query to be in the form of either
db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob")
```
[prepare-statement]: https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-prepare-transact-sql?view=sql-server-ver16
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
[prepare-statement]: https://learn.microsoft.com/sql/relational-databases/system-stored-procedures/sp-prepare-transact-sql?view=sql-server-ver16
## Example
```yaml
tools:
search_flights_by_number:
@@ -70,12 +70,40 @@ tools:
description: 1 to 4 digit number
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: mssql-sql
source: my-instance
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "mssql-sql". |
| source | string | true | Name of the source the T-SQL statement should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "mssql-sql". |
| source | string | true | Name of the source the T-SQL statement should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -18,15 +18,15 @@ database. It's compatible with any of the following sources:
The specified SQL statement is executed as a [prepared statement][mysql-prepare],
and expects parameters in the SQL query to be in the form of placeholders `?`.
[mysql-prepare]: https://dev.mysql.com/doc/refman/8.4/en/sql-prepared-statements.html
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
[mysql-prepare]: https://dev.mysql.com/doc/refman/8.4/en/sql-prepared-statements.html
## Example
```yaml
tools:
search_flights_by_number:
@@ -65,12 +65,40 @@ tools:
description: 1 to 4 digit number
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: mysql-sql
source: my-mysql-instance
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "mysql-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "mysql-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -19,17 +19,18 @@ database. It's compatible with any of the following sources:
The specified SQL statement is executed as a [prepared statement][pg-prepare],
and specified parameters will inserted according to their position: e.g. `1`
will be the first parameter specified, `$@` will be the second parameter, and so
on.
on. If template parameters are included, they will be resolved before execution
of the prepared statement.
[pg-prepare]: https://www.postgresql.org/docs/current/sql-prepare.html
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
[pg-prepare]: https://www.postgresql.org/docs/current/sql-prepare.html
## Example
```yaml
tools:
search_flights_by_number:
@@ -68,12 +69,40 @@ tools:
description: 1 to 4 digit number
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: postgres-sql
source: my-pg-instance
statement: |
SELECT * FROM {{.tableName}}
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "postgres-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| **field** | **type** | **required** | **description** |
|---------------------|:---------------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "postgres-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -0,0 +1,57 @@
---
title: "redis"
type: docs
weight: 1
description: >
A "redis" tool executes a set of pre-defined Redis commands against a Redis instance.
---
## About
A redis tool executes a series of pre-defined Redis commands against a
Redis source.
The specified Redis commands are executed sequentially. Each command is
represented as a string list, where the first element is the command name (e.g., SET,
GET, HGETALL) and subsequent elements are its arguments.
### Dynamic Command Parameters
Command arguments can be templated using the `$variableName` annotation. The
array type parameters will be expanded once into multiple arguments. Take the
following config for example:
```yaml
commands:
- [SADD, userNames, $userNames] # Array will be flattened into multiple arguments.
parameters:
- name: userNames
type: array
description: The user names to be set.
```
If the input is an array of strings `["Alice", "Sid", "Bob"]`, The final command
to be executed after argument expansion will be `[SADD, userNames, Alice, Sid, Bob]`.
## Example
```yaml
tools:
user_data_tool:
kind: redis
source: my-redis-instance
description: |
Use this tool to interact with user data stored in Redis.
It can set, retrieve, and delete user-specific information.
commands:
- [SADD, userNames, $userNames] # Array will be flattened into multiple arguments.
- [GET, $userId]
parameters:
- name: userId
type: string
description: The unique identifier for the user.
- name: userNames
type: array
description: The user names to be set.
```

View File

@@ -35,15 +35,15 @@ statement][pg-prepare], and specified parameters will inserted according to
their position: e.g. `$1` will be the first parameter specified, `$@` will be
the second parameter, and so on.
[pg-prepare]: https://www.postgresql.org/docs/current/sql-prepare.html
## Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
[pg-prepare]: https://www.postgresql.org/docs/current/sql-prepare.html
## Example
{{< tabpane persist="header" >}}
{{< tab header="GoogleSQL" lang="yaml" >}}
@@ -125,13 +125,41 @@ tools:
{{< /tab >}}
{{< /tabpane >}}
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: spanner
source: my-spanner-instance
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "spanner-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| readOnly | bool | false | When set to `true`, the `statement` is run as a read-only transaction. Default: `false`. |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "spanner-sql". |
| source | string | true | Name of the source the SQL should execute on. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | SQL statement to execute on. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| readOnly | bool | false | When set to `true`, the `statement` is run as a read-only transaction. Default: `false`. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -20,13 +20,13 @@ The statement field supports any valid SQLite SQL statement, including `SELECT`,
`INSERT`, `UPDATE`, `DELETE`, `CREATE/ALTER/DROP` table statements, and other
DDL statements.
### Example
> **Note:** This tool uses parameterized queries to prevent SQL injections.
> Query parameters can be used as substitutes for arbitrary expressions.
> Parameters cannot be used as substitutes for identifiers, column names, table
> names, or other parts of the query.
### Example
```yaml
tools:
search-users:
@@ -43,12 +43,41 @@ tools:
statement: SELECT * FROM users WHERE name LIKE ? AND age >= ?
```
### Example with Template Parameters
> **Note:** This tool allows direct modifications to the SQL statement,
> including identifiers, column names, and table names. **This makes it more
> vulnerable to SQL injections**. Using basic parameters only (see above) is
> recommended for performance and safety reasons. For more details, please check
> [templateParameters](_index#template-parameters).
```yaml
tools:
list_table:
kind: sqlite-sql
source: my-sqlite-db
statement: |
SELECT * FROM {{.tableName}};
description: |
Use this tool to list all information from a specific table.
Example:
{{
"tableName": "flights",
}}
templateParameters:
- name: tableName
type: string
description: Table to select from
```
## Reference
| **field** | **type** | **required** | **description** |
|-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------|
| kind | string | Yes | Must be "sqlite-sql" |
| source | string | Yes | Name of a SQLite source configuration |
| description | string | Yes | Description of what the tool does |
| parameters | array | No | List of parameters for the SQL statement |
| statement | string | Yes | The SQL statement to execute |
| **field** | **type** | **required** | **description** |
|--------------------|:------------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------------------------------------------------|
| kind | string | true | Must be "sqlite-sql". |
| source | string | true | Name of the source the SQLite source configuration. |
| description | string | true | Description of the tool that is passed to the LLM. |
| statement | string | true | The SQL statement to execute. |
| parameters | [parameters](_index#specifying-parameters) | false | List of [parameters](_index#specifying-parameters) that will be inserted into the SQL statement. |
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |

View File

@@ -0,0 +1,56 @@
---
title: "valkey"
type: docs
weight: 1
description: >
A "valkey" tool executes a set of pre-defined Valkey commands against a Memorystore for Valkey instance.
---
## About
A valkey tool executes a series of pre-defined Valkey commands against a
Memorystore for Valkey instance.
The specified Valkey commands are executed sequentially. Each command is
represented as a string array, where the first element is the command name (e.g., SET,
GET, HGETALL) and subsequent elements are its arguments.
### Dynamic Command Parameters
Command arguments can be templated using the `$variableName` annotation. The
array type parameters will be expanded once into multiple arguments. Take the
following config for example:
```yaml
commands:
- [SADD, userNames, $userNames] # Array will be flattened into multiple arguments.
parameters:
- name: userNames
type: array
description: The user names to be set.
```
If the input is an array of strings `["Alice", "Sid", "Bob"]`, The final command
to be executed after argument expansion will be `[SADD, userNames, Alice, Sid, Bob]`.
## Example
```yaml
tools:
user_data_tool:
kind: valkey
source: my-valkey-instance
description: |
Use this tool to interact with user data stored in Valkey.
It can set, retrieve, and delete user-specific information.
commands:
- [SADD, userNames, $userNames] # Array will be flattened into multiple arguments.
- [GET, $userId]
parameters:
- name: userId
type: string
description: The unique identifier for the user.
- name: userNames
type: array
description: The user names to be set.
```

View File

@@ -220,7 +220,7 @@
},
"outputs": [],
"source": [
"version = \"0.6.0\" # x-release-please-version\n",
"version = \"0.7.0\" # x-release-please-version\n",
"! curl -O https://storage.googleapis.com/genai-toolbox/v{version}/linux/amd64/toolbox\n",
"\n",
"# Make the binary executable\n",

View File

@@ -32,6 +32,13 @@ This guide assumes you have already done the following:
```
1. Completed setup for usage with an LLM model such as
{{< tabpane text=true persist=header >}}
{{% tab header="Core" lang="en" %}}
- [langchain-vertexai](https://python.langchain.com/docs/integrations/llms/google_vertex_ai_palm/#setup) package.
- [langchain-google-genai](https://python.langchain.com/docs/integrations/chat/google_generative_ai/#setup) package.
- [langchain-anthropic](https://python.langchain.com/docs/integrations/chat/anthropic/#setup) package.
{{% /tab %}}
{{% tab header="LangChain" lang="en" %}}
- [langchain-vertexai](https://python.langchain.com/docs/integrations/llms/google_vertex_ai_palm/#setup) package.
@@ -131,7 +138,7 @@ In this section, we will download Toolbox, configure our tools in a `tools.yaml`
<!-- {x-release-please-start-version} -->
```bash
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/$OS/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
```
<!-- {x-release-please-end} -->
@@ -246,6 +253,10 @@ you can connect to a
1. In a new terminal, install the SDK package.
{{< tabpane persist=header >}}
{{< tab header="Core" lang="bash" >}}
pip install toolbox-core
{{< /tab >}}
{{< tab header="Langchain" lang="bash" >}}
pip install toolbox-langchain
@@ -262,8 +273,15 @@ pip install google-adk
{{< /tabpane >}}
1. Install other required dependencies:
{{< tabpane persist=header >}}
{{< tab header="Core" lang="bash" >}}
# TODO(developer): replace with correct package if needed
pip install langgraph langchain-google-vertexai
# pip install langchain-google-genai
# pip install langchain-anthropic
{{< /tab >}}
{{< tab header="Langchain" lang="bash" >}}
# TODO(developer): replace with correct package if needed
@@ -285,8 +303,120 @@ pip install toolbox-core
1. Create a new file named `hotel_agent.py` and copy the following
code to create an agent:
{{< tabpane persist=header >}}
{{< tab header="Core" lang="python" >}}
import asyncio
from google import genai
from google.genai.types import (
Content,
FunctionDeclaration,
GenerateContentConfig,
Part,
Tool,
)
from toolbox_core import ToolboxClient
prompt = """
You're a helpful hotel assistant. You handle hotel searching, booking and
cancellations. When the user searches for a hotel, mention it's name, id,
location and price tier. Always mention hotel id while performing any
searches. This is very important for any operations. For any bookings or
cancellations, please provide the appropriate confirmation. Be sure to
update checkin or checkout dates if mentioned by the user.
Don't ask for confirmations from the user.
"""
queries = [
"Find hotels in Basel with Basel in it's name.",
"Please book the hotel Hilton Basel for me.",
"This is too expensive. Please cancel it.",
"Please book Hyatt Regency for me",
"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.",
]
async def run_application():
async with ToolboxClient("http://127.0.0.1:5000") as toolbox_client:
# The toolbox_tools list contains Python callables (functions/methods) designed for LLM tool-use
# integration. While this example uses Google's genai client, these callables can be adapted for
# various function-calling or agent frameworks. For easier integration with supported frameworks
# (https://github.com/googleapis/mcp-toolbox-python-sdk/tree/main/packages), use the
# provided wrapper packages, which handle framework-specific boilerplate.
toolbox_tools = await toolbox_client.load_toolset("my-toolset")
genai_client = genai.Client(
vertexai=True, project="project-id", location="us-central1"
)
genai_tools = [
Tool(
function_declarations=[
FunctionDeclaration.from_callable_with_api_option(callable=tool)
]
)
for tool in toolbox_tools
]
history = []
for query in queries:
user_prompt_content = Content(
role="user",
parts=[Part.from_text(text=query)],
)
history.append(user_prompt_content)
response = genai_client.models.generate_content(
model="gemini-2.0-flash-001",
contents=history,
config=GenerateContentConfig(
system_instruction=prompt,
tools=genai_tools,
),
)
history.append(response.candidates[0].content)
function_response_parts = []
for function_call in response.function_calls:
fn_name = function_call.name
# The tools are sorted alphabetically
if fn_name == "search-hotels-by-name":
function_result = await toolbox_tools[3](**function_call.args)
elif fn_name == "search-hotels-by-location":
function_result = await toolbox_tools[2](**function_call.args)
elif fn_name == "book-hotel":
function_result = await toolbox_tools[0](**function_call.args)
elif fn_name == "update-hotel":
function_result = await toolbox_tools[4](**function_call.args)
elif fn_name == "cancel-hotel":
function_result = await toolbox_tools[1](**function_call.args)
else:
raise ValueError("Function name not present.")
function_response = {"result": function_result}
function_response_part = Part.from_function_response(
name=function_call.name,
response=function_response,
)
function_response_parts.append(function_response_part)
if function_response_parts:
tool_response_content = Content(role="tool", parts=function_response_parts)
history.append(tool_response_content)
response2 = genai_client.models.generate_content(
model="gemini-2.0-flash-001",
contents=history,
config=GenerateContentConfig(
tools=genai_tools,
),
)
final_model_response_content = response2.candidates[0].content
history.append(final_model_response_content)
print(response2.text)
asyncio.run(run_application())
{{< /tab >}}
{{< tab header="LangChain" lang="python" >}}
import asyncio
from langgraph.prebuilt import create_react_agent
# TODO(developer): replace this with another import if needed
from langchain_google_vertexai import ChatVertexAI
@@ -313,25 +443,25 @@ queries = [
"My check in dates would be from April 10, 2024 to April 19, 2024.",
]
def main():
async def main():
# TODO(developer): replace this with another model if needed
model = ChatVertexAI(model_name="gemini-2.0-flash-001")
# model = ChatGoogleGenerativeAI(model="gemini-2.0-flash-001")
# model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
# Load the tools from the Toolbox server
async with ToolboxClient("http://127.0.0.1:5000") as client:
tools = client.load_toolset()
client = ToolboxClient("http://127.0.0.1:5000")
tools = await client.aload_toolset()
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "thread-1"}}
for query in queries:
inputs = {"messages": [("user", prompt + query)]}
response = agent.invoke(inputs, stream_mode="values", config=config)
print(response["messages"][-1].content)
config = {"configurable": {"thread_id": "thread-1"}}
for query in queries:
inputs = {"messages": [("user", prompt + query)]}
response = await agent.ainvoke(inputs, stream_mode="values", config=config)
print(response["messages"][-1].content)
main()
asyncio.run(main())
{{< /tab >}}
{{< tab header="LlamaIndex" lang="python" >}}
import asyncio
@@ -380,19 +510,19 @@ async def main():
# )
# Load the tools from the Toolbox server
async with ToolboxClient("http://127.0.0.1:5000") as client:
tools = client.load_toolset()
client = ToolboxClient("http://127.0.0.1:5000")
tools = await client.aload_toolset()
agent = AgentWorkflow.from_tools_or_functions(
tools,
llm=llm,
system_prompt=prompt,
)
ctx = Context(agent)
for query in queries:
response = await agent.run(user_msg=query, ctx=ctx)
print(f"---- {query} ----")
print(str(response))
agent = AgentWorkflow.from_tools_or_functions(
tools,
llm=llm,
system_prompt=prompt,
)
ctx = Context(agent)
for query in queries:
response = await agent.arun(user_msg=query, ctx=ctx)
print(f"---- {query} ----")
print(str(response))
asyncio.run(main())
{{< /tab >}}
@@ -479,6 +609,9 @@ with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client:
{{< /tabpane >}}
{{< tabpane text=true persist=header >}}
{{% tab header="Core" lang="en" %}}
To learn more about the Core SDK, check out the [Toolbox Core SDK documentation.](https://github.com/googleapis/genai-toolbox/tree/main/sdks/toolbox-core)
{{% /tab %}}
{{% tab header="Langchain" lang="en" %}}
To learn more about Agents in LangChain, check out the [LangGraph Agent documentation.](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent)
{{% /tab %}}

View File

@@ -84,7 +84,7 @@ In this section, we will download Toolbox, configure our tools in a `tools.yaml`
<!-- {x-release-please-start-version} -->
```bash
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
curl -O https://storage.googleapis.com/genai-toolbox/v0.6.0/$OS/toolbox
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
```
<!-- {x-release-please-end} -->

56
go.mod
View File

@@ -2,30 +2,33 @@ module github.com/googleapis/genai-toolbox
go 1.23.8
toolchain go1.24.3
toolchain go1.24.4
require (
cloud.google.com/go/alloydbconn v1.15.2
cloud.google.com/go/alloydbconn v1.15.3
cloud.google.com/go/bigquery v1.69.0
cloud.google.com/go/bigtable v1.37.0
cloud.google.com/go/cloudsqlconn v1.17.1
cloud.google.com/go/cloudsqlconn v1.17.2
cloud.google.com/go/spanner v1.82.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.52.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.28.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0
github.com/couchbase/gocb/v2 v2.10.0
github.com/couchbase/tools-common/http v1.0.9
github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/chi/v5 v5.2.2
github.com/go-chi/httplog/v2 v2.1.1
github.com/go-chi/render v1.0.3
github.com/go-playground/validator/v10 v10.26.0
github.com/go-sql-driver/mysql v1.9.2
github.com/go-sql-driver/mysql v1.9.3
github.com/goccy/go-yaml v1.18.0
github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.5
github.com/json-iterator/go v1.1.12
github.com/microsoft/go-mssqldb v1.8.2
github.com/neo4j/neo4j-go-driver/v5 v5.28.1
github.com/redis/go-redis/v9 v9.10.0
github.com/spf13/cobra v1.9.1
github.com/valkey-io/valkey-go v1.0.61
go.opentelemetry.io/contrib/propagators/autoprop v0.61.0
go.opentelemetry.io/otel v1.36.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0
@@ -35,17 +38,17 @@ require (
go.opentelemetry.io/otel/sdk/metric v1.36.0
go.opentelemetry.io/otel/trace v1.36.0
golang.org/x/oauth2 v0.30.0
google.golang.org/api v0.236.0
modernc.org/sqlite v1.37.1
google.golang.org/api v0.238.0
modernc.org/sqlite v1.38.0
)
require golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
require (
cel.dev/expr v0.20.0 // indirect
cel.dev/expr v0.23.0 // indirect
cloud.google.com/go v0.121.0 // indirect
cloud.google.com/go/alloydb v1.15.2 // indirect
cloud.google.com/go/auth v0.16.1 // indirect
cloud.google.com/go/alloydb v1.16.1 // indirect
cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
@@ -55,17 +58,18 @@ require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.52.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/apache/arrow/go/v15 v15.0.2 // indirect
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect
github.com/couchbase/gocbcore/v10 v10.7.0 // indirect
github.com/couchbase/gocbcoreps v0.1.3 // indirect
github.com/couchbase/goprotostellar v1.0.2 // indirect
github.com/couchbase/tools-common/errors v1.0.0 // indirect
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
@@ -96,6 +100,8 @@ require (
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
@@ -108,7 +114,7 @@ require (
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/contrib/propagators/aws v1.36.0 // indirect
go.opentelemetry.io/contrib/propagators/b3 v1.36.0 // indirect
@@ -118,21 +124,21 @@ require (
go.opentelemetry.io/proto/otlp v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.25.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.33.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/grpc v1.72.2 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
modernc.org/libc v1.65.7 // indirect
modernc.org/libc v1.65.10 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect
)

124
go.sum
View File

@@ -1,5 +1,5 @@
cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI=
cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
cel.dev/expr v0.23.0 h1:wUb94w6OYQS4uXraxo9U+wUAs9jT47Xvl4iPgAwM2ss=
cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -53,10 +53,10 @@ cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9j
cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ=
cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k=
cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw=
cloud.google.com/go/alloydb v1.15.2 h1:wW1uQy39jkK9O5KApw1TJlQG592aJ4AuegT7sJ9bmRM=
cloud.google.com/go/alloydb v1.15.2/go.mod h1:gWJaNDqS51UTSFFRf+VdO9FyvCxmPNic05rmDX8GP5M=
cloud.google.com/go/alloydbconn v1.15.2 h1:mAYPxiMXSrbVmLNnpF5QHT3sYcbQ4Ohibb7AYReIoQw=
cloud.google.com/go/alloydbconn v1.15.2/go.mod h1:EjJMii4lmPi/wxLThjQ/uMJFNUCqLAAjQINNcuFX7eY=
cloud.google.com/go/alloydb v1.16.1 h1:pW4D0O2jAfAjoOEI1bgChPwMHWE8X8BjwSO0tfWkWvk=
cloud.google.com/go/alloydb v1.16.1/go.mod h1:zeZuGJ5mEaQE70FMXEvZIp5hQLR9yrGnHo1YUOncWRY=
cloud.google.com/go/alloydbconn v1.15.3 h1:j0Y0+LpVjdyUguX0uwsaeTtq4tQUZiFvsO52AH+yusY=
cloud.google.com/go/alloydbconn v1.15.3/go.mod h1:9yrNzUeMr3wR/D4gTJrh5ph2VDW/19tAMV7TlNuyRfM=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4=
cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M=
@@ -105,8 +105,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo
cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo=
cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0=
cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E=
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4=
cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA=
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0=
@@ -167,8 +167,8 @@ cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb
cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM=
cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk=
cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA=
cloud.google.com/go/cloudsqlconn v1.17.1 h1:jnBDOtliNASkHivU+gIs8Hk9govggDD0UYO1e/MnrYg=
cloud.google.com/go/cloudsqlconn v1.17.1/go.mod h1:jfz0XbsYVQAfwbK4hFCjpgPnyQyA7sOektt2t2hXw3o=
cloud.google.com/go/cloudsqlconn v1.17.2 h1:SxSt6ujMxK1KyxKAI2Z5raT2n3geN7ipu6bA8f7iR7E=
cloud.google.com/go/cloudsqlconn v1.17.2/go.mod h1:l7NymuoD+hycOo+92SJEyETPtE05oRG4oXjcH3swftw=
cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY=
cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI=
cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4=
@@ -651,14 +651,14 @@ github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.52.0 h1:QFgWzcdmJlgEAwJz/zePYVJQxfoJGRtgIqZfIUFg5oQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.52.0/go.mod h1:ayYHuYU7iNcNtEs1K9k6D/Bju7u1VEHMQm5qQ1n3GtM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.28.0 h1:RC78FvsZ8rLRLgVQuw1jMJ8d6t38QgOv3hDoUVGD50U=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.28.0/go.mod h1:03+QlJ+6zSrBaVaZ9K87fzUyKBDcAh0X1n1Vxq3XAjc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.52.0 h1:0l8ynskVvq1dvIn5vJbFMf/a/3TqFpRmCMrruFbzlvk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.52.0/go.mod h1:f/ad5NuHnYz8AOZGuR0cY+l36oSCstdxD73YlIchr6I=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.52.0 h1:wbMd4eG/fOhsCa6+IP8uEDvWF5vl7rNoUWmP5f72Tbs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.52.0/go.mod h1:gdIm9TxRk5soClCwuB0FtdXsbqtw0aqPwBEurK9tPkw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0 h1:YVtMlmfRUTaWs3+1acwMBp7rBUo6zrxl6Kn13/R9YW4=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0/go.mod h1:rKOFVIPbNs2wZeh7ZeQ0D9p/XLgbNiTr5m7x6KuAshk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
@@ -677,6 +677,10 @@ github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -704,8 +708,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k=
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/couchbase/gocb/v2 v2.10.0 h1:NNxZ4okToU1Ylqp6F8tE41CEJQPhb2WjufryAkeubOk=
github.com/couchbase/gocb/v2 v2.10.0/go.mod h1:OSbMfQkP7ltbKiDZhsT2mGDhkQNmvGXxptKcxAUJQ2Y=
github.com/couchbase/gocbcore/v10 v10.7.0 h1:lAEi0PNeEGKOu8pWrPUdtLOT2oGr1J/UTdGHVPC3r/0=
@@ -728,6 +732,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -762,8 +768,8 @@ github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzP
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk=
github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
@@ -797,8 +803,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
@@ -879,6 +885,7 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -971,6 +978,8 @@ github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
@@ -1009,10 +1018,17 @@ github.com/microsoft/go-mssqldb v1.8.2 h1:236sewazvC8FvG6Dr3bszrVhMkAl4KYImryLkR
github.com/microsoft/go-mssqldb v1.8.2/go.mod h1:vp38dT33FGfVotRiTmDo3bFyaHq+p3LektQrjTULowo=
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY=
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/neo4j/neo4j-go-driver/v5 v5.28.1 h1:RKWQW7wTgYAY2fU9S+9LaJ9OwRPbRc0I17tlT7nDmAY=
github.com/neo4j/neo4j-go-driver/v5 v5.28.1/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
@@ -1035,6 +1051,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -1074,6 +1092,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valkey-io/valkey-go v1.0.61 h1:uz7gxSs4dKqLfaa8xKFo8wHaCWYSCD3lMhVL0OJifZA=
github.com/valkey-io/valkey-go v1.0.61/go.mod h1:bHmwjIEOrGq/ubOJfh5uMRs7Xj6mV3mQ/ZXUbmqpjqY=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1102,8 +1122,8 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/detectors/gcp v1.35.0 h1:bGvFt68+KTiAKFlacHW6AhA56GF2rS0bdD3aJYEnmzA=
go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/contrib/propagators/autoprop v0.61.0 h1:cxOVDJ30qfzV27G5p9WMtJUB/3cXC0iL+u9EV1fSOws=
@@ -1156,8 +1176,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1217,8 +1237,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1276,8 +1296,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1325,8 +1345,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1432,16 +1452,16 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1585,8 +1605,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/
google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI=
google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0=
google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg=
google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0=
google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4=
google.golang.org/api v0.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1729,10 +1749,10 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 h1:1tXaIXCracvtsRxSBsYDiSBN0cuJvM7QYW+MrpIRY78=
google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk=
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0=
google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -1774,8 +1794,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1831,8 +1851,8 @@ modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJD
modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU=
modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8=
modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/fileutil v1.3.3 h1:3qaU+7f7xxTUmvU1pJTZiDLAIoJVdUSSauJNHg9yXoA=
modernc.org/fileutil v1.3.3/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
@@ -1843,8 +1863,8 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
modernc.org/libc v1.65.7 h1:Ia9Z4yzZtWNtUIuiPuQ7Qf7kxYrxP1/jeHZzG8bFu00=
modernc.org/libc v1.65.7/go.mod h1:011EQibzzio/VX3ygj1qGFt5kMjP0lHb0qCW5/D/pQU=
modernc.org/libc v1.65.10 h1:ZwEk8+jhW7qBjHIT+wd0d9VjitRyQef9BnzlzGwMODc=
modernc.org/libc v1.65.10/go.mod h1:StFvYpx7i/mXtBAfVOjaU0PWZOvIRoZSgXhrwXzr8Po=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
@@ -1862,8 +1882,8 @@ modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/sqlite v1.37.1 h1:EgHJK/FPoqC+q2YBXg7fUmES37pCHFc97sI7zSayBEs=
modernc.org/sqlite v1.37.1/go.mod h1:XwdRtsE1MpiBcL54+MbKcaDvcuej+IYSMfLN6gSKV8g=
modernc.org/sqlite v1.38.0 h1:+4OrfPQ8pxHKuWG4md1JpR/EYAh3Md7TdejuuzE7EUI=
modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=

View File

@@ -17,7 +17,7 @@ package prebuiltconfigs
import (
"embed"
"fmt"
"path/filepath"
"path"
"strings"
)
@@ -66,7 +66,7 @@ func loadPrebuiltToolYAMLs() (map[string][]byte, []string, error) {
for _, entry := range entries {
lowerName := strings.ToLower(entry.Name())
if !entry.IsDir() && (strings.HasSuffix(lowerName, ".yaml")) {
filePathInFS := filepath.Join("tools", entry.Name())
filePathInFS := path.Join("tools", entry.Name())
content, err := prebuiltConfigsFS.ReadFile(filePathInFS)
if err != nil {
errMsg := fmt.Errorf("failed to read a prebuilt tool %w", err)

View File

@@ -22,21 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/auth"
"github.com/googleapis/genai-toolbox/internal/auth/google"
"github.com/googleapis/genai-toolbox/internal/sources"
alloydbpgsrc "github.com/googleapis/genai-toolbox/internal/sources/alloydbpg"
bigquerysrc "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
bigtablesrc "github.com/googleapis/genai-toolbox/internal/sources/bigtable"
cloudsqlmssqlsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmssql"
cloudsqlmysqlsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmysql"
cloudsqlpgsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
couchbasesrc "github.com/googleapis/genai-toolbox/internal/sources/couchbase"
dgraphsrc "github.com/googleapis/genai-toolbox/internal/sources/dgraph"
httpsrc "github.com/googleapis/genai-toolbox/internal/sources/http"
mssqlsrc "github.com/googleapis/genai-toolbox/internal/sources/mssql"
mysqlsrc "github.com/googleapis/genai-toolbox/internal/sources/mysql"
neo4jsrc "github.com/googleapis/genai-toolbox/internal/sources/neo4j"
postgressrc "github.com/googleapis/genai-toolbox/internal/sources/postgres"
spannersrc "github.com/googleapis/genai-toolbox/internal/sources/spanner"
sqlitesrc "github.com/googleapis/genai-toolbox/internal/sources/sqlite"
"github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
)
@@ -145,108 +130,23 @@ func (c *SourceConfigs) UnmarshalYAML(ctx context.Context, unmarshal func(interf
kind, ok := v["kind"]
if !ok {
return fmt.Errorf("missing 'kind' field for %q", name)
return fmt.Errorf("missing 'kind' field for source %q", name)
}
kindStr, ok := kind.(string)
if !ok {
return fmt.Errorf("invalid 'kind' field for source %q (must be a string)", name)
}
dec, err := util.NewStrictDecoder(v)
yamlDecoder, err := util.NewStrictDecoder(v)
if err != nil {
return fmt.Errorf("error creating decoder: %w", err)
}
switch kind {
case alloydbpgsrc.SourceKind:
actual := alloydbpgsrc.Config{Name: name, IPType: "public"}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case bigtablesrc.SourceKind:
actual := bigtablesrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case cloudsqlpgsrc.SourceKind:
actual := cloudsqlpgsrc.Config{Name: name, IPType: "public"}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case postgressrc.SourceKind:
actual := postgressrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case cloudsqlmysqlsrc.SourceKind:
actual := cloudsqlmysqlsrc.Config{Name: name, IPType: "public"}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case mysqlsrc.SourceKind:
actual := mysqlsrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case spannersrc.SourceKind:
actual := spannersrc.Config{Name: name, Dialect: "googlesql"}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case neo4jsrc.SourceKind:
actual := neo4jsrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case cloudsqlmssqlsrc.SourceKind:
actual := cloudsqlmssqlsrc.Config{Name: name, IPType: "public"}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case mssqlsrc.SourceKind:
actual := mssqlsrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case dgraphsrc.SourceKind:
actual := dgraphsrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case httpsrc.SourceKind:
actual := httpsrc.DefaultConfig(name)
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case bigquerysrc.SourceKind:
actual := bigquerysrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case sqlitesrc.SourceKind:
actual := sqlitesrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
case couchbasesrc.SourceKind:
actual := couchbasesrc.Config{Name: name}
if err := dec.DecodeContext(ctx, &actual); err != nil {
return fmt.Errorf("unable to parse as %q: %w", kind, err)
}
(*c)[name] = actual
default:
return fmt.Errorf("%q is not a valid kind of data source", kind)
return fmt.Errorf("error creating YAML decoder for source %q: %w", name, err)
}
sourceConfig, err := sources.DecodeConfig(ctx, kindStr, name, yamlDecoder)
if err != nil {
return err
}
(*c)[name] = sourceConfig
}
return nil
}

View File

@@ -21,6 +21,7 @@ import (
"strings"
"cloud.google.com/go/alloydbconn"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/jackc/pgx/v5/pgxpool"
@@ -32,6 +33,20 @@ const SourceKind string = "alloydb-postgres"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, IPType: "public"} // Default IPType
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -159,7 +159,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"alloydb-postgres\": ipType invalid: must be one of \"public\", or \"private\"",
err: "unable to parse source \"my-pg-instance\" as \"alloydb-postgres\": ipType invalid: must be one of \"public\", or \"private\"",
},
{
desc: "extra field",
@@ -176,7 +176,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"alloydb-postgres\": [3:1] unknown field \"foo\"\n 1 | cluster: my-cluster\n 2 | database: my_db\n> 3 | foo: bar\n ^\n 4 | instance: my-instance\n 5 | kind: alloydb-postgres\n 6 | password: my_pass\n 7 | ",
err: "unable to parse source \"my-pg-instance\" as \"alloydb-postgres\": [3:1] unknown field \"foo\"\n 1 | cluster: my-cluster\n 2 | database: my_db\n> 3 | foo: bar\n ^\n 4 | instance: my-instance\n 5 | kind: alloydb-postgres\n 6 | password: my_pass\n 7 | ",
},
{
desc: "missing required field",
@@ -191,7 +191,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"alloydb-postgres\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
err: "unable to parse source \"my-pg-instance\" as \"alloydb-postgres\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -19,12 +19,12 @@ import (
"fmt"
bigqueryapi "cloud.google.com/go/bigquery"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
"golang.org/x/oauth2/google"
"google.golang.org/api/option"
)
const SourceKind string = "bigquery"
@@ -32,6 +32,20 @@ const SourceKind string = "bigquery"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
// BigQuery configs
Name string `yaml:"name" validate:"required"`

View File

@@ -83,17 +83,17 @@ func TestFailParseFromYaml(t *testing.T) {
location: us
foo: bar
`,
err: "unable to parse as \"bigquery\": [1:1] unknown field \"foo\"\n> 1 | foo: bar\n ^\n 2 | kind: bigquery\n 3 | location: us\n 4 | project: my-project",
err: "unable to parse source \"my-instance\" as \"bigquery\": [1:1] unknown field \"foo\"\n> 1 | foo: bar\n ^\n 2 | kind: bigquery\n 3 | location: us\n 4 | project: my-project",
},
{
desc: "missing required field",
in: `
sources:
my-mysql-instance:
my-instance:
kind: bigquery
location: us
`,
err: "unable to parse as \"bigquery\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
err: "unable to parse source \"my-instance\" as \"bigquery\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"cloud.google.com/go/bigtable"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
@@ -30,6 +31,20 @@ const SourceKind string = "bigtable"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -84,7 +84,7 @@ func TestFailParseFromYaml(t *testing.T) {
instance: my-instance
foo: bar
`,
err: "unable to parse as \"bigtable\": [1:1] unknown field \"foo\"\n> 1 | foo: bar\n ^\n 2 | instance: my-instance\n 3 | kind: bigtable\n 4 | project: my-project",
err: "unable to parse source \"my-bigtable-instance\" as \"bigtable\": [1:1] unknown field \"foo\"\n> 1 | foo: bar\n ^\n 2 | instance: my-instance\n 3 | kind: bigtable\n 4 | project: my-project",
},
{
desc: "missing required field",
@@ -94,7 +94,7 @@ func TestFailParseFromYaml(t *testing.T) {
kind: bigtable
project: my-project
`,
err: "unable to parse as \"bigtable\": Key: 'Config.Instance' Error:Field validation for 'Instance' failed on the 'required' tag",
err: "unable to parse source \"my-bigtable-instance\" as \"bigtable\": Key: 'Config.Instance' Error:Field validation for 'Instance' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -18,9 +18,11 @@ import (
"context"
"database/sql"
"fmt"
"net/url"
"slices"
"cloud.google.com/go/cloudsqlconn/sqlserver/mssql"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
@@ -31,6 +33,20 @@ const SourceKind string = "cloud-sql-mssql"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, IPType: "public"} // Default IPType
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
// Cloud SQL MSSQL configs
Name string `yaml:"name" validate:"required"`
@@ -96,7 +112,13 @@ func initCloudSQLMssqlConnection(ctx context.Context, tracer trace.Tracer, name,
defer span.End()
// Create dsn
dsn := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&cloudsql=%s:%s:%s", user, pass, ipAddress, dbname, project, region, instance)
query := fmt.Sprintf("database=%s&cloudsql=%s:%s:%s", dbname, project, region, instance)
url := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword(user, pass),
Host: ipAddress,
RawQuery: query,
}
// Get dial options
userAgent, err := util.UserAgentFromContext(ctx)
@@ -119,7 +141,7 @@ func initCloudSQLMssqlConnection(ctx context.Context, tracer trace.Tracer, name,
// Open database connection
db, err := sql.Open(
"cloudsql-sqlserver-driver",
dsn,
url.String(),
)
if err != nil {
return nil, err

View File

@@ -99,7 +99,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-mssql\": ipType invalid: must be one of \"public\", or \"private\"",
err: "unable to parse source \"my-instance\" as \"cloud-sql-mssql\": ipType invalid: must be one of \"public\", or \"private\"",
},
{
desc: "extra field",
@@ -116,7 +116,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"cloud-sql-mssql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | ipAddress: localhost\n 5 | kind: cloud-sql-mssql\n 6 | ",
err: "unable to parse source \"my-instance\" as \"cloud-sql-mssql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | ipAddress: localhost\n 5 | kind: cloud-sql-mssql\n 6 | ",
},
{
desc: "missing required field",
@@ -131,7 +131,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-mssql\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
err: "unable to parse source \"my-instance\" as \"cloud-sql-mssql\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -21,6 +21,7 @@ import (
"slices"
"cloud.google.com/go/cloudsqlconn/mysql/mysql"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
@@ -31,6 +32,20 @@ const SourceKind string = "cloud-sql-mysql"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, IPType: "public"} // Default IPType
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -152,7 +152,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-mysql\": ipType invalid: must be one of \"public\", or \"private\"",
err: "unable to parse source \"my-mysql-instance\" as \"cloud-sql-mysql\": ipType invalid: must be one of \"public\", or \"private\"",
},
{
desc: "extra field",
@@ -168,7 +168,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"cloud-sql-mysql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: cloud-sql-mysql\n 5 | password: my_pass\n 6 | ",
err: "unable to parse source \"my-mysql-instance\" as \"cloud-sql-mysql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: cloud-sql-mysql\n 5 | password: my_pass\n 6 | ",
},
{
desc: "missing required field",
@@ -182,7 +182,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-mysql\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
err: "unable to parse source \"my-mysql-instance\" as \"cloud-sql-mysql\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -20,6 +20,7 @@ import (
"net"
"cloud.google.com/go/cloudsqlconn"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/jackc/pgx/v5/pgxpool"
@@ -31,6 +32,20 @@ const SourceKind string = "cloud-sql-postgres"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, IPType: "public"} // Default IPType
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -152,7 +152,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-postgres\": ipType invalid: must be one of \"public\", or \"private\"",
err: "unable to parse source \"my-pg-instance\" as \"cloud-sql-postgres\": ipType invalid: must be one of \"public\", or \"private\"",
},
{
desc: "extra field",
@@ -168,7 +168,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"cloud-sql-postgres\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: cloud-sql-postgres\n 5 | password: my_pass\n 6 | ",
err: "unable to parse source \"my-pg-instance\" as \"cloud-sql-postgres\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: cloud-sql-postgres\n 5 | password: my_pass\n 6 | ",
},
{
desc: "missing required field",
@@ -182,7 +182,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"cloud-sql-postgres\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
err: "unable to parse source \"my-pg-instance\" as \"cloud-sql-postgres\": Key: 'Config.Project' Error:Field validation for 'Project' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -17,10 +17,12 @@ package couchbase
import (
"context"
"crypto/tls"
"fmt"
"os"
"github.com/couchbase/gocb/v2"
tlsutil "github.com/couchbase/tools-common/http/tls"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"go.opentelemetry.io/otel/trace"
)
@@ -30,6 +32,20 @@ const SourceKind string = "couchbase"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -125,7 +125,7 @@ func TestFailParseFromYaml(t *testing.T) {
scope: inventory
foo: bar
`,
err: "unable to parse as \"couchbase\": [3:1] unknown field \"foo\"\n 1 | bucket: travel-sample\n 2 | connectionString: localhost\n> 3 | foo: bar\n ^\n 4 | kind: couchbase\n 5 | password: password\n 6 | scope: inventory\n 7 | ",
err: "unable to parse source \"my-couchbase-instance\" as \"couchbase\": [3:1] unknown field \"foo\"\n 1 | bucket: travel-sample\n 2 | connectionString: localhost\n> 3 | foo: bar\n ^\n 4 | kind: couchbase\n 5 | password: password\n 6 | scope: inventory\n 7 | ",
},
{
desc: "missing required field",
@@ -138,7 +138,7 @@ func TestFailParseFromYaml(t *testing.T) {
bucket: travel-sample
scope: inventory
`,
err: "unable to parse as \"couchbase\": Key: 'Config.ConnectionString' Error:Field validation for 'ConnectionString' failed on the 'required' tag",
err: "unable to parse source \"my-couchbase-instance\" as \"couchbase\": Key: 'Config.ConnectionString' Error:Field validation for 'ConnectionString' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -24,6 +24,7 @@ import (
"net/url"
"strings"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"go.opentelemetry.io/otel/trace"
)
@@ -33,6 +34,20 @@ const SourceKind string = "dgraph"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
// HttpToken stores credentials for making HTTP request
type HttpToken struct {
UserId string

View File

@@ -106,7 +106,7 @@ func TestFailParseFromYaml(t *testing.T) {
dgraphUrl: https://localhost:8080
foo: bar
`,
err: "unable to parse as \"dgraph\": [2:1] unknown field \"foo\"\n 1 | dgraphUrl: https://localhost:8080\n> 2 | foo: bar\n ^\n 3 | kind: dgraph",
err: "unable to parse source \"my-dgraph-instance\" as \"dgraph\": [2:1] unknown field \"foo\"\n 1 | dgraphUrl: https://localhost:8080\n> 2 | foo: bar\n ^\n 3 | kind: dgraph",
},
{
desc: "missing required field",
@@ -115,7 +115,7 @@ func TestFailParseFromYaml(t *testing.T) {
my-dgraph-instance:
kind: dgraph
`,
err: "unable to parse as \"dgraph\": Key: 'Config.DgraphUrl' Error:Field validation for 'DgraphUrl' failed on the 'required' tag",
err: "unable to parse source \"my-dgraph-instance\" as \"dgraph\": Key: 'Config.DgraphUrl' Error:Field validation for 'DgraphUrl' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -15,12 +15,15 @@ package http
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/url"
"time"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
)
@@ -29,32 +32,59 @@ const SourceKind string = "http"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, Timeout: "30s"} // Default timeout
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
BaseURL string `yaml:"baseUrl"`
Timeout string `yaml:"timeout"`
DefaultHeaders map[string]string `yaml:"headers"`
QueryParams map[string]string `yaml:"queryParams"`
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
BaseURL string `yaml:"baseUrl"`
Timeout string `yaml:"timeout"`
DefaultHeaders map[string]string `yaml:"headers"`
QueryParams map[string]string `yaml:"queryParams"`
DisableSslVerification bool `yaml:"disableSslVerification"`
}
func (r Config) SourceConfigKind() string {
return SourceKind
}
// DefaultConfig is a helper function that generates the default configuration for an HTTP Tool Config.
func DefaultConfig(name string) Config {
return Config{Name: name, Timeout: "30s"}
}
// Initialize initializes an HTTP Source instance.
func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
duration, err := time.ParseDuration(r.Timeout)
if err != nil {
return nil, fmt.Errorf("unable to parse Timeout string as time.Duration: %s", err)
}
tr := &http.Transport{}
logger, err := util.LoggerFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("unable to get logger from ctx: %s", err)
}
if r.DisableSslVerification {
tr.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
logger.WarnContext(ctx, "Insecure HTTP is enabled for HTTP source %s. TLS certificate verification is skipped.\n", r.Name)
}
client := http.Client{
Timeout: duration,
Timeout: duration,
Transport: tr,
}
// Validate BaseURL

View File

@@ -15,7 +15,6 @@
package http_test
import (
"strings"
"testing"
yaml "github.com/goccy/go-yaml"
@@ -35,6 +34,24 @@ func TestParseFromYamlHttp(t *testing.T) {
{
desc: "basic example",
in: `
sources:
my-http-instance:
kind: http
baseUrl: http://test_server/
`,
want: map[string]sources.SourceConfig{
"my-http-instance": http.Config{
Name: "my-http-instance",
Kind: http.SourceKind,
BaseURL: "http://test_server/",
Timeout: "30s",
DisableSslVerification: false,
},
},
},
{
desc: "advanced example",
in: `
sources:
my-http-instance:
kind: http
@@ -46,15 +63,17 @@ func TestParseFromYamlHttp(t *testing.T) {
queryParams:
api-key: test_api_key
param: param-value
disableSslVerification: true
`,
want: map[string]sources.SourceConfig{
"my-http-instance": http.Config{
Name: "my-http-instance",
Kind: http.SourceKind,
BaseURL: "http://test_server/",
Timeout: "10s",
DefaultHeaders: map[string]string{"Authorization": "test_header", "Custom-Header": "custom"},
QueryParams: map[string]string{"api-key": "test_api_key", "param": "param-value"},
Name: "my-http-instance",
Kind: http.SourceKind,
BaseURL: "http://test_server/",
Timeout: "10s",
DefaultHeaders: map[string]string{"Authorization": "test_header", "Custom-Header": "custom"},
QueryParams: map[string]string{"api-key": "test_api_key", "param": "param-value"},
DisableSslVerification: true,
},
},
},
@@ -96,7 +115,7 @@ func TestFailParseFromYaml(t *testing.T) {
api-key: test_api_key
project: test-project
`,
err: "unable to parse as \"http\"",
err: "unable to parse source \"my-http-instance\" as \"http\": [5:1] unknown field \"project\"\n 2 | headers:\n 3 | Authorization: test_header\n 4 | kind: http\n> 5 | project: test-project\n ^\n 6 | queryParams:\n 7 | api-key: test_api_key\n 8 | timeout: 10s",
},
{
desc: "missing required field",
@@ -105,7 +124,7 @@ func TestFailParseFromYaml(t *testing.T) {
my-http-instance:
baseUrl: http://test_server/
`,
err: "missing 'kind' field for \"my-http-instance\"",
err: "missing 'kind' field for source \"my-http-instance\"",
},
}
for _, tc := range tcs {
@@ -119,9 +138,8 @@ func TestFailParseFromYaml(t *testing.T) {
t.Fatalf("expect parsing to fail")
}
errStr := err.Error()
if !strings.Contains(errStr, tc.err) {
t.Fatalf("unexpected error string: got %q, want substring %q", errStr, tc.err)
if errStr != tc.err {
t.Fatalf("unexpected error: got %q, want %q", errStr, tc.err)
}
})
}

View File

@@ -18,7 +18,9 @@ import (
"context"
"database/sql"
"fmt"
"net/url"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
_ "github.com/microsoft/go-mssqldb"
"go.opentelemetry.io/otel/trace"
@@ -29,6 +31,20 @@ const SourceKind string = "mssql"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
// Cloud SQL MSSQL configs
Name string `yaml:"name" validate:"required"`
@@ -91,10 +107,17 @@ func initMssqlConnection(ctx context.Context, tracer trace.Tracer, name, host, p
defer span.End()
// Create dsn
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s", user, pass, host, port, dbname)
query := url.Values{}
query.Add("database", dbname)
url := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword(user, pass),
Host: fmt.Sprintf("%s:%s", host, port),
RawQuery: query.Encode(),
}
// Open database connection
db, err := sql.Open("sqlserver", dsn)
db, err := sql.Open("sqlserver", url.String())
if err != nil {
return nil, fmt.Errorf("sql.Open: %w", err)
}

View File

@@ -70,7 +70,6 @@ func TestParseFromYamlMssql(t *testing.T) {
}
})
}
}
func TestFailParseFromYaml(t *testing.T) {
@@ -92,7 +91,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"mssql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: 0.0.0.0\n 4 | kind: mssql\n 5 | password: my_pass\n 6 | ",
err: "unable to parse source \"my-mssql-instance\" as \"mssql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: 0.0.0.0\n 4 | kind: mssql\n 5 | password: my_pass\n 6 | ",
},
{
desc: "missing required field",
@@ -105,7 +104,7 @@ func TestFailParseFromYaml(t *testing.T) {
database: my_db
user: my_user
`,
err: "unable to parse as \"mssql\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
err: "unable to parse source \"my-mssql-instance\" as \"mssql\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -20,6 +20,7 @@ import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"go.opentelemetry.io/otel/trace"
)
@@ -29,6 +30,20 @@ const SourceKind string = "mysql"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -92,7 +92,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"mysql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: 0.0.0.0\n 4 | kind: mysql\n 5 | password: my_pass\n 6 | ",
err: "unable to parse source \"my-mysql-instance\" as \"mysql\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: 0.0.0.0\n 4 | kind: mysql\n 5 | password: my_pass\n 6 | ",
},
{
desc: "missing required field",
@@ -105,7 +105,7 @@ func TestFailParseFromYaml(t *testing.T) {
user: my_user
password: my_pass
`,
err: "unable to parse as \"mysql\": Key: 'Config.Host' Error:Field validation for 'Host' failed on the 'required' tag",
err: "unable to parse source \"my-mysql-instance\" as \"mysql\": Key: 'Config.Host' Error:Field validation for 'Host' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -18,6 +18,7 @@ import (
"context"
"fmt"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
"go.opentelemetry.io/otel/trace"
@@ -28,6 +29,20 @@ const SourceKind string = "neo4j"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, Database: "neo4j"} // Default database
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -89,7 +89,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"neo4j\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | kind: neo4j\n 4 | password: my_pass\n 5 | uri: neo4j+s://my-host:7687\n 6 | ",
err: "unable to parse source \"my-neo4j-instance\" as \"neo4j\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | kind: neo4j\n 4 | password: my_pass\n 5 | uri: neo4j+s://my-host:7687\n 6 | ",
},
{
desc: "missing required field",
@@ -101,7 +101,7 @@ func TestFailParseFromYaml(t *testing.T) {
database: my_db
user: my_user
`,
err: "unable to parse as \"neo4j\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
err: "unable to parse source \"my-neo4j-instance\" as \"neo4j\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -17,7 +17,9 @@ package postgres
import (
"context"
"fmt"
"net/url"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/jackc/pgx/v5/pgxpool"
"go.opentelemetry.io/otel/trace"
@@ -28,6 +30,20 @@ const SourceKind string = "postgres"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
@@ -81,9 +97,15 @@ func initPostgresConnectionPool(ctx context.Context, tracer trace.Tracer, name,
//nolint:all // Reassigned ctx
ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceKind, name)
defer span.End()
// urlExample := "postgres:dd//username:password@localhost:5432/database_name"
i := fmt.Sprintf("postgres://%s:%s@%s:%s/%s", user, pass, host, port, dbname)
pool, err := pgxpool.New(ctx, i)
url := &url.URL{
Scheme: "postgres",
User: url.UserPassword(user, pass),
Host: fmt.Sprintf("%s:%s", host, port),
Path: dbname,
}
pool, err := pgxpool.New(ctx, url.String())
if err != nil {
return nil, fmt.Errorf("unable to create connection pool: %w", err)
}

View File

@@ -92,7 +92,7 @@ func TestFailParseFromYaml(t *testing.T) {
password: my_pass
foo: bar
`,
err: "unable to parse as \"postgres\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: my-host\n 4 | kind: postgres\n 5 | password: my_pass\n 6 | ",
err: "unable to parse source \"my-pg-instance\" as \"postgres\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | host: my-host\n 4 | kind: postgres\n 5 | password: my_pass\n 6 | ",
},
{
desc: "missing required field",
@@ -105,7 +105,7 @@ func TestFailParseFromYaml(t *testing.T) {
database: my_db
user: my_user
`,
err: "unable to parse as \"postgres\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
err: "unable to parse source \"my-pg-instance\" as \"postgres\": Key: 'Config.Password' Error:Field validation for 'Password' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -0,0 +1,152 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package redis
import (
"context"
"fmt"
"time"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/redis/go-redis/v9"
"go.opentelemetry.io/otel/trace"
)
const SourceKind string = "redis"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Address []string `yaml:"address" validate:"required"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Database int `yaml:"database"`
UseGCPIAM bool `yaml:"useGCPIAM"`
ClusterEnabled bool `yaml:"clusterEnabled"`
}
func (r Config) SourceConfigKind() string {
return SourceKind
}
// RedisClient is an interface for `redis.Client` and `redis.ClusterClient
type RedisClient interface {
Do(context.Context, ...any) *redis.Cmd
}
var _ RedisClient = (*redis.Client)(nil)
var _ RedisClient = (*redis.ClusterClient)(nil)
func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
client, err := initRedisClient(ctx, r)
if err != nil {
return nil, fmt.Errorf("error initializing Redis client: %s", err)
}
s := &Source{
Name: r.Name,
Kind: SourceKind,
Client: client,
}
return s, nil
}
func initRedisClient(ctx context.Context, r Config) (RedisClient, error) {
var authFn func(ctx context.Context) (username string, password string, err error)
if r.UseGCPIAM {
// Pass in an access token getter fn for IAM auth
authFn = func(ctx context.Context) (username string, password string, err error) {
token, err := sources.GetIAMAccessToken(ctx)
if err != nil {
return "", "", err
}
return "default", token, nil
}
}
var client RedisClient
var err error
if r.ClusterEnabled {
// Create a new Redis Cluster client
clusterClient := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: r.Address,
// PoolSize applies per cluster node and not for the whole cluster.
PoolSize: 10,
ConnMaxIdleTime: 60 * time.Second,
MinIdleConns: 1,
CredentialsProviderContext: authFn,
Username: r.Username,
Password: r.Password,
})
err = clusterClient.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error {
return shard.Ping(ctx).Err()
})
if err != nil {
return nil, fmt.Errorf("unable to connect to redis cluster: %s", err)
}
client = clusterClient
return client, nil
}
// Create a new Redis client
standaloneClient := redis.NewClient(&redis.Options{
Addr: r.Address[0],
PoolSize: 10,
ConnMaxIdleTime: 60 * time.Second,
MinIdleConns: 1,
DB: r.Database,
CredentialsProviderContext: authFn,
Username: r.Username,
Password: r.Password,
})
_, err = standaloneClient.Ping(ctx).Result()
if err != nil {
return nil, fmt.Errorf("unable to connect to redis: %s", err)
}
client = standaloneClient
return client, nil
}
var _ sources.Source = &Source{}
type Source struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client RedisClient
}
func (s *Source) SourceKind() string {
return SourceKind
}
func (s *Source) RedisClient() RedisClient {
return s.Client
}

View File

@@ -0,0 +1,157 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package redis_test
import (
"strings"
"testing"
yaml "github.com/goccy/go-yaml"
"github.com/google/go-cmp/cmp"
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/sources/redis"
"github.com/googleapis/genai-toolbox/internal/testutils"
)
func TestParseFromYamlRedis(t *testing.T) {
tcs := []struct {
desc string
in string
want server.SourceConfigs
}{
{
desc: "default setting",
in: `
sources:
my-redis-instance:
kind: redis
address:
- 127.0.0.1
`,
want: server.SourceConfigs{
"my-redis-instance": redis.Config{
Name: "my-redis-instance",
Kind: redis.SourceKind,
Address: []string{"127.0.0.1"},
ClusterEnabled: false,
UseGCPIAM: false,
},
},
},
{
desc: "advanced example",
in: `
sources:
my-redis-instance:
kind: redis
address:
- 127.0.0.1
password: my-pass
database: 1
useGCPIAM: true
clusterEnabled: true
`,
want: server.SourceConfigs{
"my-redis-instance": redis.Config{
Name: "my-redis-instance",
Kind: redis.SourceKind,
Address: []string{"127.0.0.1"},
Password: "my-pass",
Database: 1,
ClusterEnabled: true,
UseGCPIAM: true,
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
// Parse contents
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if !cmp.Equal(tc.want, got.Sources) {
t.Fatalf("incorrect parse: want %v, got %v", tc.want, got.Sources)
}
})
}
}
func TestFailParseFromYaml(t *testing.T) {
tcs := []struct {
desc string
in string
err string
}{
{
desc: "invalid database",
in: `
sources:
my-redis-instance:
kind: redis
project: my-project
address:
- 127.0.0.1
password: my-pass
database: data
`,
err: "cannot unmarshal string into Go struct field .Sources of type int",
},
{
desc: "extra field",
in: `
sources:
my-redis-instance:
kind: redis
project: my-project
address:
- 127.0.0.1
password: my-pass
database: 1
`,
err: "unable to parse source \"my-redis-instance\" as \"redis\": [6:1] unknown field \"project\"",
},
{
desc: "missing required field",
in: `
sources:
my-redis-instance:
kind: redis
`,
err: "unable to parse source \"my-redis-instance\" as \"redis\": Key: 'Config.Address' Error:Field validation for 'Address' failed on the 'required' tag",
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
// Parse contents
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err == nil {
t.Fatalf("expect parsing to fail")
}
errStr := err.Error()
if !strings.Contains(errStr, tc.err) {
t.Fatalf("unexpected error: got %q, want %q", errStr, tc.err)
}
})
}
}

View File

@@ -17,10 +17,42 @@ package sources
import (
"context"
"fmt"
"github.com/goccy/go-yaml"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
// SourceConfigFactory defines the function signature for creating a SourceConfig.
type SourceConfigFactory func(ctx context.Context, name string, decoder *yaml.Decoder) (SourceConfig, error)
var sourceRegistry = make(map[string]SourceConfigFactory)
// Register registers a new source kind with its factory.
// It returns false if the kind is already registered.
func Register(kind string, factory SourceConfigFactory) bool {
if _, exists := sourceRegistry[kind]; exists {
// Source with this kind already exists, do not overwrite.
return false
}
sourceRegistry[kind] = factory
return true
}
// DecodeConfig decodes a source configuration using the registered factory for the given kind.
func DecodeConfig(ctx context.Context, kind string, name string, decoder *yaml.Decoder) (SourceConfig, error) {
factory, found := sourceRegistry[kind]
if !found {
return nil, fmt.Errorf("unknown source kind: %q", kind)
}
sourceConfig, err := factory(ctx, name, decoder)
if err != nil {
return nil, fmt.Errorf("unable to parse source %q as %q: %w", name, kind, err)
}
return sourceConfig, err
}
// SourceConfig is the interface for configuring a source.
type SourceConfig interface {
SourceConfigKind() string

View File

@@ -19,6 +19,7 @@ import (
"fmt"
"cloud.google.com/go/spanner"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util"
"go.opentelemetry.io/otel/trace"
@@ -29,6 +30,20 @@ const SourceKind string = "spanner"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, Dialect: "googlesql"} // Default dialect
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -132,7 +132,7 @@ func TestFailParseFromYaml(t *testing.T) {
dialect: fail
database: my_db
`,
err: "unable to parse as \"spanner\": dialect invalid: must be one of \"googlesql\", or \"postgresql\"",
err: "unable to parse source \"my-spanner-instance\" as \"spanner\": dialect invalid: must be one of \"googlesql\", or \"postgresql\"",
},
{
desc: "extra field",
@@ -145,7 +145,7 @@ func TestFailParseFromYaml(t *testing.T) {
database: my_db
foo: bar
`,
err: "unable to parse as \"spanner\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: spanner\n 5 | project: my-project",
err: "unable to parse source \"my-spanner-instance\" as \"spanner\": [2:1] unknown field \"foo\"\n 1 | database: my_db\n> 2 | foo: bar\n ^\n 3 | instance: my-instance\n 4 | kind: spanner\n 5 | project: my-project",
},
{
desc: "missing required field",
@@ -156,7 +156,7 @@ func TestFailParseFromYaml(t *testing.T) {
project: my-project
instance: my-instance
`,
err: "unable to parse as \"spanner\": Key: 'Config.Database' Error:Field validation for 'Database' failed on the 'required' tag",
err: "unable to parse source \"my-spanner-instance\" as \"spanner\": Key: 'Config.Database' Error:Field validation for 'Database' failed on the 'required' tag",
},
}
for _, tc := range tcs {

View File

@@ -19,6 +19,7 @@ import (
"database/sql"
"fmt"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"go.opentelemetry.io/otel/trace"
_ "modernc.org/sqlite" // Pure Go SQLite driver
@@ -29,6 +30,20 @@ const SourceKind string = "sqlite"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`

View File

@@ -85,3 +85,20 @@ func GetIAMPrincipalEmailFromADC(ctx context.Context) (string, error) {
email := strings.TrimSuffix(emailValue.(string), ".gserviceaccount.com")
return email, nil
}
func GetIAMAccessToken(ctx context.Context) (string, error) {
creds, err := google.FindDefaultCredentials(ctx, "https://www.googleapis.com/auth/cloud-platform")
if err != nil {
return "", fmt.Errorf("failed to find default credentials (run 'gcloud auth application-default login'?): %w", err)
}
token, err := creds.TokenSource.Token() // This gets an oauth2.Token
if err != nil {
return "", fmt.Errorf("failed to get token from token source: %w", err)
}
if !token.Valid() {
return "", fmt.Errorf("retrieved token is invalid or expired")
}
return token.AccessToken, nil
}

View File

@@ -0,0 +1,125 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package valkey
import (
"context"
"fmt"
"log"
"github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/valkey-io/valkey-go"
"go.opentelemetry.io/otel/trace"
)
const SourceKind string = "valkey"
// validate interface
var _ sources.SourceConfig = Config{}
func init() {
if !sources.Register(SourceKind, newConfig) {
panic(fmt.Sprintf("source kind %q already registered", SourceKind))
}
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name}
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
return actual, nil
}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Address []string `yaml:"address" validate:"required"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Database int `yaml:"database"`
UseGCPIAM bool `yaml:"useGCPIAM"`
DisableCache bool `yaml:"disableCache"`
}
func (r Config) SourceConfigKind() string {
return SourceKind
}
func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {
client, err := initValkeyClient(ctx, r)
if err != nil {
return nil, fmt.Errorf("error initializing Valkey client: %s", err)
}
s := &Source{
Name: r.Name,
Kind: SourceKind,
Client: client,
}
return s, nil
}
func initValkeyClient(ctx context.Context, r Config) (valkey.Client, error) {
var authFn func(valkey.AuthCredentialsContext) (valkey.AuthCredentials, error)
if r.UseGCPIAM {
// Pass in an access token getter fn for IAM auth
authFn = func(valkey.AuthCredentialsContext) (valkey.AuthCredentials, error) {
token, err := sources.GetIAMAccessToken(ctx)
creds := valkey.AuthCredentials{Username: "default", Password: token}
if err != nil {
return creds, err
}
return creds, nil
}
}
client, err := valkey.NewClient(valkey.ClientOption{
InitAddress: r.Address,
SelectDB: r.Database,
Username: r.Username,
Password: r.Password,
AuthCredentialsFn: authFn,
DisableCache: r.DisableCache,
})
if err != nil {
log.Fatalf("error creating Valkey client: %v", err)
}
// Ping the server to check connectivity
pingCmd := client.B().Ping().Build()
_, err = client.Do(ctx, pingCmd).ToString()
if err != nil {
log.Fatalf("Failed to execute PING command: %v", err)
}
return client, nil
}
var _ sources.Source = &Source{}
type Source struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client valkey.Client
}
func (s *Source) SourceKind() string {
return SourceKind
}
func (s *Source) ValkeyClient() valkey.Client {
return s.Client
}

View File

@@ -0,0 +1,162 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package valkey_test
import (
"strings"
"testing"
yaml "github.com/goccy/go-yaml"
"github.com/google/go-cmp/cmp"
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/sources/valkey"
"github.com/googleapis/genai-toolbox/internal/testutils"
)
func TestParseFromYamlValkey(t *testing.T) {
tcs := []struct {
desc string
in string
want server.SourceConfigs
}{
{
desc: "default setting",
in: `
sources:
my-valkey-instance:
kind: valkey
address:
- 127.0.0.1
`,
want: map[string]sources.SourceConfig{
"my-valkey-instance": valkey.Config{
Name: "my-valkey-instance",
Kind: valkey.SourceKind,
Address: []string{"127.0.0.1"},
Username: "",
Password: "",
Database: 0,
UseGCPIAM: false,
DisableCache: false,
},
},
},
{
desc: "advanced example",
in: `
sources:
my-valkey-instance:
kind: valkey
address:
- 127.0.0.1
database: 1
username: user
password: pass
useGCPIAM: true
disableCache: true
`,
want: map[string]sources.SourceConfig{
"my-valkey-instance": valkey.Config{
Name: "my-valkey-instance",
Kind: valkey.SourceKind,
Address: []string{"127.0.0.1"},
Username: "user",
Password: "pass",
Database: 1,
UseGCPIAM: true,
DisableCache: true,
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
// Parse contents
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if !cmp.Equal(tc.want, got.Sources) {
t.Fatalf("incorrect parse: want %v, got %v", tc.want, got.Sources)
}
})
}
}
func TestFailParseFromYaml(t *testing.T) {
tcs := []struct {
desc string
in string
err string
}{
{
desc: "invalid database",
in: `
sources:
my-valkey-instance:
kind: valkey
project: my-project
address:
- 127.0.0.1
database: my-db
useGCPIAM: false
`,
err: "cannot unmarshal string into Go struct field .Sources of type int",
},
{
desc: "extra field",
in: `
sources:
my-valkey-instance:
kind: valkey
address:
- 127.0.0.1
project: proj
database: 1
`,
err: "unable to parse source \"my-valkey-instance\" as \"valkey\": [5:1] unknown field \"project\"",
},
{
desc: "missing required field",
in: `
sources:
my-valkey-instance:
kind: valkey
`,
err: "unable to parse source \"my-valkey-instance\" as \"valkey\": Key: 'Config.Address' Error:Field validation for 'Address' failed on the 'required' tag",
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Sources server.SourceConfigs `yaml:"sources"`
}{}
// Parse contents
err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got)
if err == nil {
t.Fatalf("expect parsing to fail")
}
errStr := err.Error()
if !strings.Contains(errStr, tc.err) {
t.Fatalf("unexpected error: got %q, want %q", errStr, tc.err)
}
})
}
}

View File

@@ -53,13 +53,14 @@ var _ compatibleSource = &bigqueryds.Source{}
var compatibleSources = [...]string{bigqueryds.SourceKind}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
}
// validate interface
@@ -82,22 +83,26 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
}
allParameters, paramManifest, paramMcpManifest := tools.ProcessParameters(cfg.TemplateParameters, cfg.Parameters)
mcpManifest := tools.McpManifest{
Name: cfg.Name,
Description: cfg.Description,
InputSchema: cfg.Parameters.McpManifest(),
InputSchema: paramMcpManifest,
}
// finish tool setup
t := Tool{
Name: cfg.Name,
Kind: kind,
Parameters: cfg.Parameters,
Statement: cfg.Statement,
AuthRequired: cfg.AuthRequired,
Client: s.BigQueryClient(),
manifest: tools.Manifest{Description: cfg.Description, Parameters: cfg.Parameters.Manifest(), AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
Name: cfg.Name,
Kind: kind,
Parameters: cfg.Parameters,
TemplateParameters: cfg.TemplateParameters,
AllParams: allParameters,
Statement: cfg.Statement,
AuthRequired: cfg.AuthRequired,
Client: s.BigQueryClient(),
manifest: tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
}
return t, nil
}
@@ -106,10 +111,12 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
Name string `yaml:"name"`
Kind string `yaml:"kind"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
AllParams tools.Parameters `yaml:"allParams"`
Client *bigqueryapi.Client
Statement string
@@ -118,11 +125,22 @@ type Tool struct {
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
namedArgs := make([]bigqueryapi.QueryParameter, 0, len(params))
paramsMap := params.AsReversedMap()
for _, v := range params.AsSlice() {
paramName := paramsMap[v]
if strings.Contains(t.Statement, "@"+paramName) {
paramsMap := params.AsMap()
newStatement, err := tools.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract template params %w", err)
}
newParams, err := tools.GetParams(t.Parameters, paramsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract standard params %w", err)
}
namedArgs := make([]bigqueryapi.QueryParameter, 0, len(newParams))
newParamsMap := newParams.AsReversedMap()
for _, v := range newParams.AsSlice() {
paramName := newParamsMap[v]
if strings.Contains(newStatement, "@"+paramName) {
namedArgs = append(namedArgs, bigqueryapi.QueryParameter{
Name: paramName,
Value: v,
@@ -134,7 +152,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
}
}
query := t.Client.Query(t.Statement)
query := t.Client.Query(newStatement)
query.Parameters = namedArgs
query.Location = t.Client.Location
@@ -164,7 +182,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
}
func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
return tools.ParseParams(t.Parameters, data, claims)
return tools.ParseParams(t.AllParams, data, claims)
}
func (t Tool) Manifest() tools.Manifest {

View File

@@ -82,3 +82,76 @@ func TestParseFromYamlBigQuery(t *testing.T) {
}
}
func TestParseFromYamlWithTemplateBigQuery(t *testing.T) {
ctx, err := testutils.ContextWithNewLogger()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
tcs := []struct {
desc string
in string
want server.ToolConfigs
}{
{
desc: "basic example",
in: `
tools:
example_tool:
kind: bigquery-sql
source: my-instance
description: some description
statement: |
SELECT * FROM SQL_STATEMENT;
parameters:
- name: country
type: string
description: some description
templateParameters:
- name: tableName
type: string
description: The table to select hotels from.
- name: fieldArray
type: array
description: The columns to return for the query.
items:
name: column
type: string
description: A column name that will be returned from the query.
`,
want: server.ToolConfigs{
"example_tool": bigquery.Config{
Name: "example_tool",
Kind: "bigquery-sql",
Source: "my-instance",
Description: "some description",
Statement: "SELECT * FROM SQL_STATEMENT;\n",
AuthRequired: []string{},
Parameters: []tools.Parameter{
tools.NewStringParameter("country", "some description"),
},
TemplateParameters: []tools.Parameter{
tools.NewStringParameter("tableName", "The table to select hotels from."),
tools.NewArrayParameter("fieldArray", "The columns to return for the query.", tools.NewStringParameter("column", "A column name that will be returned from the query.")),
},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Tools server.ToolConfigs `yaml:"tools"`
}{}
// Parse contents
err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if diff := cmp.Diff(tc.want, got.Tools); diff != "" {
t.Fatalf("incorrect parse: diff %v", diff)
}
})
}
}

View File

@@ -51,13 +51,14 @@ var _ compatibleSource = &bigtabledb.Source{}
var compatibleSources = [...]string{bigtabledb.SourceKind}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
}
// validate interface
@@ -80,22 +81,26 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
}
allParameters, paramManifest, paramMcpManifest := tools.ProcessParameters(cfg.TemplateParameters, cfg.Parameters)
mcpManifest := tools.McpManifest{
Name: cfg.Name,
Description: cfg.Description,
InputSchema: cfg.Parameters.McpManifest(),
InputSchema: paramMcpManifest,
}
// finish tool setup
t := Tool{
Name: cfg.Name,
Kind: kind,
Parameters: cfg.Parameters,
Statement: cfg.Statement,
AuthRequired: cfg.AuthRequired,
Client: s.BigtableClient(),
manifest: tools.Manifest{Description: cfg.Description, Parameters: cfg.Parameters.Manifest(), AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
Name: cfg.Name,
Kind: kind,
Parameters: cfg.Parameters,
TemplateParameters: cfg.TemplateParameters,
AllParams: allParameters,
Statement: cfg.Statement,
AuthRequired: cfg.AuthRequired,
Client: s.BigtableClient(),
manifest: tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
}
return t, nil
}
@@ -104,10 +109,12 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
Name string `yaml:"name"`
Kind string `yaml:"kind"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
AllParams tools.Parameters `yaml:"allParams"`
Client *bigtable.Client
Statement string
@@ -141,21 +148,32 @@ func getMapParamsType(tparams tools.Parameters, params tools.ParamValues) (map[s
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
mapParamsType, err := getMapParamsType(t.Parameters, params)
paramsMap := params.AsMap()
newStatement, err := tools.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract template params %w", err)
}
newParams, err := tools.GetParams(t.Parameters, paramsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract standard params %w", err)
}
mapParamsType, err := getMapParamsType(t.Parameters, newParams)
if err != nil {
return nil, fmt.Errorf("fail to get map params: %w", err)
}
ps, err := t.Client.PrepareStatement(
ctx,
t.Statement,
newStatement,
mapParamsType,
)
if err != nil {
return nil, fmt.Errorf("unable to prepare statement: %w", err)
}
bs, err := ps.Bind(params.AsMap())
bs, err := ps.Bind(newParams.AsMap())
if err != nil {
return nil, fmt.Errorf("unable to bind: %w", err)
}
@@ -183,7 +201,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
}
func (t Tool) ParseParams(data map[string]any, claims map[string]map[string]any) (tools.ParamValues, error) {
return tools.ParseParams(t.Parameters, data, claims)
return tools.ParseParams(t.AllParams, data, claims)
}
func (t Tool) Manifest() tools.Manifest {

View File

@@ -82,3 +82,76 @@ func TestParseFromYamlBigtable(t *testing.T) {
}
}
func TestParseFromYamlWithTemplateBigtable(t *testing.T) {
ctx, err := testutils.ContextWithNewLogger()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
tcs := []struct {
desc string
in string
want server.ToolConfigs
}{
{
desc: "basic example",
in: `
tools:
example_tool:
kind: bigtable-sql
source: my-pg-instance
description: some description
statement: |
SELECT * FROM SQL_STATEMENT;
parameters:
- name: country
type: string
description: some description
templateParameters:
- name: tableName
type: string
description: The table to select hotels from.
- name: fieldArray
type: array
description: The columns to return for the query.
items:
name: column
type: string
description: A column name that will be returned from the query.
`,
want: server.ToolConfigs{
"example_tool": bigtable.Config{
Name: "example_tool",
Kind: "bigtable-sql",
Source: "my-pg-instance",
Description: "some description",
Statement: "SELECT * FROM SQL_STATEMENT;\n",
AuthRequired: []string{},
Parameters: []tools.Parameter{
tools.NewStringParameter("country", "some description"),
},
TemplateParameters: []tools.Parameter{
tools.NewStringParameter("tableName", "The table to select hotels from."),
tools.NewArrayParameter("fieldArray", "The columns to return for the query.", tools.NewStringParameter("column", "A column name that will be returned from the query.")),
},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Tools server.ToolConfigs `yaml:"tools"`
}{}
// Parse contents
err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if diff := cmp.Diff(tc.want, got.Tools); diff != "" {
t.Fatalf("incorrect parse: diff %v", diff)
}
})
}
}

View File

@@ -53,13 +53,14 @@ var _ compatibleSource = &couchbase.Source{}
var compatibleSources = [...]string{couchbase.SourceKind}
type Config struct {
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
Source string `yaml:"source" validate:"required"`
Description string `yaml:"description" validate:"required"`
Statement string `yaml:"statement" validate:"required"`
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
}
// validate interface
@@ -82,21 +83,25 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
return nil, fmt.Errorf("invalid source for %q tool: source kind must be one of %q", kind, compatibleSources)
}
allParameters, paramManifest, paramMcpManifest := tools.ProcessParameters(cfg.TemplateParameters, cfg.Parameters)
mcpManifest := tools.McpManifest{
Name: cfg.Name,
Description: cfg.Description,
InputSchema: cfg.Parameters.McpManifest(),
InputSchema: paramMcpManifest,
}
// finish tool setup
t := Tool{
Name: cfg.Name,
Kind: kind,
Parameters: cfg.Parameters,
TemplateParameters: cfg.TemplateParameters,
AllParams: allParameters,
Statement: cfg.Statement,
Scope: s.CouchbaseScope(),
QueryScanConsistency: s.CouchbaseQueryScanConsistency(),
AuthRequired: cfg.AuthRequired,
manifest: tools.Manifest{Description: cfg.Description, Parameters: cfg.Parameters.Manifest(), AuthRequired: cfg.AuthRequired},
manifest: tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
}
return t, nil
@@ -106,10 +111,12 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Parameters tools.Parameters `yaml:"parameters"`
AuthRequired []string `yaml:"authRequired"`
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Parameters tools.Parameters `yaml:"parameters"`
TemplateParameters tools.Parameters `yaml:"templateParameters"`
AllParams tools.Parameters `yaml:"allParams"`
AuthRequired []string `yaml:"authRequired"`
Scope *gocb.Scope
QueryScanConsistency uint
@@ -119,10 +126,19 @@ type Tool struct {
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
namedParams := params.AsMap()
results, err := t.Scope.Query(t.Statement, &gocb.QueryOptions{
namedParamsMap := params.AsMap()
newStatement, err := tools.ResolveTemplateParams(t.TemplateParameters, t.Statement, namedParamsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract template params %w", err)
}
newParams, err := tools.GetParams(t.Parameters, namedParamsMap)
if err != nil {
return nil, fmt.Errorf("unable to extract standard params %w", err)
}
results, err := t.Scope.Query(newStatement, &gocb.QueryOptions{
ScanConsistency: gocb.QueryScanConsistency(t.QueryScanConsistency),
NamedParameters: namedParams,
NamedParameters: newParams.AsMap(),
})
if err != nil {
return nil, fmt.Errorf("unable to execute query: %w", err)
@@ -141,7 +157,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
}
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (tools.ParamValues, error) {
return tools.ParseParams(t.Parameters, data, claimsMap)
return tools.ParseParams(t.AllParams, data, claimsMap)
}
func (t Tool) Manifest() tools.Manifest {

View File

@@ -85,3 +85,67 @@ func TestParseFromYamlCouchbase(t *testing.T) {
})
}
}
func TestParseFromYamlWithTemplateMssql(t *testing.T) {
ctx, err := testutils.ContextWithNewLogger()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
tcs := []struct {
desc string
in string
want server.ToolConfigs
}{
{
desc: "basic example",
in: `
tools:
example_tool:
kind: couchbase-sql
source: my-couchbase-instance
description: some tool description
statement: |
select * from {{.tableName}} WHERE name = $hotel;
parameters:
- name: hotel
type: string
description: hotel parameter description
templateParameters:
- name: tableName
type: string
description: The table to select hotels from.
`,
want: server.ToolConfigs{
"example_tool": couchbase.Config{
Name: "example_tool",
Kind: "couchbase-sql",
AuthRequired: []string{},
Source: "my-couchbase-instance",
Description: "some tool description",
Statement: "select * from {{.tableName}} WHERE name = $hotel;\n",
Parameters: []tools.Parameter{
tools.NewStringParameter("hotel", "hotel parameter description"),
},
TemplateParameters: []tools.Parameter{
tools.NewStringParameter("tableName", "The table to select hotels from."),
},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got := struct {
Tools server.ToolConfigs `yaml:"tools"`
}{}
// Parse contents
err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got)
if err != nil {
t.Fatalf("unable to unmarshal: %s", err)
}
if diff := cmp.Diff(tc.want, got.Tools); diff != "" {
t.Fatalf("incorrect parse: diff %v", diff)
}
})
}
}

View File

@@ -59,6 +59,7 @@ type Config struct {
Method tools.HTTPMethod `yaml:"method" validate:"required"`
Headers map[string]string `yaml:"headers"`
RequestBody string `yaml:"requestBody"`
PathParams tools.Parameters `yaml:"pathParams"`
QueryParams tools.Parameters `yaml:"queryParams"`
BodyParams tools.Parameters `yaml:"bodyParams"`
HeaderParams tools.Parameters `yaml:"headerParams"`
@@ -84,20 +85,6 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
return nil, fmt.Errorf("invalid source for %q tool: source kind must be `http`", kind)
}
// Create URL based on BaseURL and Path
// Attach query parameters
u, err := url.Parse(s.BaseURL + cfg.Path)
if err != nil {
return nil, fmt.Errorf("error parsing URL: %s", err)
}
// Get existing query parameters from the URL
queryParameters := u.Query()
for key, value := range s.QueryParams {
queryParameters.Add(key, value)
}
u.RawQuery = queryParameters.Encode()
// Combine Source and Tool headers.
// In case of conflict, Tool header overrides Source header
combinedHeaders := make(map[string]string)
@@ -105,10 +92,11 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
maps.Copy(combinedHeaders, cfg.Headers)
// Create a slice for all parameters
allParameters := slices.Concat(cfg.BodyParams, cfg.HeaderParams, cfg.QueryParams)
allParameters := slices.Concat(cfg.PathParams, cfg.BodyParams, cfg.HeaderParams, cfg.QueryParams)
// Create parameter MCP manifest
paramManifest := slices.Concat(
cfg.PathParams.Manifest(),
cfg.QueryParams.Manifest(),
cfg.BodyParams.Manifest(),
cfg.HeaderParams.Manifest(),
@@ -116,13 +104,14 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
if paramManifest == nil {
paramManifest = make([]tools.ParameterManifest, 0)
}
pathMcpManifest := cfg.PathParams.McpManifest()
queryMcpManifest := cfg.QueryParams.McpManifest()
bodyMcpManifest := cfg.BodyParams.McpManifest()
headerMcpManifest := cfg.HeaderParams.McpManifest()
// Concatenate parameters for MCP `required` field
concatRequiredManifest := slices.Concat(
pathMcpManifest.Required,
queryMcpManifest.Required,
bodyMcpManifest.Required,
headerMcpManifest.Required,
@@ -133,6 +122,9 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
// Concatenate parameters for MCP `properties` field
concatPropertiesManifest := make(map[string]tools.ParameterMcpManifest)
for name, p := range pathMcpManifest.Properties {
concatPropertiesManifest[name] = p
}
for name, p := range queryMcpManifest.Properties {
concatPropertiesManifest[name] = p
}
@@ -167,20 +159,23 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
// finish tool setup
return Tool{
Name: cfg.Name,
Kind: kind,
URL: u,
Method: cfg.Method,
AuthRequired: cfg.AuthRequired,
RequestBody: cfg.RequestBody,
QueryParams: cfg.QueryParams,
BodyParams: cfg.BodyParams,
HeaderParams: cfg.HeaderParams,
Headers: combinedHeaders,
Client: s.Client,
AllParams: allParameters,
manifest: tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
Name: cfg.Name,
Kind: kind,
BaseURL: s.BaseURL,
Path: cfg.Path,
Method: cfg.Method,
AuthRequired: cfg.AuthRequired,
RequestBody: cfg.RequestBody,
PathParams: cfg.PathParams,
QueryParams: cfg.QueryParams,
BodyParams: cfg.BodyParams,
HeaderParams: cfg.HeaderParams,
Headers: combinedHeaders,
DefaultQueryParams: s.QueryParams,
Client: s.Client,
AllParams: allParameters,
manifest: tools.Manifest{Description: cfg.Description, Parameters: paramManifest, AuthRequired: cfg.AuthRequired},
mcpManifest: mcpManifest,
}, nil
}
@@ -193,14 +188,18 @@ type Tool struct {
Description string `yaml:"description"`
AuthRequired []string `yaml:"authRequired"`
URL *url.URL `yaml:"url"`
Method tools.HTTPMethod `yaml:"method"`
Headers map[string]string `yaml:"headers"`
RequestBody string `yaml:"requestBody"`
QueryParams tools.Parameters `yaml:"queryParams"`
BodyParams tools.Parameters `yaml:"bodyParams"`
HeaderParams tools.Parameters `yaml:"headerParams"`
AllParams tools.Parameters `yaml:"allParams"`
BaseURL string `yaml:"baseURL"`
Path string `yaml:"path"`
Method tools.HTTPMethod `yaml:"method"`
Headers map[string]string `yaml:"headers"`
DefaultQueryParams map[string]string `yaml:"defaultQueryParams"`
RequestBody string `yaml:"requestBody"`
PathParams tools.Parameters `yaml:"pathParams"`
QueryParams tools.Parameters `yaml:"queryParams"`
BodyParams tools.Parameters `yaml:"bodyParams"`
HeaderParams tools.Parameters `yaml:"headerParams"`
AllParams tools.Parameters `yaml:"allParams"`
Client *http.Client
manifest tools.Manifest
@@ -218,16 +217,11 @@ func convertParamToJSON(param any) (string, error) {
// Helper function to generate the HTTP request body upon Tool invocation.
func getRequestBody(bodyParams tools.Parameters, requestBodyPayload string, paramsMap map[string]any) (string, error) {
// Create a map for request body parameters
bodyParamsMap := make(map[string]any)
for _, p := range bodyParams {
k := p.GetName()
v, ok := paramsMap[k]
if !ok {
return "", fmt.Errorf("missing request body parameter %s", k)
}
bodyParamsMap[k] = v
bodyParamValues, err := tools.GetParams(bodyParams, paramsMap)
if err != nil {
return "", err
}
bodyParamsMap := bodyParamValues.AsMap()
// Create a FuncMap to format array parameters
funcMap := template.FuncMap{
@@ -246,14 +240,45 @@ func getRequestBody(bodyParams tools.Parameters, requestBodyPayload string, para
}
// Helper function to generate the HTTP request URL upon Tool invocation.
func getURL(u *url.URL, queryParams tools.Parameters, paramsMap map[string]any) (string, error) {
func getURL(baseURL, path string, pathParams, queryParams tools.Parameters, defaultQueryParams map[string]string, paramsMap map[string]any) (string, error) {
// use Go template to replace path params
pathParamValues, err := tools.GetParams(pathParams, paramsMap)
if err != nil {
return "", err
}
pathParamsMap := pathParamValues.AsMap()
templ, err := template.New("url").Parse(path)
if err != nil {
return "", fmt.Errorf("error parsing URL: %s", err)
}
var templatedPath bytes.Buffer
err = templ.Execute(&templatedPath, pathParamsMap)
if err != nil {
return "", fmt.Errorf("error replacing pathParams: %s", err)
}
// Create URL based on BaseURL and Path
// Attach query parameters
parsedURL, err := url.Parse(baseURL + templatedPath.String())
if err != nil {
return "", fmt.Errorf("error parsing URL: %s", err)
}
// Get existing query parameters from the URL
queryParameters := parsedURL.Query()
for key, value := range defaultQueryParams {
queryParameters.Add(key, value)
}
parsedURL.RawQuery = queryParameters.Encode()
// Set dynamic query parameters
query := u.Query()
query := parsedURL.Query()
for _, p := range queryParams {
query.Add(p.GetName(), fmt.Sprintf("%v", paramsMap[p.GetName()]))
}
u.RawQuery = query.Encode()
return u.String(), nil
parsedURL.RawQuery = query.Encode()
return parsedURL.String(), nil
}
// Helper function to generate the HTTP headers upon Tool invocation.
@@ -284,9 +309,9 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
}
// Calculate URL
urlString, err := getURL(t.URL, t.QueryParams, paramsMap)
urlString, err := getURL(t.BaseURL, t.Path, t.PathParams, t.QueryParams, t.DefaultQueryParams, paramsMap)
if err != nil {
return nil, fmt.Errorf("error populating query parameters: %s", err)
return nil, fmt.Errorf("error populating path parameters: %s", err)
}
req, _ := http.NewRequest(string(t.Method), urlString, strings.NewReader(requestBody))

View File

@@ -44,7 +44,30 @@ func TestParseFromYamlHTTP(t *testing.T) {
kind: http
source: my-instance
method: GET
path: "search?name=alice&pet=cat"
description: some description
path: search
`,
want: server.ToolConfigs{
"example_tool": http.Config{
Name: "example_tool",
Kind: "http",
Source: "my-instance",
Method: "GET",
Path: "search",
Description: "some description",
AuthRequired: []string{},
},
},
},
{
desc: "advanced example",
in: `
tools:
example_tool:
kind: http
source: my-instance
method: GET
path: "{{.pathParam}}?name=alice&pet=cat"
description: some description
authRequired:
- my-google-auth-service
@@ -58,6 +81,10 @@ func TestParseFromYamlHTTP(t *testing.T) {
field: user_id
- name: other-auth-service
field: user_id
pathParams:
- name: pathParam
type: string
description: path param
requestBody: |
{
"age": {{.age}},
@@ -85,7 +112,7 @@ func TestParseFromYamlHTTP(t *testing.T) {
Kind: "http",
Source: "my-instance",
Method: "GET",
Path: "search?name=alice&pet=cat",
Path: "{{.pathParam}}?name=alice&pet=cat",
Description: "some description",
AuthRequired: []string{"my-google-auth-service", "other-auth-service"},
QueryParams: []tools.Parameter{
@@ -93,6 +120,11 @@ func TestParseFromYamlHTTP(t *testing.T) {
[]tools.ParamAuthService{{Name: "my-google-auth-service", Field: "user_id"},
{Name: "other-auth-service", Field: "user_id"}}),
},
PathParams: tools.Parameters{
&tools.StringParameter{
CommonParameter: tools.CommonParameter{Name: "pathParam", Type: "string", Desc: "path param"},
},
},
RequestBody: `{
"age": {{.age}},
"city": "{{.city}}",

Some files were not shown because too many files have changed in this diff Show More