Compare commits

..

3 Commits

Author SHA1 Message Date
duwenxin
b482dbf8e0 docs: add temporary warning on ADC connection to Cloud Run issue 2026-01-09 17:41:46 -05:00
Shobhit Singh
4abf0c39e7 feat(bigquery): make maximum rows returned from queries configurable (#2262)
This change allows the agent developer to control the maxium number of
rows returned from tools running BigQuery SQL query. Using this feature
the agent developer could limit how large output is presented to LLM in
an agentic user journey.

## Description

> Should include a concise description of the changes (bug or feature),
it's
> impact, along with a summary of the solution

## PR Checklist

> Thank you for opening a Pull Request! Before submitting your PR, there
are a
> few things you can do to make sure it goes smoothly:

- [x] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [ ] Make sure to open an issue
https://github.com/googleapis/genai-toolbox/issues/2261
  before writing your code! That way we can discuss the change, evaluate
  designs, and agree on the general idea
- [x] Ensure the tests and linter pass
- [x] Code coverage does not decrease (if any source code was changed)
- [x] Appropriate docs were updated (if necessary)
- [ ] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #2261 2261
2026-01-09 20:43:46 +00:00
Yuan Teoh
dd7b9de623 docs: add issue and pr triaging and SLO (#2257)
## Description

update docs to reflect triaging workflow and SLO

## PR Checklist

> Thank you for opening a Pull Request! Before submitting your PR, there
are a
> few things you can do to make sure it goes smoothly:

- [x] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [x] Make sure to open an issue as a

[bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose)
  before writing your code! That way we can discuss the change, evaluate
  designs, and agree on the general idea
- [x] Ensure the tests and linter pass
- [x] Code coverage does not decrease (if any source code was changed)
- [x] Appropriate docs were updated (if necessary)
- [x] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #<issue_number_goes_here>
2026-01-09 19:21:41 +00:00
36 changed files with 110 additions and 894 deletions

View File

@@ -379,6 +379,23 @@ to approve PRs for main. TeamSync is used to create this team from the MDB
Group `toolbox-contributors`. Googlers who are developing for MCP-Toolbox
but aren't part of the core team should join this group.
### Issue/PR Triage and SLO
After an issue is created, maintainers will assign the following labels:
* `Priority` (defaulted to P0)
* `Type` (if applicable)
* `Product` (if applicable)
All incoming issues and PRs will follow the following SLO:
| Type | Priority | Objective |
|-----------------|----------|------------------------------------------------------------------------|
| Feature Request | P0 | Must respond within **5 days** |
| Process | P0 | Must respond within **5 days** |
| Bugs | P0 | Must respond within **5 days**, and resolve/closure within **14 days** |
| Bugs | P1 | Must respond within **7 days**, and resolve/closure within **90 days** |
| Bugs | P2 | Must respond within **30 days**
_Types that are not listed in the table do not adhere to any SLO._
### Releasing
Toolbox has two types of releases: versioned and continuous. It uses Google

View File

@@ -101,6 +101,9 @@ authentication token.
TOOLBOX_URL = "https://your-toolbox-service-xyz.a.run.app"
# Initialize the client with the Cloud Run URL and Auth headers
# WARNING: There is a known issue that may cause it to fail with a 401 error
# on local machines.
# See https://github.com/googleapis/mcp-toolbox-sdk-python/issues/496
client = ToolboxSyncClient(
TOOLBOX_URL,
client_headers={"Authorization": auth_methods.get_google_id_token(TOOLBOX_URL)}

View File

@@ -211,6 +211,9 @@ from toolbox_core import ToolboxClient, auth_methods
# Replace with the Cloud Run service URL generated in the previous step
URL = "https://cloud-run-url.app"
# WARNING: There is a known issue that may cause it to fail with a 401 error
# on local machines.
# See https://github.com/googleapis/mcp-toolbox-sdk-python/issues/496
auth_token_provider = auth_methods.aget_google_id_token(URL) # can also use sync method
async def main():

View File

@@ -134,6 +134,7 @@ sources:
# scopes: # Optional: List of OAuth scopes to request.
# - "https://www.googleapis.com/auth/bigquery"
# - "https://www.googleapis.com/auth/drive.readonly"
# maxQueryResultRows: 50 # Optional: Limits the number of rows returned by queries. Defaults to 50.
```
Initialize a BigQuery source that uses the client's access token:
@@ -153,6 +154,7 @@ sources:
# scopes: # Optional: List of OAuth scopes to request.
# - "https://www.googleapis.com/auth/bigquery"
# - "https://www.googleapis.com/auth/drive.readonly"
# maxQueryResultRows: 50 # Optional: Limits the number of rows returned by queries. Defaults to 50.
```
## Reference
@@ -167,3 +169,4 @@ sources:
| useClientOAuth | bool | false | If true, forwards the client's OAuth access token from the "Authorization" header to downstream queries. **Note:** This cannot be used with `writeMode: protected`. |
| scopes | []string | false | A list of OAuth 2.0 scopes to use for the credentials. If not provided, default scopes are used. |
| impersonateServiceAccount | string | false | Service account email to impersonate when making BigQuery and Dataplex API calls. The authenticated principal must have the `roles/iam.serviceAccountTokenCreator` role on the target service account. [Learn More](https://cloud.google.com/iam/docs/service-account-impersonation) |
| maxQueryResultRows | int | false | The maximum number of rows to return from a query. Defaults to 50. |

View File

@@ -19,6 +19,7 @@ sources:
location: ${BIGQUERY_LOCATION:}
useClientOAuth: ${BIGQUERY_USE_CLIENT_OAUTH:false}
scopes: ${BIGQUERY_SCOPES:}
maxQueryResultRows: ${BIGQUERY_MAX_QUERY_RESULT_ROWS:50}
tools:
analyze_contribution:

View File

@@ -89,6 +89,7 @@ type Config struct {
UseClientOAuth bool `yaml:"useClientOAuth"`
ImpersonateServiceAccount string `yaml:"impersonateServiceAccount"`
Scopes StringOrStringSlice `yaml:"scopes"`
MaxQueryResultRows int `yaml:"maxQueryResultRows"`
}
// StringOrStringSlice is a custom type that can unmarshal both a single string
@@ -127,6 +128,10 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
r.WriteMode = WriteModeAllowed
}
if r.MaxQueryResultRows == 0 {
r.MaxQueryResultRows = 50
}
if r.WriteMode == WriteModeProtected && r.UseClientOAuth {
// The protected mode only allows write operations to the session's temporary datasets.
// when using client OAuth, a new session is created every
@@ -150,7 +155,7 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
Client: client,
RestService: restService,
TokenSource: tokenSource,
MaxQueryResultRows: 50,
MaxQueryResultRows: r.MaxQueryResultRows,
ClientCreator: clientCreator,
}
@@ -567,7 +572,7 @@ func (s *Source) RunSQL(ctx context.Context, bqClient *bigqueryapi.Client, state
}
var out []any
for {
for s.MaxQueryResultRows <= 0 || len(out) < s.MaxQueryResultRows {
var val []bigqueryapi.Value
err = it.Next(&val)
if err == iterator.Done {

View File

@@ -21,9 +21,12 @@ import (
yaml "github.com/goccy/go-yaml"
"github.com/google/go-cmp/cmp"
"go.opentelemetry.io/otel/trace/noop"
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/sources/bigquery"
"github.com/googleapis/genai-toolbox/internal/testutils"
"github.com/googleapis/genai-toolbox/internal/util"
)
func TestParseFromYamlBigQuery(t *testing.T) {
@@ -154,6 +157,26 @@ func TestParseFromYamlBigQuery(t *testing.T) {
},
},
},
{
desc: "with max query result rows example",
in: `
sources:
my-instance:
kind: bigquery
project: my-project
location: us
maxQueryResultRows: 10
`,
want: server.SourceConfigs{
"my-instance": bigquery.Config{
Name: "my-instance",
Kind: bigquery.SourceKind,
Project: "my-project",
Location: "us",
MaxQueryResultRows: 10,
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
@@ -220,6 +243,59 @@ func TestFailParseFromYaml(t *testing.T) {
}
}
func TestInitialize_MaxQueryResultRows(t *testing.T) {
ctx, err := testutils.ContextWithNewLogger()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
ctx = util.WithUserAgent(ctx, "test-agent")
tracer := noop.NewTracerProvider().Tracer("")
tcs := []struct {
desc string
cfg bigquery.Config
want int
}{
{
desc: "default value",
cfg: bigquery.Config{
Name: "test-default",
Kind: bigquery.SourceKind,
Project: "test-project",
UseClientOAuth: true,
},
want: 50,
},
{
desc: "configured value",
cfg: bigquery.Config{
Name: "test-configured",
Kind: bigquery.SourceKind,
Project: "test-project",
UseClientOAuth: true,
MaxQueryResultRows: 100,
},
want: 100,
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
src, err := tc.cfg.Initialize(ctx, tracer)
if err != nil {
t.Fatalf("Initialize failed: %v", err)
}
bqSrc, ok := src.(*bigquery.Source)
if !ok {
t.Fatalf("Expected *bigquery.Source, got %T", src)
}
if bqSrc.MaxQueryResultRows != tc.want {
t.Errorf("MaxQueryResultRows = %d, want %d", bqSrc.MaxQueryResultRows, tc.want)
}
})
}
}
func TestNormalizeValue(t *testing.T) {
tests := []struct {
name string

View File

@@ -1,15 +0,0 @@
cd server-darwin-arm64
npm pack .
npm publish --access public
cd ../server-darwin-x64
npm pack .
npm publish --access public
cd ../server-linux-x64
npm pack .
npm publish --access public
cd ../server-win32-x64
npm pack .
npm publish --access public

View File

@@ -1,6 +0,0 @@
# @toolbox-sdk/server-darwin-arm64
Platform-specific binary for the `toolbox` package on Darwin arm64.
This package is automatically installed by the main `@toolbox-sdk/server` package and is not intended to be installed directly.
For more information, visit the [toolbox npm package](https://www.npmjs.com/package/@toolbox-sdk/server).

View File

@@ -1,19 +0,0 @@
{
"name": "@toolbox-sdk/server-darwin-arm64",
"version": "0.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@toolbox-sdk/server-darwin-arm64",
"version": "0.25.0",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"os": [
"darwin"
]
}
}
}

View File

@@ -1,20 +0,0 @@
{
"name": "@toolbox-sdk/server-darwin-arm64",
"version": "0.25.0",
"license": "Apache-2.0",
"author": "Google LLC",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"main": "bin/toolbox",
"repository": "googleapis/genai-toolbox",
"scripts": {
"prepack": "node scripts/downloadBinary.js darwin arm64"
},
"files": [
"bin/toolbox"
]
}

View File

@@ -1,85 +0,0 @@
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
// 1. Configuration
const PLATFORM_MAP = {
'linux': 'linux',
'darwin': 'darwin',
'win32': 'windows'
};
const ARCH_MAP = {
'x64': 'amd64',
'arm64': 'arm64'
};
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node download-binary.js <platform> <arch>");
process.exit(1);
}
const [targetPlatform, targetArch] = args;
// 2. Determine Version
const version = fs.readFileSync(path.join(process.cwd(), 'version.txt'), 'utf8').trim();
// 3. Construct URL
const gcsPlatform = PLATFORM_MAP[targetPlatform];
const gcsArch = ARCH_MAP[targetArch];
if (!gcsPlatform || !gcsArch) {
console.error(`Unsupported platform/arch: ${targetPlatform}/${targetArch}`);
process.exit(1);
}
const extension = targetPlatform === 'win32' ? '.exe' : '';
const binaryName = `toolbox${extension}`;
const url = `https://storage.googleapis.com/genai-toolbox/v${version}/${gcsPlatform}/${gcsArch}/${binaryName}`;
// 4. Prepare Output
const binDir = path.join(process.cwd(), 'bin');
if (!fs.existsSync(binDir)) {
fs.mkdirSync(binDir, { recursive: true });
}
const destPath = path.join(binDir, binaryName);
if (fs.existsSync(destPath)) {
console.log(`[Skipped] Binary already exists at ${destPath}`);
process.exit(0);
}
console.log(`[Prepack] Downloading ${binaryName} for ${targetPlatform}/${targetArch}...`);
console.log(`[Source] ${url}`);
// 5. Download Function
const file = fs.createWriteStream(destPath);
https.get(url, function(response) {
if (response.statusCode !== 200) {
console.error(`❌ Failed to download. Status Code: ${response.statusCode}`);
fs.unlink(destPath, () => {}); // Delete partial file
process.exit(1);
}
response.pipe(file);
file.on('finish', () => {
file.close(() => {
// 6. Make executable (Unix only)
if (targetPlatform !== 'win32') {
try {
execSync(`chmod +x "${destPath}"`);
} catch (err) {
console.warn("⚠️ Could not set executable permissions (chmod failed).");
}
}
console.log(`✅ Success! Binary saved to ${destPath}`);
});
});
}).on('error', function(err) {
fs.unlink(destPath, () => {});
console.error(`❌ Download Error: ${err.message}`);
process.exit(1);
});

View File

@@ -1 +0,0 @@
0.25.0

View File

@@ -1,6 +0,0 @@
# @toolbox-sdk/server-darwin-x64
Platform-specific binary for the `toolbox` package on Darwin x64.
This package is automatically installed by the main `@toolbox-sdk/server` package and is not intended to be installed directly.
For more information, visit the [toolbox npm package](https://www.npmjs.com/package/@toolbox-sdk/server).

View File

@@ -1,19 +0,0 @@
{
"name": "@toolbox-sdk/server-darwin-x64",
"version": "0.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@toolbox-sdk/server-darwin-x64",
"version": "0.25.0",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"os": [
"darwin"
]
}
}
}

View File

@@ -1,20 +0,0 @@
{
"name": "@toolbox-sdk/server-darwin-x64",
"version": "0.25.0",
"license": "Apache-2.0",
"author": "Google LLC",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"main": "bin/toolbox",
"repository": "googleapis/genai-toolbox",
"scripts": {
"prepack": "node scripts/downloadBinary.js darwin x64"
},
"files": [
"bin/toolbox"
]
}

View File

@@ -1,85 +0,0 @@
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
// 1. Configuration
const PLATFORM_MAP = {
'linux': 'linux',
'darwin': 'darwin',
'win32': 'windows'
};
const ARCH_MAP = {
'x64': 'amd64',
'arm64': 'arm64'
};
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node download-binary.js <platform> <arch>");
process.exit(1);
}
const [targetPlatform, targetArch] = args;
// 2. Determine Version
const version = fs.readFileSync(path.join(process.cwd(), 'version.txt'), 'utf8').trim();
// 3. Construct URL
const gcsPlatform = PLATFORM_MAP[targetPlatform];
const gcsArch = ARCH_MAP[targetArch];
if (!gcsPlatform || !gcsArch) {
console.error(`Unsupported platform/arch: ${targetPlatform}/${targetArch}`);
process.exit(1);
}
const extension = targetPlatform === 'win32' ? '.exe' : '';
const binaryName = `toolbox${extension}`;
const url = `https://storage.googleapis.com/genai-toolbox/v${version}/${gcsPlatform}/${gcsArch}/${binaryName}`;
// 4. Prepare Output
const binDir = path.join(process.cwd(), 'bin');
if (!fs.existsSync(binDir)) {
fs.mkdirSync(binDir, { recursive: true });
}
const destPath = path.join(binDir, binaryName);
if (fs.existsSync(destPath)) {
console.log(`[Skipped] Binary already exists at ${destPath}`);
process.exit(0);
}
console.log(`[Prepack] Downloading ${binaryName} for ${targetPlatform}/${targetArch}...`);
console.log(`[Source] ${url}`);
// 5. Download Function
const file = fs.createWriteStream(destPath);
https.get(url, function(response) {
if (response.statusCode !== 200) {
console.error(`❌ Failed to download. Status Code: ${response.statusCode}`);
fs.unlink(destPath, () => {}); // Delete partial file
process.exit(1);
}
response.pipe(file);
file.on('finish', () => {
file.close(() => {
// 6. Make executable (Unix only)
if (targetPlatform !== 'win32') {
try {
execSync(`chmod +x "${destPath}"`);
} catch (err) {
console.warn("⚠️ Could not set executable permissions (chmod failed).");
}
}
console.log(`✅ Success! Binary saved to ${destPath}`);
});
});
}).on('error', function(err) {
fs.unlink(destPath, () => {});
console.error(`❌ Download Error: ${err.message}`);
process.exit(1);
});

View File

@@ -1 +0,0 @@
0.25.0

View File

@@ -1,7 +0,0 @@
# @toolbox-sdk/server-linux-x64
Platform-specific binary for the `toolbox` package on Linux x64.
This package is automatically installed by the main `@toolbox-sdk/server` package and is not intended to be installed directly.
For more information, visit the [toolbox npm package](https://www.npmjs.com/package/@toolbox-sdk/server).

View File

@@ -1,19 +0,0 @@
{
"name": "@toolbox-sdk/server-linux-x64",
"version": "0.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@toolbox-sdk/server-linux-x64",
"version": "0.25.0",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"os": [
"linux"
]
}
}
}

View File

@@ -1,20 +0,0 @@
{
"name": "@toolbox-sdk/server-linux-x64",
"version": "0.25.0",
"license": "Apache-2.0",
"author": "Google LLC",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "bin/toolbox",
"repository": "googleapis/genai-toolbox",
"scripts": {
"prepack": "node scripts/downloadBinary.js linux x64"
},
"files": [
"bin/toolbox"
]
}

View File

@@ -1,85 +0,0 @@
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
// 1. Configuration
const PLATFORM_MAP = {
'linux': 'linux',
'darwin': 'darwin',
'win32': 'windows'
};
const ARCH_MAP = {
'x64': 'amd64',
'arm64': 'arm64'
};
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node download-binary.js <platform> <arch>");
process.exit(1);
}
const [targetPlatform, targetArch] = args;
// 2. Determine Version
const version = fs.readFileSync(path.join(process.cwd(), 'version.txt'), 'utf8').trim();
// 3. Construct URL
const gcsPlatform = PLATFORM_MAP[targetPlatform];
const gcsArch = ARCH_MAP[targetArch];
if (!gcsPlatform || !gcsArch) {
console.error(`Unsupported platform/arch: ${targetPlatform}/${targetArch}`);
process.exit(1);
}
const extension = targetPlatform === 'win32' ? '.exe' : '';
const binaryName = `toolbox${extension}`;
const url = `https://storage.googleapis.com/genai-toolbox/v${version}/${gcsPlatform}/${gcsArch}/${binaryName}`;
// 4. Prepare Output
const binDir = path.join(process.cwd(), 'bin');
if (!fs.existsSync(binDir)) {
fs.mkdirSync(binDir, { recursive: true });
}
const destPath = path.join(binDir, binaryName);
if (fs.existsSync(destPath)) {
console.log(`[Skipped] Binary already exists at ${destPath}`);
process.exit(0);
}
console.log(`[Prepack] Downloading ${binaryName} for ${targetPlatform}/${targetArch}...`);
console.log(`[Source] ${url}`);
// 5. Download Function
const file = fs.createWriteStream(destPath);
https.get(url, function(response) {
if (response.statusCode !== 200) {
console.error(`❌ Failed to download. Status Code: ${response.statusCode}`);
fs.unlink(destPath, () => {}); // Delete partial file
process.exit(1);
}
response.pipe(file);
file.on('finish', () => {
file.close(() => {
// 6. Make executable (Unix only)
if (targetPlatform !== 'win32') {
try {
execSync(`chmod +x "${destPath}"`);
} catch (err) {
console.warn("⚠️ Could not set executable permissions (chmod failed).");
}
}
console.log(`✅ Success! Binary saved to ${destPath}`);
});
});
}).on('error', function(err) {
fs.unlink(destPath, () => {});
console.error(`❌ Download Error: ${err.message}`);
process.exit(1);
});

View File

@@ -1 +0,0 @@
0.25.0

View File

@@ -1,7 +0,0 @@
# @toolbox-sdk/server-win32-x64
Platform-specific binary for the `toolbox` package on Windows x64.
This package is automatically installed by the main `@toolbox-sdk/server` package and is not intended to be installed directly.
For more information, visit the [toolbox npm package](https://www.npmjs.com/package/@toolbox-sdk/server).

View File

@@ -1,19 +0,0 @@
{
"name": "@toolbox-sdk/server-win32-x64",
"version": "0.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@toolbox-sdk/server-win32-x64",
"version": "0.25.0",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"os": [
"win32"
]
}
}
}

View File

@@ -1,20 +0,0 @@
{
"name": "@toolbox-sdk/server-win32-x64",
"version": "0.25.0",
"license": "Apache-2.0",
"author": "Google LLC",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "bin/toolbox.exe",
"repository": "googleapis/genai-toolbox",
"scripts": {
"prepack": "node scripts/downloadBinary.js win32 x64"
},
"files": [
"bin/toolbox.exe"
]
}

View File

@@ -1,85 +0,0 @@
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
// 1. Configuration
const PLATFORM_MAP = {
'linux': 'linux',
'darwin': 'darwin',
'win32': 'windows'
};
const ARCH_MAP = {
'x64': 'amd64',
'arm64': 'arm64'
};
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("Usage: node download-binary.js <platform> <arch>");
process.exit(1);
}
const [targetPlatform, targetArch] = args;
// 2. Determine Version
const version = fs.readFileSync(path.join(process.cwd(), 'version.txt'), 'utf8').trim();
// 3. Construct URL
const gcsPlatform = PLATFORM_MAP[targetPlatform];
const gcsArch = ARCH_MAP[targetArch];
if (!gcsPlatform || !gcsArch) {
console.error(`Unsupported platform/arch: ${targetPlatform}/${targetArch}`);
process.exit(1);
}
const extension = targetPlatform === 'win32' ? '.exe' : '';
const binaryName = `toolbox${extension}`;
const url = `https://storage.googleapis.com/genai-toolbox/v${version}/${gcsPlatform}/${gcsArch}/${binaryName}`;
// 4. Prepare Output
const binDir = path.join(process.cwd(), 'bin');
if (!fs.existsSync(binDir)) {
fs.mkdirSync(binDir, { recursive: true });
}
const destPath = path.join(binDir, binaryName);
if (fs.existsSync(destPath)) {
console.log(`[Skipped] Binary already exists at ${destPath}`);
process.exit(0);
}
console.log(`[Prepack] Downloading ${binaryName} for ${targetPlatform}/${targetArch}...`);
console.log(`[Source] ${url}`);
// 5. Download Function
const file = fs.createWriteStream(destPath);
https.get(url, function(response) {
if (response.statusCode !== 200) {
console.error(`❌ Failed to download. Status Code: ${response.statusCode}`);
fs.unlink(destPath, () => {}); // Delete partial file
process.exit(1);
}
response.pipe(file);
file.on('finish', () => {
file.close(() => {
// 6. Make executable (Unix only)
if (targetPlatform !== 'win32') {
try {
execSync(`chmod +x "${destPath}"`);
} catch (err) {
console.warn("⚠️ Could not set executable permissions (chmod failed).");
}
}
console.log(`✅ Success! Binary saved to ${destPath}`);
});
});
}).on('error', function(err) {
fs.unlink(destPath, () => {});
console.error(`❌ Download Error: ${err.message}`);
process.exit(1);
});

