mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-01-12 00:49:08 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fb1235cb0 |
@@ -17,8 +17,15 @@ steps:
|
||||
waitFor: ['-']
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
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 .
|
||||
docker buildx build --build-arg COMMIT_SHA=$(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
|
||||
|
||||
- id: "install-dependencies"
|
||||
name: golang:1
|
||||
@@ -123,7 +130,6 @@ options:
|
||||
automapSubstitutions: true
|
||||
dynamicSubstitutions: true
|
||||
logging: CLOUD_LOGGING_ONLY # Necessary for custom service account
|
||||
machineType: 'E2_HIGHCPU_32'
|
||||
|
||||
substitutions:
|
||||
_REGION: us-central1
|
||||
|
||||
@@ -33,7 +33,7 @@ steps:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
script: |
|
||||
go test -c -race ./tests/...
|
||||
go test -c -cover -coverprofile=coverage.out -race ./tests/...
|
||||
|
||||
- id: "cloud-sql-pg"
|
||||
name: golang:1
|
||||
@@ -75,7 +75,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
./alloydbpg.test -test.v
|
||||
./alloydbpg.test -test.v -test.coverprofile=coverage.out
|
||||
|
||||
- id: "alloydb-ai-nl"
|
||||
name: golang:1
|
||||
|
||||
@@ -18,13 +18,19 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
docker buildx create --name container-builder --driver docker-container --bootstrap --use
|
||||
docker buildx build --build-arg BUILD_TYPE=container.release --build-arg COMMIT_SHA=$(git rev-parse HEAD) -t ${_DOCKER_URI}:$VERSION -t ${_DOCKER_URI}:latest .
|
||||
|
||||
export TAGS="-t ${_DOCKER_URI}:$VERSION"
|
||||
- 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
|
||||
if [[ $_PUSH_LATEST == 'true' ]]; then
|
||||
export TAGS="$TAGS -t ${_DOCKER_URI}:latest"
|
||||
docker push ${_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
|
||||
@@ -137,7 +143,6 @@ options:
|
||||
automapSubstitutions: true
|
||||
dynamicSubstitutions: true
|
||||
logging: CLOUD_LOGGING_ONLY # Necessary for custom service account
|
||||
machineType: 'E2_HIGHCPU_32'
|
||||
|
||||
substitutions:
|
||||
_REGION: us-central1
|
||||
|
||||
9
.github/blunderbuss.yml
vendored
9
.github/blunderbuss.yml
vendored
@@ -2,14 +2,7 @@ assign_issues:
|
||||
- kurtisvg
|
||||
- Yuan325
|
||||
- duwenxin99
|
||||
assign_issues_by:
|
||||
- labels:
|
||||
- 'product: bigquery'
|
||||
to:
|
||||
- Genesis929
|
||||
- shobsi
|
||||
- jiaxunwu
|
||||
assign_prs:
|
||||
- kurtisvg
|
||||
- Yuan325
|
||||
- duwenxin99
|
||||
- duwenxin99
|
||||
6
.github/labels.yaml
vendored
6
.github/labels.yaml
vendored
@@ -84,9 +84,3 @@
|
||||
- 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.
|
||||
|
||||
|
||||
2
.github/sync-repo-settings.yaml
vendored
2
.github/sync-repo-settings.yaml
vendored
@@ -31,8 +31,6 @@ 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
|
||||
|
||||
12
.github/workflows/tests.yaml
vendored
12
.github/workflows/tests.yaml
vendored
@@ -32,7 +32,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
# os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
os: [ubuntu-latest]
|
||||
fail-fast: false
|
||||
permissions:
|
||||
contents: 'read'
|
||||
@@ -74,8 +75,7 @@ jobs:
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Run tests with coverage
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
- name: Run tests
|
||||
run: |
|
||||
source_dir="./internal/sources/*"
|
||||
tool_dir="./internal/tools/*"
|
||||
@@ -85,13 +85,7 @@ 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')
|
||||
|
||||
42
DEVELOPER.md
42
DEVELOPER.md
@@ -41,48 +41,6 @@
|
||||
|
||||
### 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
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
# 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 . .
|
||||
|
||||
33
cmd/root.go
33
cmd/root.go
@@ -284,7 +284,7 @@ func run(cmd *Command) error {
|
||||
ctx = util.WithLogger(ctx, cmd.logger)
|
||||
|
||||
// Set up OpenTelemetry
|
||||
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.cfg.Version, cmd.cfg.TelemetryOTLP, cmd.cfg.TelemetryGCP, cmd.cfg.TelemetryServiceName)
|
||||
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.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())
|
||||
@@ -352,33 +352,30 @@ 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)
|
||||
if cmd.cfg.Stdio {
|
||||
go func() {
|
||||
defer close(srvErr)
|
||||
go func() {
|
||||
defer close(srvErr)
|
||||
if cmd.cfg.Stdio {
|
||||
err = s.ServeStdio(ctx, cmd.inStream, cmd.outStream)
|
||||
if err != nil {
|
||||
srvErr <- err
|
||||
}
|
||||
}()
|
||||
} 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)
|
||||
} else {
|
||||
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 {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
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 IDE’s 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
|
||||
@@ -1,22 +0,0 @@
|
||||
---
|
||||
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
|
||||
@@ -5,9 +5,266 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to AlloyDB using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
@@ -5,9 +5,235 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to BigQuery using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
@@ -5,9 +5,265 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to Cloud SQL for SQL Server using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
|
||||
@@ -5,9 +5,259 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to Cloud SQL for MySQL using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
|
||||
@@ -5,9 +5,260 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to Cloud SQL for Postgres using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
|
||||
@@ -5,9 +5,354 @@ weight: 2
|
||||
description: >
|
||||
Connect your IDE to Spanner using Toolbox.
|
||||
---
|
||||
<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>
|
||||
|
||||
[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.7.0/linux/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="darwin/arm64" lang="bash" >}}
|
||||
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.7.0/darwin/amd64/toolbox
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="windows/amd64" lang="bash" >}}
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.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 >}}
|
||||
@@ -27,7 +27,6 @@ sources:
|
||||
queryParams:
|
||||
param1: value1
|
||||
param2: value2
|
||||
# disableSslVerification: false
|
||||
```
|
||||
|
||||
{{< notice tip >}}
|
||||
@@ -37,13 +36,12 @@ 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. |
|
||||
| disableSslVerification | bool | false | Disable SSL certificate verification. This should only be used for local development. Defaults to `false`. |
|
||||
| **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. |
|
||||
|
||||
[parse-duration-doc]: https://pkg.go.dev/time#ParseDuration
|
||||
|
||||
@@ -79,12 +79,11 @@ 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" |
|
||||
| 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. |
|
||||
| **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. |
|
||||
|
||||
### Array Parameters
|
||||
|
||||
@@ -103,17 +102,12 @@ 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" |
|
||||
| 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 >}}
|
||||
| **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. |
|
||||
|
||||
### Authenticated Parameters
|
||||
|
||||
|
||||
@@ -20,16 +20,12 @@ 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
|
||||
@@ -63,40 +59,12 @@ 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. |
|
||||
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared 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. |
|
||||
|
||||
@@ -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,43 +62,15 @@ 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. |
|
||||
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared 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. |
|
||||
|
||||
## Tips
|
||||
|
||||
|
||||
@@ -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,41 +58,13 @@ 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. |
|
||||
| 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. |
|
||||
| **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. |
|
||||
|
||||
@@ -16,12 +16,7 @@ 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 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.
|
||||
|
||||
Toolbox composes the request URL from the HTTP Source's `baseUrl` and the HTTP Tool's `path`.
|
||||
For example, the following config allows you to reach different paths of the same server using multiple Tools:
|
||||
|
||||
```yaml
|
||||
@@ -44,17 +39,6 @@ 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
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -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,40 +70,12 @@ 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. |
|
||||
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared 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. |
|
||||
|
||||
@@ -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,40 +65,12 @@ 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. |
|
||||
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared 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. |
|
||||
|
||||
@@ -22,8 +22,6 @@ will be the first parameter specified, `$@` will be the second parameter, and so
|
||||
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.
|
||||
@@ -31,6 +29,8 @@ of the prepared statement.
|
||||
> 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
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
search_flights_by_number:
|
||||
@@ -71,11 +71,10 @@ tools:
|
||||
|
||||
### 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).
|
||||
> **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:
|
||||
|
||||
@@ -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,41 +125,13 @@ 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`. |
|
||||
| templateParameters | [templateParameters](_index#template-parameters) | false | List of [templateParameters](_index#template-parameters) that will be inserted into the SQL statement before executing prepared statement. |
|
||||
| **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`. |
|
||||
|
||||
@@ -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,41 +43,12 @@ 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 | 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. |
|
||||
| **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 |
|
||||
|
||||
14
go.mod
14
go.mod
@@ -10,15 +10,15 @@ require (
|
||||
cloud.google.com/go/bigtable v1.37.0
|
||||
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.53.0
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.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/couchbase/gocb/v2 v2.10.0
|
||||
github.com/couchbase/tools-common/http v1.0.9
|
||||
github.com/go-chi/chi/v5 v5.2.2
|
||||
github.com/go-chi/chi/v5 v5.2.1
|
||||
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.3
|
||||
github.com/go-sql-driver/mysql v1.9.2
|
||||
github.com/goccy/go-yaml v1.18.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/uuid v1.6.0
|
||||
@@ -26,7 +26,7 @@ require (
|
||||
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/redis/go-redis/v9 v9.9.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
|
||||
@@ -38,7 +38,7 @@ 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.238.0
|
||||
google.golang.org/api v0.236.0
|
||||
modernc.org/sqlite v1.38.0
|
||||
)
|
||||
|
||||
@@ -58,7 +58,7 @@ 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.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.52.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
|
||||
|
||||
32
go.sum
32
go.sum
@@ -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.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/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/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=
|
||||
@@ -768,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.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
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/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=
|
||||
@@ -803,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.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
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-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=
|
||||
@@ -1051,8 +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/redis/go-redis/v9 v9.9.0 h1:URbPQ4xVQSQhZ27WMQVmZSo3uT3pL+4IdHVcYq2nVfM=
|
||||
github.com/redis/go-redis/v9 v9.9.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=
|
||||
@@ -1605,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.238.0 h1:+EldkglWIg/pWjkq97sd+XxH7PxakNYoe/rkSTbnvOs=
|
||||
google.golang.org/api v0.238.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
|
||||
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/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=
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"slices"
|
||||
|
||||
"cloud.google.com/go/cloudsqlconn/sqlserver/mssql"
|
||||
@@ -112,13 +111,7 @@ func initCloudSQLMssqlConnection(ctx context.Context, tracer trace.Tracer, name,
|
||||
defer span.End()
|
||||
|
||||
// Create dsn
|
||||
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,
|
||||
}
|
||||
dsn := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&cloudsql=%s:%s:%s", user, pass, ipAddress, dbname, project, region, instance)
|
||||
|
||||
// Get dial options
|
||||
userAgent, err := util.UserAgentFromContext(ctx)
|
||||
@@ -141,7 +134,7 @@ func initCloudSQLMssqlConnection(ctx context.Context, tracer trace.Tracer, name,
|
||||
// Open database connection
|
||||
db, err := sql.Open(
|
||||
"cloudsql-sqlserver-driver",
|
||||
url.String(),
|
||||
dsn,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -15,7 +15,6 @@ package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -23,7 +22,6 @@ import (
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||
"github.com/googleapis/genai-toolbox/internal/util"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
@@ -47,13 +45,12 @@ func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources
|
||||
}
|
||||
|
||||
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"`
|
||||
DisableSslVerification bool `yaml:"disableSslVerification"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func (r Config) SourceConfigKind() string {
|
||||
@@ -66,25 +63,8 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
|
||||
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,
|
||||
Transport: tr,
|
||||
Timeout: duration,
|
||||
}
|
||||
|
||||
// Validate BaseURL
|
||||
|
||||
@@ -34,24 +34,6 @@ 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
|
||||
@@ -63,17 +45,15 @@ 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"},
|
||||
DisableSslVerification: true,
|
||||
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"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||
@@ -107,17 +106,10 @@ func initMssqlConnection(ctx context.Context, tracer trace.Tracer, name, host, p
|
||||
defer span.End()
|
||||
|
||||
// Create dsn
|
||||
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(),
|
||||
}
|
||||
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s", user, pass, host, port, dbname)
|
||||
|
||||
// Open database connection
|
||||
db, err := sql.Open("sqlserver", url.String())
|
||||
db, err := sql.Open("sqlserver", dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sql.Open: %w", err)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package postgres
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||
@@ -97,15 +96,9 @@ 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"
|
||||
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())
|
||||
i := fmt.Sprintf("postgres://%s:%s@%s:%s/%s", user, pass, host, port, dbname)
|
||||
pool, err := pgxpool.New(ctx, i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create connection pool: %w", err)
|
||||
}
|
||||
|
||||
@@ -53,14 +53,13 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// validate interface
|
||||
@@ -83,26 +82,22 @@ 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: paramMcpManifest,
|
||||
InputSchema: cfg.Parameters.McpManifest(),
|
||||
}
|
||||
|
||||
// finish tool setup
|
||||
t := Tool{
|
||||
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,
|
||||
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,
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
@@ -111,12 +106,10 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
AllParams tools.Parameters `yaml:"allParams"`
|
||||
Name string `yaml:"name"`
|
||||
Kind string `yaml:"kind"`
|
||||
AuthRequired []string `yaml:"authRequired"`
|
||||
Parameters tools.Parameters `yaml:"parameters"`
|
||||
|
||||
Client *bigqueryapi.Client
|
||||
Statement string
|
||||
@@ -125,22 +118,11 @@ type Tool struct {
|
||||
}
|
||||
|
||||
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
|
||||
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 := make([]bigqueryapi.QueryParameter, 0, len(params))
|
||||
paramsMap := params.AsReversedMap()
|
||||
for _, v := range params.AsSlice() {
|
||||
paramName := paramsMap[v]
|
||||
if strings.Contains(t.Statement, "@"+paramName) {
|
||||
namedArgs = append(namedArgs, bigqueryapi.QueryParameter{
|
||||
Name: paramName,
|
||||
Value: v,
|
||||
@@ -152,7 +134,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
|
||||
}
|
||||
}
|
||||
|
||||
query := t.Client.Query(newStatement)
|
||||
query := t.Client.Query(t.Statement)
|
||||
query.Parameters = namedArgs
|
||||
query.Location = t.Client.Location
|
||||
|
||||
@@ -182,7 +164,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.AllParams, data, claims)
|
||||
return tools.ParseParams(t.Parameters, data, claims)
|
||||
}
|
||||
|
||||
func (t Tool) Manifest() tools.Manifest {
|
||||
|
||||
@@ -82,76 +82,3 @@ 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,14 +51,13 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// validate interface
|
||||
@@ -81,26 +80,22 @@ 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: paramMcpManifest,
|
||||
InputSchema: cfg.Parameters.McpManifest(),
|
||||
}
|
||||
|
||||
// finish tool setup
|
||||
t := Tool{
|
||||
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,
|
||||
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,
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
@@ -109,12 +104,10 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
AllParams tools.Parameters `yaml:"allParams"`
|
||||
Name string `yaml:"name"`
|
||||
Kind string `yaml:"kind"`
|
||||
AuthRequired []string `yaml:"authRequired"`
|
||||
Parameters tools.Parameters `yaml:"parameters"`
|
||||
|
||||
Client *bigtable.Client
|
||||
Statement string
|
||||
@@ -148,32 +141,21 @@ func getMapParamsType(tparams tools.Parameters, params tools.ParamValues) (map[s
|
||||
}
|
||||
|
||||
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
|
||||
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)
|
||||
mapParamsType, err := getMapParamsType(t.Parameters, params)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to get map params: %w", err)
|
||||
}
|
||||
|
||||
ps, err := t.Client.PrepareStatement(
|
||||
ctx,
|
||||
newStatement,
|
||||
t.Statement,
|
||||
mapParamsType,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to prepare statement: %w", err)
|
||||
}
|
||||
|
||||
bs, err := ps.Bind(newParams.AsMap())
|
||||
bs, err := ps.Bind(params.AsMap())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to bind: %w", err)
|
||||
}
|
||||
@@ -201,7 +183,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.AllParams, data, claims)
|
||||
return tools.ParseParams(t.Parameters, data, claims)
|
||||
}
|
||||
|
||||
func (t Tool) Manifest() tools.Manifest {
|
||||
|
||||
@@ -82,76 +82,3 @@ 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,14 +53,13 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// validate interface
|
||||
@@ -83,25 +82,21 @@ 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: paramMcpManifest,
|
||||
InputSchema: cfg.Parameters.McpManifest(),
|
||||
}
|
||||
// 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: paramManifest, AuthRequired: cfg.AuthRequired},
|
||||
manifest: tools.Manifest{Description: cfg.Description, Parameters: cfg.Parameters.Manifest(), AuthRequired: cfg.AuthRequired},
|
||||
mcpManifest: mcpManifest,
|
||||
}
|
||||
return t, nil
|
||||
@@ -111,12 +106,10 @@ 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"`
|
||||
TemplateParameters tools.Parameters `yaml:"templateParameters"`
|
||||
AllParams tools.Parameters `yaml:"allParams"`
|
||||
AuthRequired []string `yaml:"authRequired"`
|
||||
Name string `yaml:"name"`
|
||||
Kind string `yaml:"kind"`
|
||||
Parameters tools.Parameters `yaml:"parameters"`
|
||||
AuthRequired []string `yaml:"authRequired"`
|
||||
|
||||
Scope *gocb.Scope
|
||||
QueryScanConsistency uint
|
||||
@@ -126,19 +119,10 @@ type Tool struct {
|
||||
}
|
||||
|
||||
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, error) {
|
||||
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{
|
||||
namedParams := params.AsMap()
|
||||
results, err := t.Scope.Query(t.Statement, &gocb.QueryOptions{
|
||||
ScanConsistency: gocb.QueryScanConsistency(t.QueryScanConsistency),
|
||||
NamedParameters: newParams.AsMap(),
|
||||
NamedParameters: namedParams,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to execute query: %w", err)
|
||||
@@ -157,7 +141,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.AllParams, data, claimsMap)
|
||||
return tools.ParseParams(t.Parameters, data, claimsMap)
|
||||
}
|
||||
|
||||
func (t Tool) Manifest() tools.Manifest {
|
||||
|
||||
@@ -85,67 +85,3 @@ 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ 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"`
|
||||
@@ -85,6 +84,20 @@ 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)
|
||||
@@ -92,11 +105,10 @@ 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.PathParams, cfg.BodyParams, cfg.HeaderParams, cfg.QueryParams)
|
||||
allParameters := slices.Concat(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(),
|
||||
@@ -104,14 +116,13 @@ 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,
|
||||
@@ -122,9 +133,6 @@ 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
|
||||
}
|
||||
@@ -159,23 +167,20 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
|
||||
|
||||
// finish tool setup
|
||||
return Tool{
|
||||
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,
|
||||
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,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -188,18 +193,14 @@ type Tool struct {
|
||||
Description string `yaml:"description"`
|
||||
AuthRequired []string `yaml:"authRequired"`
|
||||
|
||||
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"`
|
||||
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"`
|
||||
|
||||
Client *http.Client
|
||||
manifest tools.Manifest
|
||||
@@ -240,45 +241,14 @@ func getRequestBody(bodyParams tools.Parameters, requestBodyPayload string, para
|
||||
}
|
||||
|
||||
// Helper function to generate the HTTP request URL upon Tool invocation.
|
||||
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()
|
||||
|
||||
func getURL(u *url.URL, queryParams tools.Parameters, paramsMap map[string]any) (string, error) {
|
||||
// Set dynamic query parameters
|
||||
query := parsedURL.Query()
|
||||
query := u.Query()
|
||||
for _, p := range queryParams {
|
||||
query.Add(p.GetName(), fmt.Sprintf("%v", paramsMap[p.GetName()]))
|
||||
}
|
||||
parsedURL.RawQuery = query.Encode()
|
||||
return parsedURL.String(), nil
|
||||
u.RawQuery = query.Encode()
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// Helper function to generate the HTTP headers upon Tool invocation.
|
||||
@@ -309,9 +279,9 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues) ([]any, erro
|
||||
}
|
||||
|
||||
// Calculate URL
|
||||
urlString, err := getURL(t.BaseURL, t.Path, t.PathParams, t.QueryParams, t.DefaultQueryParams, paramsMap)
|
||||
urlString, err := getURL(t.URL, t.QueryParams, paramsMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error populating path parameters: %s", err)
|
||||
return nil, fmt.Errorf("error populating query parameters: %s", err)
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest(string(t.Method), urlString, strings.NewReader(requestBody))
|
||||
|
||||
@@ -44,30 +44,7 @@ func TestParseFromYamlHTTP(t *testing.T) {
|
||||
kind: http
|
||||
source: my-instance
|
||||
method: GET
|
||||
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"
|
||||
path: "search?name=alice&pet=cat"
|
||||
description: some description
|
||||
authRequired:
|
||||
- my-google-auth-service
|
||||
@@ -81,10 +58,6 @@ 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}},
|
||||
@@ -112,7 +85,7 @@ func TestParseFromYamlHTTP(t *testing.T) {
|
||||
Kind: "http",
|
||||
Source: "my-instance",
|
||||
Method: "GET",
|
||||
Path: "{{.pathParam}}?name=alice&pet=cat",
|
||||
Path: "search?name=alice&pet=cat",
|
||||
Description: "some description",
|
||||
AuthRequired: []string{"my-google-auth-service", "other-auth-service"},
|
||||
QueryParams: []tools.Parameter{
|
||||
@@ -120,11 +93,6 @@ 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}}",
|
||||
|
||||
@@ -130,10 +130,7 @@ func ParseParams(ps Parameters, data map[string]any, claimsMap map[string]map[st
|
||||
var ok bool
|
||||
v, ok = data[name]
|
||||
if !ok {
|
||||
v = p.GetDefault()
|
||||
if v == nil {
|
||||
return nil, fmt.Errorf("parameter %q is required", name)
|
||||
}
|
||||
return nil, fmt.Errorf("parameter %q is required", name)
|
||||
}
|
||||
} else {
|
||||
// parse authenticated parameter
|
||||
@@ -256,7 +253,6 @@ type Parameter interface {
|
||||
// but this is done to differentiate it from the fields in CommonParameter.
|
||||
GetName() string
|
||||
GetType() string
|
||||
GetDefault() any
|
||||
GetAuthServices() []ParamAuthService
|
||||
Parse(any) (any, error)
|
||||
Manifest() ParameterManifest
|
||||
@@ -386,10 +382,8 @@ func (ps Parameters) McpManifest() McpToolsSchema {
|
||||
for _, p := range ps {
|
||||
name := p.GetName()
|
||||
properties[name] = p.McpManifest()
|
||||
// parameters that doesn't have a default value are added to the required field
|
||||
if p.GetDefault() == nil {
|
||||
required = append(required, name)
|
||||
}
|
||||
// all parameters are added to the required field
|
||||
required = append(required, name)
|
||||
}
|
||||
|
||||
return McpToolsSchema{
|
||||
@@ -403,7 +397,6 @@ func (ps Parameters) McpManifest() McpToolsSchema {
|
||||
type ParameterManifest struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Required bool `json:"required"`
|
||||
Description string `json:"description"`
|
||||
AuthServices []string `json:"authSources"`
|
||||
Items *ParameterManifest `json:"items,omitempty"`
|
||||
@@ -420,7 +413,6 @@ type ParameterMcpManifest struct {
|
||||
type CommonParameter struct {
|
||||
Name string `yaml:"name" validate:"required"`
|
||||
Type string `yaml:"type" validate:"required"`
|
||||
Default any `yaml:"default"`
|
||||
Desc string `yaml:"description" validate:"required"`
|
||||
AuthServices []ParamAuthService `yaml:"authServices"`
|
||||
AuthSources []ParamAuthService `yaml:"authSources"` // Deprecated: Kept for compatibility.
|
||||
@@ -436,10 +428,6 @@ func (p *CommonParameter) GetType() string {
|
||||
return p.Type
|
||||
}
|
||||
|
||||
func (p *CommonParameter) GetDefault() any {
|
||||
return p.Default
|
||||
}
|
||||
|
||||
// Manifest returns the manifest for the Parameter.
|
||||
func (p *CommonParameter) Manifest() ParameterManifest {
|
||||
// only list ParamAuthService names (without fields) in manifest
|
||||
@@ -447,14 +435,9 @@ func (p *CommonParameter) Manifest() ParameterManifest {
|
||||
for i, a := range p.AuthServices {
|
||||
authNames[i] = a.Name
|
||||
}
|
||||
var required bool
|
||||
if p.Default == nil {
|
||||
required = true
|
||||
}
|
||||
return ParameterManifest{
|
||||
Name: p.Name,
|
||||
Type: p.Type,
|
||||
Required: required,
|
||||
Description: p.Desc,
|
||||
AuthServices: authNames,
|
||||
}
|
||||
@@ -485,7 +468,7 @@ type ParamAuthService struct {
|
||||
}
|
||||
|
||||
// NewStringParameter is a convenience function for initializing a StringParameter.
|
||||
func NewStringParameter(name string, desc string) *StringParameter {
|
||||
func NewStringParameter(name, desc string) *StringParameter {
|
||||
return &StringParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -496,21 +479,8 @@ func NewStringParameter(name string, desc string) *StringParameter {
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringParameterWithDefault is a convenience function for initializing a StringParameter with default value.
|
||||
func NewStringParameterWithDefault(name string, defaultV, desc string) *StringParameter {
|
||||
return &StringParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
Type: typeString,
|
||||
Default: defaultV,
|
||||
Desc: desc,
|
||||
AuthServices: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringParameterWithAuth is a convenience function for initializing a StringParameter with a list of ParamAuthService.
|
||||
func NewStringParameterWithAuth(name string, desc string, authServices []ParamAuthService) *StringParameter {
|
||||
func NewStringParameterWithAuth(name, desc string, authServices []ParamAuthService) *StringParameter {
|
||||
return &StringParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -541,7 +511,7 @@ func (p *StringParameter) GetAuthServices() []ParamAuthService {
|
||||
}
|
||||
|
||||
// NewIntParameter is a convenience function for initializing a IntParameter.
|
||||
func NewIntParameter(name string, desc string) *IntParameter {
|
||||
func NewIntParameter(name, desc string) *IntParameter {
|
||||
return &IntParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -552,21 +522,8 @@ func NewIntParameter(name string, desc string) *IntParameter {
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntParameterWithDefault is a convenience function for initializing a IntParameter with default value.
|
||||
func NewIntParameterWithDefault(name string, defaultV any, desc string) *IntParameter {
|
||||
return &IntParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
Type: typeInt,
|
||||
Default: defaultV,
|
||||
Desc: desc,
|
||||
AuthServices: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntParameterWithAuth is a convenience function for initializing a IntParameter with a list of ParamAuthService.
|
||||
func NewIntParameterWithAuth(name string, desc string, authServices []ParamAuthService) *IntParameter {
|
||||
func NewIntParameterWithAuth(name, desc string, authServices []ParamAuthService) *IntParameter {
|
||||
return &IntParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -610,7 +567,7 @@ func (p *IntParameter) GetAuthServices() []ParamAuthService {
|
||||
}
|
||||
|
||||
// NewFloatParameter is a convenience function for initializing a FloatParameter.
|
||||
func NewFloatParameter(name string, desc string) *FloatParameter {
|
||||
func NewFloatParameter(name, desc string) *FloatParameter {
|
||||
return &FloatParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -621,21 +578,8 @@ func NewFloatParameter(name string, desc string) *FloatParameter {
|
||||
}
|
||||
}
|
||||
|
||||
// NewFloatParameterWithDefault is a convenience function for initializing a FloatParameter with default value.
|
||||
func NewFloatParameterWithDefault(name string, defaultV float64, desc string) *FloatParameter {
|
||||
return &FloatParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
Type: typeFloat,
|
||||
Default: defaultV,
|
||||
Desc: desc,
|
||||
AuthServices: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewFloatParameterWithAuth is a convenience function for initializing a FloatParameter with a list of ParamAuthService.
|
||||
func NewFloatParameterWithAuth(name string, desc string, authServices []ParamAuthService) *FloatParameter {
|
||||
func NewFloatParameterWithAuth(name, desc string, authServices []ParamAuthService) *FloatParameter {
|
||||
return &FloatParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -677,7 +621,7 @@ func (p *FloatParameter) GetAuthServices() []ParamAuthService {
|
||||
}
|
||||
|
||||
// NewBooleanParameter is a convenience function for initializing a BooleanParameter.
|
||||
func NewBooleanParameter(name string, desc string) *BooleanParameter {
|
||||
func NewBooleanParameter(name, desc string) *BooleanParameter {
|
||||
return &BooleanParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -688,21 +632,8 @@ func NewBooleanParameter(name string, desc string) *BooleanParameter {
|
||||
}
|
||||
}
|
||||
|
||||
// NewBooleanParameterWithDefault is a convenience function for initializing a BooleanParameter with default value.
|
||||
func NewBooleanParameterWithDefault(name string, defaultV bool, desc string) *BooleanParameter {
|
||||
return &BooleanParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
Type: typeBool,
|
||||
Default: defaultV,
|
||||
Desc: desc,
|
||||
AuthServices: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewBooleanParameterWithAuth is a convenience function for initializing a BooleanParameter with a list of ParamAuthService.
|
||||
func NewBooleanParameterWithAuth(name string, desc string, authServices []ParamAuthService) *BooleanParameter {
|
||||
func NewBooleanParameterWithAuth(name, desc string, authServices []ParamAuthService) *BooleanParameter {
|
||||
return &BooleanParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -733,7 +664,7 @@ func (p *BooleanParameter) GetAuthServices() []ParamAuthService {
|
||||
}
|
||||
|
||||
// NewArrayParameter is a convenience function for initializing a ArrayParameter.
|
||||
func NewArrayParameter(name string, desc string, items Parameter) *ArrayParameter {
|
||||
func NewArrayParameter(name, desc string, items Parameter) *ArrayParameter {
|
||||
return &ArrayParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -745,22 +676,8 @@ func NewArrayParameter(name string, desc string, items Parameter) *ArrayParamete
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayParameterWithDefault is a convenience function for initializing a ArrayParameter with default value.
|
||||
func NewArrayParameterWithDefault(name string, defaultV any, desc string, items Parameter) *ArrayParameter {
|
||||
return &ArrayParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
Type: typeArray,
|
||||
Default: defaultV,
|
||||
Desc: desc,
|
||||
AuthServices: nil,
|
||||
},
|
||||
Items: items,
|
||||
}
|
||||
}
|
||||
|
||||
// NewArrayParameterWithAuth is a convenience function for initializing a ArrayParameter with a list of ParamAuthService.
|
||||
func NewArrayParameterWithAuth(name string, desc string, items Parameter, authServices []ParamAuthService) *ArrayParameter {
|
||||
func NewArrayParameterWithAuth(name, desc string, items Parameter, authServices []ParamAuthService) *ArrayParameter {
|
||||
return &ArrayParameter{
|
||||
CommonParameter: CommonParameter{
|
||||
Name: name,
|
||||
@@ -829,15 +746,9 @@ func (p *ArrayParameter) Manifest() ParameterManifest {
|
||||
authNames[i] = a.Name
|
||||
}
|
||||
items := p.Items.Manifest()
|
||||
var required bool
|
||||
if p.Default == nil {
|
||||
required = true
|
||||
items.Required = true
|
||||
}
|
||||
return ParameterManifest{
|
||||
Name: p.Name,
|
||||
Type: p.Type,
|
||||
Required: required,
|
||||
Description: p.Desc,
|
||||
AuthServices: authNames,
|
||||
Items: &items,
|
||||
|
||||
@@ -125,100 +125,6 @@ func TestParametersMarshal(t *testing.T) {
|
||||
tools.NewArrayParameter("my_array", "this param is an array of floats", tools.NewFloatParameter("my_float", "float item")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_string",
|
||||
"type": "string",
|
||||
"default": "foo",
|
||||
"description": "this param is a string",
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewStringParameterWithDefault("my_string", "foo", "this param is a string"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "int default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_integer",
|
||||
"type": "integer",
|
||||
"default": 5,
|
||||
"description": "this param is an int",
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewIntParameterWithDefault("my_integer", uint64(5), "this param is an int"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "float default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_float",
|
||||
"type": "float",
|
||||
"default": 1.1,
|
||||
"description": "my param is a float",
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewFloatParameterWithDefault("my_float", 1.1, "my param is a float"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bool default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_bool",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "this param is a boolean",
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewBooleanParameterWithDefault("my_bool", true, "this param is a boolean"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string array default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_array",
|
||||
"type": "array",
|
||||
"default": `["foo", "bar"]`,
|
||||
"description": "this param is an array of strings",
|
||||
"items": map[string]string{
|
||||
"name": "my_string",
|
||||
"type": "string",
|
||||
"description": "string item",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewArrayParameterWithDefault("my_array", `["foo", "bar"]`, "this param is an array of strings", tools.NewStringParameter("my_string", "string item")),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "float array default",
|
||||
in: []map[string]any{
|
||||
{
|
||||
"name": "my_array",
|
||||
"type": "array",
|
||||
"default": "[1.0, 1.1]",
|
||||
"description": "this param is an array of floats",
|
||||
"items": map[string]string{
|
||||
"name": "my_float",
|
||||
"type": "float",
|
||||
"description": "float item",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: tools.Parameters{
|
||||
tools.NewArrayParameterWithDefault("my_array", "[1.0, 1.1]", "this param is an array of floats", tools.NewFloatParameter("my_float", "float item")),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -633,46 +539,6 @@ func TestParametersParse(t *testing.T) {
|
||||
"my_bool": 1.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string default",
|
||||
params: tools.Parameters{
|
||||
tools.NewStringParameterWithDefault("my_string", "foo", "this param is a string"),
|
||||
},
|
||||
in: map[string]any{},
|
||||
want: tools.ParamValues{tools.ParamValue{Name: "my_string", Value: "foo"}},
|
||||
},
|
||||
{
|
||||
name: "int default",
|
||||
params: tools.Parameters{
|
||||
tools.NewIntParameterWithDefault("my_int", 100, "this param is an int"),
|
||||
},
|
||||
in: map[string]any{},
|
||||
want: tools.ParamValues{tools.ParamValue{Name: "my_int", Value: 100}},
|
||||
},
|
||||
{
|
||||
name: "int (big)",
|
||||
params: tools.Parameters{
|
||||
tools.NewIntParameterWithDefault("my_big_int", math.MaxInt64, "this param is an int"),
|
||||
},
|
||||
in: map[string]any{},
|
||||
want: tools.ParamValues{tools.ParamValue{Name: "my_big_int", Value: math.MaxInt64}},
|
||||
},
|
||||
{
|
||||
name: "float default",
|
||||
params: tools.Parameters{
|
||||
tools.NewFloatParameterWithDefault("my_float", 1.1, "this param is a float"),
|
||||
},
|
||||
in: map[string]any{},
|
||||
want: tools.ParamValues{tools.ParamValue{Name: "my_float", Value: 1.1}},
|
||||
},
|
||||
{
|
||||
name: "bool default",
|
||||
params: tools.Parameters{
|
||||
tools.NewBooleanParameterWithDefault("my_bool", true, "this param is a bool"),
|
||||
},
|
||||
in: map[string]any{},
|
||||
want: tools.ParamValues{tools.ParamValue{Name: "my_bool", Value: true}},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -942,22 +808,22 @@ func TestParamManifest(t *testing.T) {
|
||||
{
|
||||
name: "string",
|
||||
in: tools.NewStringParameter("foo-string", "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-string", Type: "string", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
want: tools.ParameterManifest{Name: "foo-string", Type: "string", Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "int",
|
||||
in: tools.NewIntParameter("foo-int", "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-int", Type: "integer", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
want: tools.ParameterManifest{Name: "foo-int", Type: "integer", Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "float",
|
||||
in: tools.NewFloatParameter("foo-float", "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-float", Type: "float", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
want: tools.ParameterManifest{Name: "foo-float", Type: "float", Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "boolean",
|
||||
in: tools.NewBooleanParameter("foo-bool", "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-bool", Type: "boolean", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
want: tools.ParameterManifest{Name: "foo-bool", Type: "boolean", Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "array",
|
||||
@@ -965,42 +831,9 @@ func TestParamManifest(t *testing.T) {
|
||||
want: tools.ParameterManifest{
|
||||
Name: "foo-array",
|
||||
Type: "array",
|
||||
Required: true,
|
||||
Description: "bar",
|
||||
AuthServices: []string{},
|
||||
Items: &tools.ParameterManifest{Name: "foo-string", Type: "string", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "string default",
|
||||
in: tools.NewStringParameterWithDefault("foo-string", "foo", "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-string", Type: "string", Required: false, Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "int default",
|
||||
in: tools.NewIntParameterWithDefault("foo-int", 1, "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-int", Type: "integer", Required: false, Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "float default",
|
||||
in: tools.NewFloatParameterWithDefault("foo-float", 1.1, "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-float", Type: "float", Required: false, Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "boolean default",
|
||||
in: tools.NewBooleanParameterWithDefault("foo-bool", true, "bar"),
|
||||
want: tools.ParameterManifest{Name: "foo-bool", Type: "boolean", Required: false, Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
{
|
||||
name: "array default",
|
||||
in: tools.NewArrayParameterWithDefault("foo-array", `["foo", "bar"]`, "bar", tools.NewStringParameter("foo-string", "bar")),
|
||||
want: tools.ParameterManifest{
|
||||
Name: "foo-array",
|
||||
Type: "array",
|
||||
Required: false,
|
||||
Description: "bar",
|
||||
AuthServices: []string{},
|
||||
Items: &tools.ParameterManifest{Name: "foo-string", Type: "string", Required: true, Description: "bar", AuthServices: []string{}},
|
||||
Items: &tools.ParameterManifest{Name: "foo-string", Type: "string", Description: "bar", AuthServices: []string{}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1060,54 +893,6 @@ func TestParamMcpManifest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMcpManifest(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
in tools.Parameters
|
||||
want tools.McpToolsSchema
|
||||
}{
|
||||
{
|
||||
name: "string",
|
||||
in: tools.Parameters{
|
||||
tools.NewStringParameterWithDefault("foo-string", "foo", "bar"),
|
||||
tools.NewStringParameter("foo-string2", "bar"),
|
||||
tools.NewIntParameterWithDefault("foo-int", 1, "bar"),
|
||||
tools.NewIntParameter("foo-int2", "bar"),
|
||||
tools.NewArrayParameterWithDefault("foo-array", []string{"hello", "world"}, "bar", tools.NewStringParameter("foo-string", "bar")),
|
||||
tools.NewArrayParameter("foo-array2", "bar", tools.NewStringParameter("foo-string", "bar")),
|
||||
},
|
||||
want: tools.McpToolsSchema{
|
||||
Type: "object",
|
||||
Properties: map[string]tools.ParameterMcpManifest{
|
||||
"foo-string": tools.ParameterMcpManifest{Type: "string", Description: "bar"},
|
||||
"foo-string2": tools.ParameterMcpManifest{Type: "string", Description: "bar"},
|
||||
"foo-int": tools.ParameterMcpManifest{Type: "integer", Description: "bar"},
|
||||
"foo-int2": tools.ParameterMcpManifest{Type: "integer", Description: "bar"},
|
||||
"foo-array": tools.ParameterMcpManifest{
|
||||
Type: "array",
|
||||
Description: "bar",
|
||||
Items: &tools.ParameterMcpManifest{Type: "string", Description: "bar"},
|
||||
},
|
||||
"foo-array2": tools.ParameterMcpManifest{
|
||||
Type: "array",
|
||||
Description: "bar",
|
||||
Items: &tools.ParameterMcpManifest{Type: "string", Description: "bar"},
|
||||
},
|
||||
},
|
||||
Required: []string{"foo-string2", "foo-int2", "foo-array2"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := tc.in.McpManifest()
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Fatalf("unexpected manifest: got %+v, want %+v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailParametersUnmarshal(t *testing.T) {
|
||||
ctx, err := testutils.ContextWithNewLogger()
|
||||
if err != nil {
|
||||
|
||||
@@ -118,7 +118,6 @@ func runAiNlToolGetTest(t *testing.T) {
|
||||
map[string]any{
|
||||
"name": "question",
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "The natural language question to ask.",
|
||||
"authSources": []any{},
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestAlloyDBPgToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, ALLOYDB_POSTGRES_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddPgExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetPostgresSQLTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, ALLOYDB_POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, ALLOYDB_POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -166,11 +166,11 @@ func TestAlloyDBPgToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetPostgresWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
// Test connection with different IP type
|
||||
|
||||
@@ -94,12 +94,6 @@ func TestBigQueryToolEndpoints(t *testing.T) {
|
||||
datasetName,
|
||||
strings.ReplaceAll(uuid.New().String(), "-", ""),
|
||||
)
|
||||
tableNameTemplateParam := fmt.Sprintf("`%s.%s.template_param_table_%s`",
|
||||
BIGQUERY_PROJECT,
|
||||
datasetName,
|
||||
strings.ReplaceAll(uuid.New().String(), "-", ""),
|
||||
)
|
||||
|
||||
// set up data for param tool
|
||||
create_statement1, insert_statement1, tool_statement1, params1 := getBigQueryParamToolInfo(tableNameParam)
|
||||
teardownTable1 := setupBigQueryTable(t, ctx, client, create_statement1, insert_statement1, datasetName, tableNameParam, params1)
|
||||
@@ -113,8 +107,6 @@ func TestBigQueryToolEndpoints(t *testing.T) {
|
||||
// Write config into a file and pass it to command
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, BIGQUERY_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = addBigQueryPrebuiltToolsConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := getBigQueryTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, BIGQUERY_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -137,14 +129,9 @@ func TestBigQueryToolEndpoints(t *testing.T) {
|
||||
failInvocationWant := `{"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to execute query: googleapi: Error 400: Syntax error: Unexpected identifier \"SELEC\" at [1:1]`
|
||||
datasetInfoWant := "\"Location\":\"US\",\"DefaultTableExpiration\":0,\"Labels\":null,\"Access\":"
|
||||
tableInfoWant := "[{\"Name\":\"\",\"Location\":\"US\",\"Description\":\"\",\"Schema\":[{\"Name\":\"id\""
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, _, _ := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
templateParamTestConfig := tests.NewTemplateParameterTestConfig(
|
||||
tests.WithCreateColArray(`["id INT64", "name STRING", "age INT64"]`),
|
||||
)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, templateParamTestConfig)
|
||||
|
||||
runBigQueryExecuteSqlToolInvokeTest(t, select1Want, invokeParamWant, tableNameParam)
|
||||
runBigQueryListDatasetToolInvokeTest(t, datasetName)
|
||||
runBigQueryGetDatasetInfoToolInvokeTest(t, datasetName, datasetInfoWant)
|
||||
@@ -182,13 +169,6 @@ func getBigQueryAuthToolInfo(tableName string) (string, string, string, []bigque
|
||||
return createStatement, insertStatement, toolStatement, params
|
||||
}
|
||||
|
||||
// getBigQueryTmplToolStatement returns statements for template parameter test cases for bigquery kind
|
||||
func getBigQueryTmplToolStatement() (string, string) {
|
||||
tmplSelectCombined := "SELECT * FROM {{.tableName}} WHERE id = ? ORDER BY id"
|
||||
tmplSelectFilterCombined := "SELECT * FROM {{.tableName}} WHERE {{.columnFilter}} = ? ORDER BY id"
|
||||
return tmplSelectCombined, tmplSelectFilterCombined
|
||||
}
|
||||
|
||||
func setupBigQueryTable(t *testing.T, ctx context.Context, client *bigqueryapi.Client, create_statement, insert_statement, datasetName string, tableName string, params []bigqueryapi.QueryParameter) func(*testing.T) {
|
||||
// Create dataset
|
||||
dataset := client.Dataset(datasetName)
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
|
||||
"cloud.google.com/go/bigtable"
|
||||
"github.com/google/uuid"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||
"github.com/googleapis/genai-toolbox/tests"
|
||||
)
|
||||
|
||||
@@ -70,7 +69,6 @@ func TestBigtableToolEndpoints(t *testing.T) {
|
||||
|
||||
tableName := "param_table" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
tableNameAuth := "auth_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
tableNameTemplateParam := "tmpl_param_table_" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
|
||||
columnFamilyName := "cf"
|
||||
muts, rowKeys := getTestData(columnFamilyName)
|
||||
@@ -87,14 +85,8 @@ func TestBigtableToolEndpoints(t *testing.T) {
|
||||
teardownTable2 := setupBtTable(t, ctx, sourceConfig["project"].(string), sourceConfig["instance"].(string), tableNameAuth, columnFamilyName, muts, rowKeys)
|
||||
defer teardownTable2(t)
|
||||
|
||||
mutsTmpl, rowKeysTmpl := getTestDataTemplateParam(columnFamilyName)
|
||||
teardownTableTmpl := setupBtTable(t, ctx, sourceConfig["project"].(string), sourceConfig["instance"].(string), tableNameTemplateParam, columnFamilyName, mutsTmpl, rowKeysTmpl)
|
||||
defer teardownTableTmpl(t)
|
||||
|
||||
// Write config into a file and pass it to command
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, BIGTABLE_TOOL_KIND, param_test_statement, auth_tool_statement)
|
||||
toolsFile = addTemplateParamConfig(t, toolsFile)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
t.Fatalf("command initialization returned an error: %s", err)
|
||||
@@ -114,25 +106,9 @@ func TestBigtableToolEndpoints(t *testing.T) {
|
||||
// Actual test parameters are set in https://github.com/googleapis/genai-toolbox/blob/52b09a67cb40ac0c5f461598b4673136699a3089/tests/tool_test.go#L250
|
||||
select1Want := "[{\"$col1\":1}]"
|
||||
failInvocationWant := `{"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to prepare statement: rpc error: code = InvalidArgument desc = Syntax error: Unexpected identifier \"SELEC\" [at 1:1]"}],"isError":true}}`
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, _, _ := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
|
||||
templateParamTestConfig := tests.NewTemplateParameterTestConfig(
|
||||
tests.WithIgnoreDdl(),
|
||||
tests.WithIgnoreInsert(),
|
||||
tests.WithReplaceNameFieldArray(`["CAST(cf['name'] AS string) as name"]`),
|
||||
tests.WithReplaceNameColFilter("CAST(cf['name'] AS string)"),
|
||||
)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, templateParamTestConfig)
|
||||
}
|
||||
|
||||
func convertToBytes(v int) []byte {
|
||||
binary1 := new(bytes.Buffer)
|
||||
if err := binary.Write(binary1, binary.BigEndian, int64(v)); err != nil {
|
||||
log.Fatalf("Unable to encode id: %v", err)
|
||||
}
|
||||
return binary1.Bytes()
|
||||
}
|
||||
|
||||
func getTestData(columnFamilyName string) ([]*bigtable.Mutation, []string) {
|
||||
@@ -141,7 +117,11 @@ func getTestData(columnFamilyName string) ([]*bigtable.Mutation, []string) {
|
||||
|
||||
var ids [3][]byte
|
||||
for i := range ids {
|
||||
ids[i] = convertToBytes(i + 1)
|
||||
binary1 := new(bytes.Buffer)
|
||||
if err := binary.Write(binary1, binary.BigEndian, int64(i+1)); err != nil {
|
||||
log.Fatalf("Unable to encode id: %v", err)
|
||||
}
|
||||
ids[i] = binary1.Bytes()
|
||||
}
|
||||
|
||||
now := bigtable.Time(time.Now())
|
||||
@@ -174,41 +154,6 @@ func getTestData(columnFamilyName string) ([]*bigtable.Mutation, []string) {
|
||||
return muts, rowKeys
|
||||
}
|
||||
|
||||
func getTestDataTemplateParam(columnFamilyName string) ([]*bigtable.Mutation, []string) {
|
||||
muts := []*bigtable.Mutation{}
|
||||
rowKeys := []string{}
|
||||
|
||||
var ids [2][]byte
|
||||
for i := range ids {
|
||||
ids[i] = convertToBytes(i + 1)
|
||||
}
|
||||
|
||||
now := bigtable.Time(time.Now())
|
||||
for rowKey, mutData := range map[string]map[string][]byte{
|
||||
// Do not change the test data without checking tests/common_test.go.
|
||||
// The structure and value of seed data has to match https://github.com/googleapis/genai-toolbox/blob/4dba0df12dc438eca3cb476ef52aa17cdf232c12/tests/common_test.go#L200-L251
|
||||
// Expected values are defined in https://github.com/googleapis/genai-toolbox/blob/52b09a67cb40ac0c5f461598b4673136699a3089/tests/tool_test.go#L229-L310
|
||||
"row-01": {
|
||||
"name": []byte("Alex"),
|
||||
"age": convertToBytes(21),
|
||||
"id": ids[0],
|
||||
},
|
||||
"row-02": {
|
||||
"name": []byte("Alice"),
|
||||
"age": convertToBytes(100),
|
||||
"id": ids[1],
|
||||
},
|
||||
} {
|
||||
mut := bigtable.NewMutation()
|
||||
for col, v := range mutData {
|
||||
mut.Set(columnFamilyName, col, now, v)
|
||||
}
|
||||
muts = append(muts, mut)
|
||||
rowKeys = append(rowKeys, rowKey)
|
||||
}
|
||||
return muts, rowKeys
|
||||
}
|
||||
|
||||
func setupBtTable(t *testing.T, ctx context.Context, projectId string, instance string, tableName string, columnFamilyName string, muts []*bigtable.Mutation, rowKeys []string) func(*testing.T) {
|
||||
// Creating clients
|
||||
adminClient, err := bigtable.NewAdminClient(ctx, projectId, instance)
|
||||
@@ -268,52 +213,3 @@ func setupBtTable(t *testing.T, ctx context.Context, projectId string, instance
|
||||
defer adminClient.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func addTemplateParamConfig(t *testing.T, config map[string]any) map[string]any {
|
||||
toolsMap, ok := config["tools"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("unable to get tools from config")
|
||||
}
|
||||
toolsMap["select-templateParams-tool"] = map[string]any{
|
||||
"kind": "bigtable-sql",
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": "SELECT TO_INT64(cf['age']) as age, TO_INT64(cf['id']) as id, CAST(cf['name'] AS string) as name, FROM {{.tableName}};",
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
},
|
||||
}
|
||||
toolsMap["select-templateParams-combined-tool"] = map[string]any{
|
||||
"kind": "bigtable-sql",
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": "SELECT TO_INT64(cf['age']) as age, TO_INT64(cf['id']) as id, CAST(cf['name'] AS string) as name, FROM {{.tableName}} WHERE TO_INT64(cf['id']) = @id;",
|
||||
"parameters": []tools.Parameter{tools.NewIntParameter("id", "the id of the user")},
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
},
|
||||
}
|
||||
toolsMap["select-fields-templateParams-tool"] = map[string]any{
|
||||
"kind": "bigtable-sql",
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": "SELECT {{array .fields}}, FROM {{.tableName}};",
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
tools.NewArrayParameter("fields", "The fields to select from", tools.NewStringParameter("field", "A field that will be returned from the query.")),
|
||||
},
|
||||
}
|
||||
toolsMap["select-filter-templateParams-combined-tool"] = map[string]any{
|
||||
"kind": "bigtable-sql",
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": "SELECT TO_INT64(cf['age']) as age, TO_INT64(cf['id']) as id, CAST(cf['name'] AS string) as name, FROM {{.tableName}} WHERE {{.columnFilter}} = @name;",
|
||||
"parameters": []tools.Parameter{tools.NewStringParameter("name", "the name of the user")},
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
tools.NewStringParameter("columnFilter", "some description"),
|
||||
},
|
||||
}
|
||||
config["tools"] = toolsMap
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
@@ -77,13 +76,7 @@ func getCloudSQLMssqlVars(t *testing.T) map[string]any {
|
||||
// Copied over from cloud_sql_mssql.go
|
||||
func initCloudSQLMssqlConnection(project, region, instance, ipAddress, ipType, user, pass, dbname string) (*sql.DB, error) {
|
||||
// Create dsn
|
||||
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,
|
||||
}
|
||||
dsn := fmt.Sprintf("sqlserver://%s:%s@%s?database=%s&cloudsql=%s:%s:%s", user, pass, ipAddress, dbname, project, region, instance)
|
||||
|
||||
// Get dial options
|
||||
dialOpts, err := tests.GetCloudSQLDialOpts(ipType)
|
||||
@@ -102,7 +95,7 @@ func initCloudSQLMssqlConnection(project, region, instance, ipAddress, ipType, u
|
||||
// Open database connection
|
||||
db, err := sql.Open(
|
||||
"cloudsql-sqlserver-driver",
|
||||
url.String(),
|
||||
dsn,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -141,7 +134,7 @@ func TestCloudSQLMssqlToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, CLOUD_SQL_MSSQL_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddMssqlExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetMssqlTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_MSSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_MSSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -160,11 +153,11 @@ func TestCloudSQLMssqlToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetMssqlWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
// Test connection with different IP type
|
||||
|
||||
@@ -128,7 +128,7 @@ func TestCloudSQLMysqlToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, CLOUD_SQL_MYSQL_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddMySqlExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetMysqlTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_MYSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_MYSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -147,11 +147,11 @@ func TestCloudSQLMysqlToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetMysqlWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
// Test connection with different IP type
|
||||
|
||||
@@ -132,7 +132,7 @@ func TestCloudSQLPgSimpleToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, CLOUD_SQL_POSTGRES_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddPgExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetPostgresSQLTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, CLOUD_SQL_POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -151,11 +151,11 @@ func TestCloudSQLPgSimpleToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetPostgresWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
// Test connection with different IP type
|
||||
|
||||
@@ -129,17 +129,11 @@ func AddPgExecuteSqlConfig(t *testing.T, config map[string]any) map[string]any {
|
||||
return config
|
||||
}
|
||||
|
||||
func AddTemplateParamConfig(t *testing.T, config map[string]any, toolKind, tmplSelectCombined, tmplSelectFilterCombined string, tmplSelectAll string) map[string]any {
|
||||
func AddTemplateParamConfig(t *testing.T, config map[string]any, toolKind, tmplSelectCombined, tmplSelectFilterCombined string) map[string]any {
|
||||
toolsMap, ok := config["tools"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("unable to get tools from config")
|
||||
}
|
||||
|
||||
selectAll := "SELECT * FROM {{.tableName}} ORDER BY id"
|
||||
if tmplSelectAll != "" {
|
||||
selectAll = tmplSelectAll
|
||||
}
|
||||
|
||||
toolsMap["create-table-templateParams-tool"] = map[string]any{
|
||||
"kind": toolKind,
|
||||
"source": "my-instance",
|
||||
@@ -165,7 +159,7 @@ func AddTemplateParamConfig(t *testing.T, config map[string]any, toolKind, tmplS
|
||||
"kind": toolKind,
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": selectAll,
|
||||
"statement": "SELECT * FROM {{.tableName}}",
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
},
|
||||
@@ -184,7 +178,7 @@ func AddTemplateParamConfig(t *testing.T, config map[string]any, toolKind, tmplS
|
||||
"kind": toolKind,
|
||||
"source": "my-instance",
|
||||
"description": "Create table tool with template parameters",
|
||||
"statement": "SELECT {{array .fields}} FROM {{.tableName}} ORDER BY id",
|
||||
"statement": "SELECT {{array .fields}} FROM {{.tableName}}",
|
||||
"templateParameters": []tools.Parameter{
|
||||
tools.NewStringParameter("tableName", "some description"),
|
||||
tools.NewArrayParameter("fields", "The fields to select from", tools.NewStringParameter("field", "A field that will be returned from the query.")),
|
||||
@@ -335,10 +329,12 @@ func GetMysqlTmplToolStatement() (string, string) {
|
||||
return tmplSelectCombined, tmplSelectFilterCombined
|
||||
}
|
||||
|
||||
func GetNonSpannerInvokeParamWant() (string, string) {
|
||||
func GetNonSpannerInvokeParamWant() (string, string, string, string) {
|
||||
invokeParamWant := "[{\"id\":1,\"name\":\"Alice\"},{\"id\":3,\"name\":\"Sid\"}]"
|
||||
mcpInvokeParamWant := `{"jsonrpc":"2.0","id":"my-param-tool","result":{"content":[{"type":"text","text":"{\"id\":1,\"name\":\"Alice\"}"},{"type":"text","text":"{\"id\":3,\"name\":\"Sid\"}"}]}}`
|
||||
return invokeParamWant, mcpInvokeParamWant
|
||||
tmplSelectAllWant := "[{\"age\":21,\"id\":1,\"name\":\"Alex\"},{\"age\":100,\"id\":2,\"name\":\"Alice\"}]"
|
||||
tmplSelect1Want := "[{\"age\":21,\"id\":1,\"name\":\"Alex\"}]"
|
||||
return invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want
|
||||
}
|
||||
|
||||
// GetPostgresWants return the expected wants for postgres
|
||||
|
||||
@@ -100,7 +100,6 @@ func TestCouchbaseToolEndpoints(t *testing.T) {
|
||||
// Create collection names with UUID
|
||||
collectionNameParam := "param_" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
collectionNameAuth := "auth_" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
collectionNameTemplateParam := "template_param_" + strings.ReplaceAll(uuid.New().String(), "-", "")
|
||||
|
||||
// Set up data for param tool
|
||||
paramToolStatement, params1 := getCouchbaseParamToolInfo(collectionNameParam)
|
||||
@@ -112,14 +111,8 @@ func TestCouchbaseToolEndpoints(t *testing.T) {
|
||||
teardownCollection2 := setupCouchbaseCollection(t, ctx, cluster, couchbaseBucket, couchbaseScope, collectionNameAuth, params2)
|
||||
defer teardownCollection2(t)
|
||||
|
||||
// Setup up table for template param tool
|
||||
tmplSelectCombined, tmplSelectFilterCombined, tmplSelectAll, params3 := getCouchbaseTemplateParamToolInfo()
|
||||
teardownCollection3 := setupCouchbaseCollection(t, ctx, cluster, couchbaseBucket, couchbaseScope, collectionNameTemplateParam, params3)
|
||||
defer teardownCollection3(t)
|
||||
|
||||
// Write config into a file and pass it to command
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, couchbaseToolKind, paramToolStatement, authToolStatement)
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, couchbaseToolKind, tmplSelectCombined, tmplSelectFilterCombined, tmplSelectAll)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -140,17 +133,9 @@ func TestCouchbaseToolEndpoints(t *testing.T) {
|
||||
select1Want := "[{\"$1\":1}]"
|
||||
failMcpInvocationWant := "{\"jsonrpc\":\"2.0\",\"id\":\"invoke-fail-tool\",\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"unable to execute query: parsing failure | {\\\"statement\\\":\\\"SELEC 1;\\\""
|
||||
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, _, _ := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failMcpInvocationWant)
|
||||
|
||||
templateParamTestConfig := tests.NewTemplateParameterTestConfig(
|
||||
tests.WithIgnoreDdl(),
|
||||
tests.WithIgnoreInsert(),
|
||||
tests.WithSelect1Want("[{\"age\":21,\"id\":1,\"name\":\"Alex\"}]"),
|
||||
tests.WithSelectAllWant("[{\"age\":21,\"id\":1,\"name\":\"Alex\"},{\"age\":100,\"id\":2,\"name\":\"Alice\"}]"),
|
||||
)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, collectionNameTemplateParam, templateParamTestConfig)
|
||||
}
|
||||
|
||||
// setupCouchbaseCollection creates a scope and collection and inserts test data
|
||||
@@ -255,15 +240,3 @@ func getCouchbaseAuthToolInfo(collectionName string) (string, []map[string]any)
|
||||
}
|
||||
return toolStatement, params
|
||||
}
|
||||
|
||||
func getCouchbaseTemplateParamToolInfo() (string, string, string, []map[string]any) {
|
||||
tmplSelectCombined := "SELECT {{.tableName}}.* FROM {{.tableName}} WHERE id = $id"
|
||||
tmplSelectFilterCombined := "SELECT {{.tableName}}.* FROM {{.tableName}} WHERE {{.columnFilter}} = $name"
|
||||
tmplSelectAll := "SELECT {{.tableName}}.* FROM {{.tableName}}"
|
||||
|
||||
params := []map[string]any{
|
||||
{"name": "Alex", "id": 1, "age": 21},
|
||||
{"name": "Alice", "id": 2, "age": 100},
|
||||
}
|
||||
return tmplSelectCombined, tmplSelectFilterCombined, tmplSelectAll, params
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ func TestHttpToolEndpoints(t *testing.T) {
|
||||
}
|
||||
|
||||
select1Want := `["Hello","World"]`
|
||||
invokeParamWant, _ := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, _, _, _ := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolGetTest(t)
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
runAdvancedHTTPInvokeTest(t)
|
||||
@@ -282,7 +282,7 @@ func runAdvancedHTTPInvokeTest(t *testing.T) {
|
||||
name: "invoke my-advanced-tool",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-advanced-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 3, "path": "tool3", "country": "US", "X-Other-Header": "test"}`)),
|
||||
requestBody: bytes.NewBuffer([]byte(`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 3, "country": "US", "X-Other-Header": "test"}`)),
|
||||
want: `["Hello","World"]`,
|
||||
isErr: false,
|
||||
},
|
||||
@@ -290,7 +290,7 @@ func runAdvancedHTTPInvokeTest(t *testing.T) {
|
||||
name: "invoke my-advanced-tool with wrong params",
|
||||
api: "http://127.0.0.1:5000/api/tool/my-advanced-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 4, "path": "tool3", "country": "US", "X-Other-Header": "test"}`)),
|
||||
requestBody: bytes.NewBuffer([]byte(`{"animalArray": ["rabbit", "ostrich", "whale"], "id": 4, "country": "US", "X-Other-Header": "test"}`)),
|
||||
isErr: true,
|
||||
},
|
||||
}
|
||||
@@ -408,16 +408,11 @@ func getHTTPToolsConfig(sourceConfig map[string]any, toolKind string) map[string
|
||||
"kind": toolKind,
|
||||
"source": "other-instance",
|
||||
"method": "get",
|
||||
"path": "/{{.path}}?id=2",
|
||||
"path": "/tool3?id=2",
|
||||
"description": "some description",
|
||||
"headers": map[string]string{
|
||||
"X-Custom-Header": "example",
|
||||
},
|
||||
"pathParams": []tools.Parameter{
|
||||
&tools.StringParameter{
|
||||
CommonParameter: tools.CommonParameter{Name: "path", Type: "string", Desc: "path param"},
|
||||
},
|
||||
},
|
||||
"queryParams": []tools.Parameter{
|
||||
tools.NewIntParameter("id", "user ID"), tools.NewStringParameter("country", "country")},
|
||||
"requestBody": `{
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -66,17 +65,10 @@ func getMsSQLVars(t *testing.T) map[string]any {
|
||||
// Copied over from mssql.go
|
||||
func initMssqlConnection(host, port, user, pass, dbname string) (*sql.DB, error) {
|
||||
// Create dsn
|
||||
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(),
|
||||
}
|
||||
dsn := fmt.Sprintf("sqlserver://%s:%s@%s:%s?database=%s", user, pass, host, port, dbname)
|
||||
|
||||
// Open database connection
|
||||
db, err := sql.Open("sqlserver", url.String())
|
||||
db, err := sql.Open("sqlserver", dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sql.Open: %w", err)
|
||||
}
|
||||
@@ -114,7 +106,7 @@ func TestMssqlToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, MSSQL_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddMssqlExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetMssqlTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, MSSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, MSSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -133,9 +125,9 @@ func TestMssqlToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetMssqlWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestMysqlToolEndpoints(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, MYSQL_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddMySqlExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetMysqlTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, MYSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, MYSQL_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -124,9 +124,9 @@ func TestMysqlToolEndpoints(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetMysqlWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package postgres
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -66,13 +65,8 @@ func getPostgresVars(t *testing.T) map[string]any {
|
||||
// Copied over from postgres.go
|
||||
func initPostgresConnectionPool(host, port, user, pass, dbname string) (*pgxpool.Pool, error) {
|
||||
// urlExample := "postgres:dd//username:password@localhost:5432/database_name"
|
||||
url := &url.URL{
|
||||
Scheme: "postgres",
|
||||
User: url.UserPassword(user, pass),
|
||||
Host: fmt.Sprintf("%s:%s", host, port),
|
||||
Path: dbname,
|
||||
}
|
||||
pool, err := pgxpool.New(context.Background(), url.String())
|
||||
i := fmt.Sprintf("postgres://%s:%s@%s:%s/%s", user, pass, host, port, dbname)
|
||||
pool, err := pgxpool.New(context.Background(), i)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to create connection pool: %w", err)
|
||||
}
|
||||
@@ -111,7 +105,7 @@ func TestPostgres(t *testing.T) {
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, POSTGRES_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
toolsFile = tests.AddPgExecuteSqlConfig(t, toolsFile)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := tests.GetPostgresSQLTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, POSTGRES_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -130,9 +124,9 @@ func TestPostgres(t *testing.T) {
|
||||
tests.RunToolGetTest(t)
|
||||
|
||||
select1Want, failInvocationWant, createTableStatement := tests.GetPostgresWants()
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunExecuteSqlToolInvokeTest(t, createTableStatement, select1Want)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
@@ -154,18 +154,14 @@ func TestSpannerToolEndpoints(t *testing.T) {
|
||||
invokeParamWant := "[{\"id\":\"1\",\"name\":\"Alice\"},{\"id\":\"3\",\"name\":\"Sid\"}]"
|
||||
mcpInvokeParamWant := `{"jsonrpc":"2.0","id":"my-param-tool","result":{"content":[{"type":"text","text":"{\"id\":\"1\",\"name\":\"Alice\"}"},{"type":"text","text":"{\"id\":\"3\",\"name\":\"Sid\"}"}]}}`
|
||||
failInvocationWant := `"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to execute client: unable to parse row: spanner: code = \"InvalidArgument\", desc = \"Syntax error: Unexpected identifier \\\\\\\"SELEC\\\\\\\" [at 1:1]\\\\nSELEC 1;\\\\n^\"`
|
||||
tmplSelectAllWant := "[{\"age\":\"21\",\"id\":\"1\",\"name\":\"Alex\"},{\"age\":\"100\",\"id\":\"2\",\"name\":\"Alice\"}]"
|
||||
tmplSelect1Want := "[{\"age\":\"21\",\"id\":\"1\",\"name\":\"Alex\"}]"
|
||||
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
runSpannerSchemaToolInvokeTest(t, accessSchemaWant)
|
||||
runSpannerExecuteSqlToolInvokeTest(t, select1Want, invokeParamWant, tableNameParam, tableNameAuth)
|
||||
|
||||
templateParamTestConfig := tests.NewTemplateParameterTestConfig(
|
||||
tests.WithIgnoreDdl(),
|
||||
tests.WithSelectAllWant("[{\"age\":\"21\",\"id\":\"1\",\"name\":\"Alex\"},{\"age\":\"100\",\"id\":\"2\",\"name\":\"Alice\"}]"),
|
||||
tests.WithSelect1Want("[{\"age\":\"21\",\"id\":\"1\",\"name\":\"Alex\"}]"),
|
||||
)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, templateParamTestConfig)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, true)
|
||||
}
|
||||
|
||||
// getSpannerToolInfo returns statements and param for my-param-tool for spanner-sql kind
|
||||
|
||||
@@ -133,7 +133,7 @@ func TestSQLiteToolEndpoint(t *testing.T) {
|
||||
// Write config into a file and pass it to command
|
||||
toolsFile := tests.GetToolsConfig(sourceConfig, SQLITE_TOOL_KIND, tool_statement1, tool_statement2)
|
||||
tmplSelectCombined, tmplSelectFilterCombined := getSQLiteTmplToolStatement()
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, SQLITE_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined, "")
|
||||
toolsFile = tests.AddTemplateParamConfig(t, toolsFile, SQLITE_TOOL_KIND, tmplSelectCombined, tmplSelectFilterCombined)
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
@@ -153,8 +153,8 @@ func TestSQLiteToolEndpoint(t *testing.T) {
|
||||
|
||||
select1Want := "[{\"1\":1}]"
|
||||
failInvocationWant := `{"jsonrpc":"2.0","id":"invoke-fail-tool","result":{"content":[{"type":"text","text":"unable to execute query: SQL logic error: near \"SELEC\": syntax error (1)"}],"isError":true}}`
|
||||
invokeParamWant, mcpInvokeParamWant := tests.GetNonSpannerInvokeParamWant()
|
||||
invokeParamWant, mcpInvokeParamWant, tmplSelectAllWant, tmplSelect1Want := tests.GetNonSpannerInvokeParamWant()
|
||||
tests.RunToolInvokeTest(t, select1Want, invokeParamWant)
|
||||
tests.RunMCPToolCallMethod(t, mcpInvokeParamWant, failInvocationWant)
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tests.NewTemplateParameterTestConfig())
|
||||
tests.RunToolInvokeWithTemplateParameters(t, tableNameTemplateParam, tmplSelectAllWant, tmplSelect1Want, false)
|
||||
}
|
||||
|
||||
111
tests/tool.go
111
tests/tool.go
@@ -211,97 +211,13 @@ func RunToolInvokeTest(t *testing.T, select1Want, invokeParamWant string) {
|
||||
}
|
||||
}
|
||||
|
||||
// TemplateParameterTestConfig represents the various configuration options for template parameter tests.
|
||||
type TemplateParameterTestConfig struct {
|
||||
ignoreDdl bool
|
||||
ignoreInsert bool
|
||||
selectAllWant string
|
||||
select1Want string
|
||||
nameFieldArray string
|
||||
nameColFilter string
|
||||
createColArray string
|
||||
}
|
||||
|
||||
type Option func(*TemplateParameterTestConfig)
|
||||
|
||||
// WithIgnoreDdl is the option function to configure ignoreDdl.
|
||||
func WithIgnoreDdl() Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.ignoreDdl = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithIgnoreInsert is the option function to configure ignoreInsert.
|
||||
func WithIgnoreInsert() Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.ignoreInsert = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithSelectAllWant is the option function to configure selectAllWant.
|
||||
func WithSelectAllWant(s string) Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.selectAllWant = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithSelect1Want is the option function to configure select1Want.
|
||||
func WithSelect1Want(s string) Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.select1Want = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithReplaceNameFieldArray is the option function to configure replaceNameFieldArray.
|
||||
func WithReplaceNameFieldArray(s string) Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.nameFieldArray = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithReplaceNameColFilter is the option function to configure replaceNameColFilter.
|
||||
func WithReplaceNameColFilter(s string) Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.nameColFilter = s
|
||||
}
|
||||
}
|
||||
|
||||
// WithCreateColArray is the option function to configure replaceNameColFilter.
|
||||
func WithCreateColArray(s string) Option {
|
||||
return func(c *TemplateParameterTestConfig) {
|
||||
c.createColArray = s
|
||||
}
|
||||
}
|
||||
|
||||
// NewTemplateParameterTestConfig creates a new TemplateParameterTestConfig instances with options.
|
||||
func NewTemplateParameterTestConfig(options ...Option) *TemplateParameterTestConfig {
|
||||
templateParamTestOption := &TemplateParameterTestConfig{
|
||||
ignoreDdl: false,
|
||||
ignoreInsert: false,
|
||||
selectAllWant: "[{\"age\":21,\"id\":1,\"name\":\"Alex\"},{\"age\":100,\"id\":2,\"name\":\"Alice\"}]",
|
||||
select1Want: "[{\"age\":21,\"id\":1,\"name\":\"Alex\"}]",
|
||||
nameFieldArray: `["name"]`,
|
||||
nameColFilter: "name",
|
||||
createColArray: `["id INT","name VARCHAR(20)","age INT"]`,
|
||||
}
|
||||
|
||||
// Apply provided options
|
||||
for _, option := range options {
|
||||
option(templateParamTestOption)
|
||||
}
|
||||
|
||||
return templateParamTestOption
|
||||
}
|
||||
|
||||
// RunToolInvokeWithTemplateParameters runs tool invoke test cases with template parameters.
|
||||
func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config *TemplateParameterTestConfig) {
|
||||
selectOnlyNamesWant := "[{\"name\":\"Alex\"},{\"name\":\"Alice\"}]"
|
||||
func RunToolInvokeWithTemplateParameters(t *testing.T, tableName, select_all_want, select_only_1_want string, ignoreDdl bool) {
|
||||
select_only_names_want := "[{\"name\":\"Alex\"},{\"name\":\"Alice\"}]"
|
||||
|
||||
// Test tool invoke endpoint
|
||||
invokeTcs := []struct {
|
||||
name string
|
||||
ddl bool
|
||||
insert bool
|
||||
api string
|
||||
requestHeader map[string]string
|
||||
requestBody io.Reader
|
||||
@@ -313,13 +229,12 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
ddl: true,
|
||||
api: "http://127.0.0.1:5000/api/tool/create-table-templateParams-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "columns":%s}`, tableName, config.createColArray))),
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "columns":["id INT","name VARCHAR(20)","age INT"]}`, tableName))),
|
||||
want: "null",
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
name: "invoke insert-table-templateParams-tool",
|
||||
insert: true,
|
||||
api: "http://127.0.0.1:5000/api/tool/insert-table-templateParams-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "columns":["id","name","age"], "values":"1, 'Alex', 21"}`, tableName))),
|
||||
@@ -328,7 +243,6 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
},
|
||||
{
|
||||
name: "invoke insert-table-templateParams-tool",
|
||||
insert: true,
|
||||
api: "http://127.0.0.1:5000/api/tool/insert-table-templateParams-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "columns":["id","name","age"], "values":"2, 'Alice', 100"}`, tableName))),
|
||||
@@ -340,7 +254,7 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
api: "http://127.0.0.1:5000/api/tool/select-templateParams-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s"}`, tableName))),
|
||||
want: config.selectAllWant,
|
||||
want: select_all_want,
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
@@ -348,23 +262,23 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
api: "http://127.0.0.1:5000/api/tool/select-templateParams-combined-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"id": 1, "tableName": "%s"}`, tableName))),
|
||||
want: config.select1Want,
|
||||
want: select_only_1_want,
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
name: "invoke select-fields-templateParams-tool",
|
||||
api: "http://127.0.0.1:5000/api/tool/select-fields-templateParams-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "fields":%s}`, tableName, config.nameFieldArray))),
|
||||
want: selectOnlyNamesWant,
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"tableName": "%s", "fields":["name"]}`, tableName))),
|
||||
want: select_only_names_want,
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
name: "invoke select-filter-templateParams-combined-tool",
|
||||
api: "http://127.0.0.1:5000/api/tool/select-filter-templateParams-combined-tool/invoke",
|
||||
requestHeader: map[string]string{},
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"name": "Alex", "tableName": "%s", "columnFilter": "%s"}`, tableName, config.nameColFilter))),
|
||||
want: config.select1Want,
|
||||
requestBody: bytes.NewBuffer([]byte(fmt.Sprintf(`{"name": "Alex", "tableName": "%s", "columnFilter": "name"}`, tableName))),
|
||||
want: select_only_1_want,
|
||||
isErr: false,
|
||||
},
|
||||
{
|
||||
@@ -379,11 +293,7 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
}
|
||||
for _, tc := range invokeTcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// if test case is DDL and source does not ignore ddl test cases
|
||||
ddlAllow := !tc.ddl || (tc.ddl && !config.ignoreDdl)
|
||||
// if test case is insert statement and source does not ignore insert test cases
|
||||
insertAllow := !tc.insert || (tc.insert && !config.ignoreInsert)
|
||||
if ddlAllow && insertAllow {
|
||||
if !tc.ddl || (tc.ddl && !ignoreDdl) {
|
||||
// Send Tool invocation request
|
||||
req, err := http.NewRequest(http.MethodPost, tc.api, tc.requestBody)
|
||||
if err != nil {
|
||||
@@ -393,7 +303,6 @@ func RunToolInvokeWithTemplateParameters(t *testing.T, tableName string, config
|
||||
for k, v := range tc.requestHeader {
|
||||
req.Header.Add(k, v)
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to send request: %s", err)
|
||||
|
||||
Reference in New Issue
Block a user