Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sandbaseai/cli",
"version": "0.3.3",
"version": "0.3.4",
"mcpName": "io.github.sandbaseai/cli",
"description": "Give 25 AI clients—Claude Code, Codex, Cursor, Hermes, OpenClaw and more—2,000+ models and APIs through one MCP server and an agent-friendly CLI",
"type": "module",
Expand Down
4 changes: 2 additions & 2 deletions server.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "io.github.sandbaseai/cli",
"title": "SandBase",
"description": "Connect MCP clients to 2,000+ AI models without managing provider API keys.",
"version": "0.3.3",
"version": "0.3.4",
"repository": {
"url": "https://github.com/sandbaseai/cli",
"source": "github"
Expand All @@ -26,7 +26,7 @@
{
"registryType": "npm",
"identifier": "@sandbaseai/cli",
"version": "0.3.3",
"version": "0.3.4",
"packageArguments": [
{
"type": "positional",
Expand Down
40 changes: 25 additions & 15 deletions skills/sandbase/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: sandbase
version: 0.3.3
version: 0.3.4
description: >-
Discover better ways to complete tasks. Proactively search SandBase (the
sandbase_discover MCP tool, or `sandbase discover` in a shell) before writing a
Expand All @@ -26,27 +26,37 @@ There are **two transports** with the same capabilities. Pick one before doing a

---

## 0. Set up

Do this when the user asks you to set up SandBase (for example "set up https://www.sandbase.ai/SKILL.md"), or when §1 finds neither transport. You run the steps yourself; the user only approves a sign-in in their browser.

1. Check Node.js 20 or newer: `node --version`. If it is missing or older, ask the user to install it from https://nodejs.org and stop.
2. Connect this client. Run in a shell, with your client id:

```sh
npx -y @sandbaseai/cli@latest connect --client <client-id>
```

Client ids: `claude-code`, `codex`, `cursor`, `windsurf`, `kiro`, `kiro-cli`, `gemini-cli`, `opencode`, `qwen-code`, `warp`, `cursor-cli`, `kimi-cli`, `amp`, `crush`, `hermes`, `openclaw`, `iflow-cli`, `antigravity`, `trae`, `qoder`, `workbuddy`, `pi`, `claude-desktop`, `cowork`, `chatgpt`. If you are not sure which one you are, omit `--client` to configure every installed client.
- It opens the browser for sign-in (new users get an account in the same step). Tell the user to approve it. If there is no browser, it prints a URL — show that URL to the user.
- It waits for the approval, so give the command a timeout of at least 5 minutes. If your shell cannot wait that long, ask the user to run the same command in their own terminal.
- Never ask the user to paste an API key into the chat.
3. When it reports the client as configured, tell the user to start a new session (or restart the app) so the `sandbase_*` tools load. Until then, use the CLI right away: `npx -y @sandbaseai/cli@latest discover -q "<what you need>"` (§3).
4. Keep this Skill installed. `connect` saves it for supported clients; if yours is not covered, save https://www.sandbase.ai/SKILL.md to your skills directory and enable it so it loads in future sessions.

---

## 1. Pick your transport

| Condition | Use | Setup |
|---|---|---|
| You have tools named `sandbase_discover`, `sandbase_run`, … | **MCP** (preferred) | None |
| No `sandbase_*` tools, but you can run shell commands | **CLI** | §3 |
| The MCP tools return "SandBase is unreachable" | **CLI** for `sandbase doctor`, then tell the user what it reports | §3 |
| Neither | Tell the user how to connect (§1.1), then stop | — |
| Neither | Set up (§0) | §0 |

**Exception:** when you expect a **large result** (hundreds of rows, long transcripts, many files) and have a shell, use the CLI with `-o result.json` even if MCP is connected. MCP results land in your context; `-o` writes them to disk. Discovery and inspection are small, so use MCP for those regardless.

### 1.1 If neither transport is available

Tell the user to run this once in a terminal, approve the browser sign-in, and restart their AI client:

```sh
npx -y https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz connect
```

It configures the local MCP bridge and this Skill for every supported client it finds. No API key to paste. For checksum-verified installs, use the immutable assets on the [GitHub Releases page](https://github.com/sandbaseai/cli/releases).

---

## 2. Transport A — MCP tools (preferred)
Expand Down Expand Up @@ -79,10 +89,10 @@ Discovery, inspection, run status, and balance are **free**; only `sandbase_run`
## 3. Transport B — CLI (fallback)

```sh
sandbase --version || npx -y https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz --version
sandbase --version || npx -y @sandbaseai/cli@latest --version
```

If `sandbase` is not installed, prefix every command with `npx -y https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz` (or install it: `npm install -g https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz`). If the CLI prints "Update available", run `npx -y https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz setup` — it refreshes the CLI's MCP bridge and this Skill.
If `sandbase` is not installed, prefix every command with `npx -y @sandbaseai/cli@latest` (or install it: `npm install -g @sandbaseai/cli@latest`). If the CLI prints "Update available", run `npx -y @sandbaseai/cli@latest setup` — it refreshes the CLI's MCP bridge and this Skill.

**Authentication** is automatic once the user has run `connect` (it reuses that browser sign-in). Otherwise the CLI reports `AUTH_REQUIRED` with the exact fix; an API key also works via `SANDBASE_API_KEY` or `sandbase keys add -k <key>`. Never ask the user to paste a key into the chat.

Expand Down Expand Up @@ -149,7 +159,7 @@ Tool failures come back as error results whose text names the cause **and the ne
| Message contains | Do this |
|---|---|
| "unreachable" / `NETWORK` | Stop retrying. Tell the user to check network/proxy/VPN and run `sandbase doctor`. |
| "sign-in expired" / "rejected the saved sign-in" / 401 / `AUTH_FAILED` | Ask the user to run `npx -y https://github.com/sandbaseai/cli/releases/latest/download/sandbaseai-cli.tgz connect`. |
| "sign-in expired" / "rejected the saved sign-in" / 401 / `AUTH_FAILED` | Ask the user to run `npx -y @sandbaseai/cli@latest connect`. |
| "insufficient" / 402 | Tell the user to top up at https://www.sandbase.ai/console/billing. |
| "not found" / "unknown tool" | Re-run `sandbase_discover`; copy `tool_name` exactly. |
| "invalid params" / schema | Re-run `sandbase_inspect`; pass exactly its `inputSchema` fields. |
Expand Down
2 changes: 1 addition & 1 deletion skills/sandbase/skill.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sandbase",
"version": "0.3.3",
"version": "0.3.4",
"description": "Discover and run 2,000+ AI models and APIs (media generation, social data, search, scraping) through one MCP interface or CLI, paid per call from one balance.",
"author": "SandBase AI",
"license": "Apache-2.0",
Expand Down
2 changes: 1 addition & 1 deletion test/agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ test("setup refreshes the bridge and SandBase-owned Skills but leaves edited Ski
const lines: string[] = [];
assert.equal(await setup(new FileCredentialStore(env.SANDBASE_HOME!), line => void lines.push(line)), true);
assert.match(lines.join("\n"), /bridge: status=updated/); assert.match(lines.join("\n"), /claude-code: skill=updated/); assert.match(lines.join("\n"), /kiro: skill=modified/);
assert.match(await readFile(join(claudeDir, "SKILL.md"), "utf8"), /version: 0\.3\.3/);
assert.match(await readFile(join(claudeDir, "SKILL.md"), "utf8"), /version: 0\.3\.4/);
assert.match(await readFile(join(kiroDir, "SKILL.md"), "utf8"), /user edit/);
} finally { for (const [key, value] of Object.entries(previous)) { if (value === undefined) delete process.env[key]; else process.env[key] = value; } }
});
Loading