View File

@@ -1 +0,0 @@
0.25.0

View File

@@ -1,69 +0,0 @@
# Toolbox
A CLI tool for running a toolbox server.
## Installation
You can install the toolbox globally:
```bash
npm install -g @toolbox-sdk/server
```
Or run it directly using npx:
```bash
npx @toolbox-sdk/server
```
## Configuration
The toolbox requires a `tools.yaml` file in the current working directory to define sources, tools, and prompts.
### Example `tools.yaml`
```yaml
sources:
my-pg-source:
kind: postgres
host: 127.0.0.1
port: 5432
database: toolbox_db
user: postgres
password: password
tools:
search-hotels-by-name:
kind: postgres-sql
source: my-pg-source
description: Search for hotels based on name.
parameters:
- name: name
type: string
description: The name of the hotel.
statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%';
prompts:
code-review:
description: "Asks the LLM to analyze code quality and suggest improvements."
messages:
- role: "user"
content: "Please review the following code for quality, correctness, and potential improvements: \n\n{{.code}}"
arguments:
- name: "code"
description: "The code to review"
required: true
```
To learn more on how to configure your toolbox, visit the [official docsite](https://googleapis.github.io/genai-toolbox/getting-started/configure/).
## Platform Support
The toolbox automatically handles platform-specific binaries. Supported platforms include:
- macOS (arm64, x64)
- Linux (x64)
- Windows (x64)
## Resources
For more information, visit the
- [MCP Toolbox repository](https://github.com/googleapis/genai-toolbox)
- [Official Documentation](https://googleapis.github.io/genai-toolbox/getting-started/introduction/)

View File

@@ -1,49 +0,0 @@
#!/usr/bin/env node
const { spawn } = require('child_process');
const path = require('path');
const os = require('os');
const fs = require('fs');
const PLATFORMS = {
'darwin-arm64': '@toolbox-sdk/server-darwin-arm64',
'darwin-x64': '@toolbox-sdk/server-darwin-x64',
'linux-x64': '@toolbox-sdk/server-linux-x64',
'win32-x64': '@toolbox-sdk/server-win32-x64'
};
const currentKey = `${os.platform()}-${os.arch()}`;
const pkgName = PLATFORMS[currentKey];
if (!pkgName) {
console.error(`Unsupported platform: ${currentKey}`);
process.exit(1);
}
let binPath;
try {
const pkgJsonPath = require.resolve(`${pkgName}/package.json`);
const pkgDir = path.dirname(pkgJsonPath);
const binName = os.platform() === 'win32' ? 'toolbox.exe' : 'toolbox';
binPath = path.join(pkgDir, 'bin', binName);
} catch (e) {
console.error(`Binary for ${currentKey} not found. Installation failed?`);
process.exit(1);
}
if (os.platform() !== 'win32') {
try {
fs.chmodSync(binPath, 0o755);
if (os.platform() === 'darwin') {
const { execSync } = require('child_process');
try {
execSync(`xattr -d com.apple.quarantine "${binPath}"`, { stdio: 'ignore' });
} catch (e) {
}
}
} catch (e) {
console.warn(`Could not set execute permissions on ${binPath}: ${e.message}`);
}
}
spawn(binPath, process.argv.slice(2), { stdio: 'inherit' })
.on('exit', process.exit);

View File

@@ -1,74 +0,0 @@
{
"name": "@toolbox-sdk/server",
"version": "0.25.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@toolbox-sdk/server",
"version": "0.25.0",
"license": "Apache-2.0",
"bin": {
"toolbox": "bin/run.js"
},
"optionalDependencies": {
"@toolbox-sdk/server-darwin-arm64": "0.25.0",
"@toolbox-sdk/server-darwin-x64": "0.25.0",
"@toolbox-sdk/server-linux-x64": "0.25.0",
"@toolbox-sdk/server-win32-x64": "0.25.0"
}
},
"node_modules/@toolbox-sdk/server-darwin-arm64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@toolbox-sdk/server-darwin-arm64/-/server-darwin-arm64-0.25.0.tgz",
"integrity": "sha512-HNAfaDOg2ggnZObJkh5JxoUtfL0WiA2nvDB7qNMdP3130Jgrc9y6rjpGVgN0ntk9zPhioussfbDDgc36jUTq+g==",
"cpu": [
"arm64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@toolbox-sdk/server-darwin-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@toolbox-sdk/server-darwin-x64/-/server-darwin-x64-0.25.0.tgz",
"integrity": "sha512-RG7rcfuA8jFylbdT0geXWGKtLBfsqXtwDR2kgJtr5hjdFqjhOwuN6jK0JNnjyHZoBx6xN6cG4nHs25uEWjrD9g==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@toolbox-sdk/server-linux-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@toolbox-sdk/server-linux-x64/-/server-linux-x64-0.25.0.tgz",
"integrity": "sha512-V/yjAcEJD4vxLyHXgkdUM6Wc8agma451O6Ms9loEfcIwwIWnb103UOOiZRd+pLdDViuuSzrhXNEH62vjhIoQUw==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@toolbox-sdk/server-win32-x64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@toolbox-sdk/server-win32-x64/-/server-win32-x64-0.25.0.tgz",
"integrity": "sha512-QUgPeWvHhD2lLqp4Tk1bDuEOu8l6y5ApsnTScEMIa2GO7G/jRJzkCT1TNZJIUxQMZEEXy38bn9x/fMMtNN9flQ==",
"cpu": [
"x64"
],
"license": "Apache-2.0",
"optional": true,
"os": [
"win32"
]
}
}
}

View File

@@ -1,19 +0,0 @@
{
"name": "@toolbox-sdk/server",
"version": "0.25.0",
"license": "Apache-2.0",
"author": "Google LLC",
"bin": {
"toolbox": "./bin/run.js"
},
"files": [
"bin/run.js"
],
"repository": "googleapis/genai-toolbox",
"optionalDependencies": {
"@toolbox-sdk/server-darwin-arm64": "0.25.0",
"@toolbox-sdk/server-darwin-x64": "0.25.0",
"@toolbox-sdk/server-linux-x64": "0.25.0",
"@toolbox-sdk/server-win32-x64": "0.25.0"
}
}

View File

@@ -1,91 +0,0 @@
# How to test on different platforms
1. Create a local test registry. We are using Verdaccio. During the actual process, we publish to npm instead.
```sh
# install
npm install -g verdaccio
# start server
verdaccio
```
The output will show the config file location and the URL. Open your browser to:
http://localhost:4873
> Note: You can use `npm unpublish @toolbox-sdk/server --force --registry http://localhost:4873` to unpublish the package.
2. Pack all 4 packages and publish them to the local registry. Go in each package (eg. server-darwin-arm64) and run
```sh
npm ci --force
npm pack .
```
Then publish to the local registry
```sh
npm publish --registry http://localhost:4873
```
3. Go to the server package and run
```sh
npm ci --force
npm pack .
npm publish --registry http://localhost:4873
```
Now, you have published your package.
4. Now create a new folder (let's call it testing.) Add a tools.yaml file to the folder. It should look like this:
```yaml
sources:
my-pg-source:
kind: postgres
host: 127.0.0.1
port: 5432
database: toolbox_db
user: postgres
password: password
tools:
search-hotels-by-name:
kind: postgres-sql
source: my-pg-source
description: Search for hotels based on name.
parameters:
- name: name
type: string
description: The name of the hotel.
statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%';
prompts:
code-review:
description: "Asks the LLM to analyze code quality and suggest improvements."
messages:
- role: "user"
content: "Please review the following code for quality, correctness, and potential improvements: \n\n{{.code}}"
arguments:
- name: "code"
description: "The code to review"
required: true
```
Note: Do not test this directly to the server folder. The registry might pick up local packages instead of global installation.
Use a separate testing folder outside the server folder for this testing.
6. From the testing folder, run
```sh
npx --registry=http://localhost:4873/ -y @toolbox-sdk/server
```
This should start up the toolbox server with the tools.yaml file.
7. Run the command to verify that the tools are available:
```sh
curl --location 'http://127.0.0.1:5000/mcp' \
--header 'Content-Type: application/json' \
--data '{
"jsonrpc": "2.0",
"method": "tools/list",
"params": {},
"id": 1
}'
```

View File

@@ -1,21 +0,0 @@
cd server-darwin-arm64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-darwin-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-linux-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-win32-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json

View File

@@ -1,7 +0,0 @@
cd server
npm install --package-lock-only
git add package.json package-lock.json
git commit -m "update dep versions"
npm pack .
npm publish --access public

View File

@@ -1,21 +0,0 @@
cd server-darwin-arm64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-darwin-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-linux-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json
cd ../server-win32-x64
npm install --force
rm -rf bin/
git add version.txt package.json package-lock.json