mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 14:03:52 +00:00
163 lines
3.8 KiB
Text
163 lines
3.8 KiB
Text
---
|
|
title: "Custom Tools"
|
|
description: "Give agents custom tools inside the sandbox using MCP servers or skills."
|
|
sidebarTitle: "Custom Tools"
|
|
icon: "wrench"
|
|
---
|
|
|
|
There are two common patterns for sandbox-local custom tooling:
|
|
|
|
| | MCP Server | Skill |
|
|
|---|---|---|
|
|
| **How it works** | Agent connects to an MCP server (`mcpServers`) | Agent follows `SKILL.md` instructions and runs scripts |
|
|
| **Best for** | Typed tool calls and structured protocols | Lightweight task-specific guidance |
|
|
| **Requires** | MCP server process (stdio/http/sse) | Script + `SKILL.md` |
|
|
|
|
## Option A: MCP server (stdio)
|
|
|
|
<Steps>
|
|
<Step title="Write and bundle your MCP server">
|
|
|
|
```ts src/mcp-server.ts
|
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
import { z } from "zod";
|
|
|
|
const server = new McpServer({ name: "rand", version: "1.0.0" });
|
|
|
|
server.tool(
|
|
"random_number",
|
|
"Generate a random integer between min and max",
|
|
{
|
|
min: z.number(),
|
|
max: z.number(),
|
|
},
|
|
async ({ min, max }) => ({
|
|
content: [{ type: "text", text: String(Math.floor(Math.random() * (max - min + 1)) + min) }],
|
|
}),
|
|
);
|
|
|
|
await server.connect(new StdioServerTransport());
|
|
```
|
|
|
|
```bash
|
|
npx esbuild src/mcp-server.ts --bundle --format=cjs --platform=node --target=node18 --outfile=dist/mcp-server.cjs
|
|
```
|
|
</Step>
|
|
|
|
<Step title="Upload it into the sandbox">
|
|
|
|
```ts
|
|
import { SandboxAgent } from "sandbox-agent";
|
|
import fs from "node:fs";
|
|
|
|
const sdk = await SandboxAgent.connect({ baseUrl: "http://127.0.0.1:2468" });
|
|
const content = await fs.promises.readFile("./dist/mcp-server.cjs");
|
|
|
|
await sdk.writeFsFile({ path: "/opt/mcp/custom-tools/mcp-server.cjs" }, content);
|
|
```
|
|
|
|
```bash
|
|
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/mcp/custom-tools/mcp-server.cjs" \
|
|
--data-binary @./dist/mcp-server.cjs
|
|
```
|
|
</Step>
|
|
|
|
<Step title="Register MCP config and create a session">
|
|
|
|
```ts
|
|
await sdk.setMcpConfig(
|
|
{
|
|
directory: "/workspace",
|
|
mcpName: "customTools",
|
|
},
|
|
{
|
|
type: "local",
|
|
command: "node",
|
|
args: ["/opt/mcp/custom-tools/mcp-server.cjs"],
|
|
},
|
|
);
|
|
|
|
const session = await sdk.createSession({
|
|
agent: "claude",
|
|
sessionInit: {
|
|
cwd: "/workspace",
|
|
},
|
|
});
|
|
|
|
await session.prompt([
|
|
{ type: "text", text: "Use the random_number tool with min=1 and max=10." },
|
|
]);
|
|
```
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Option B: Skills
|
|
|
|
<Steps>
|
|
<Step title="Write script + skill file">
|
|
|
|
```ts src/random-number.ts
|
|
const min = Number(process.argv[2]);
|
|
const max = Number(process.argv[3]);
|
|
|
|
if (Number.isNaN(min) || Number.isNaN(max)) {
|
|
console.error("Usage: random-number <min> <max>");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(Math.floor(Math.random() * (max - min + 1)) + min);
|
|
```
|
|
|
|
````md SKILL.md
|
|
---
|
|
name: random-number
|
|
description: Generate a random integer between min and max.
|
|
---
|
|
|
|
Run:
|
|
|
|
```bash
|
|
node /opt/skills/random-number/random-number.cjs <min> <max>
|
|
```
|
|
````
|
|
|
|
```bash
|
|
npx esbuild src/random-number.ts --bundle --format=cjs --platform=node --target=node18 --outfile=dist/random-number.cjs
|
|
```
|
|
</Step>
|
|
|
|
<Step title="Upload files">
|
|
|
|
```ts
|
|
import fs from "node:fs";
|
|
|
|
const script = await fs.promises.readFile("./dist/random-number.cjs");
|
|
await sdk.writeFsFile({ path: "/opt/skills/random-number/random-number.cjs" }, script);
|
|
|
|
const skill = await fs.promises.readFile("./SKILL.md");
|
|
await sdk.writeFsFile({ path: "/opt/skills/random-number/SKILL.md" }, skill);
|
|
```
|
|
</Step>
|
|
|
|
<Step title="Use in a session">
|
|
|
|
```ts
|
|
const session = await sdk.createSession({
|
|
agent: "claude",
|
|
sessionInit: {
|
|
cwd: "/workspace",
|
|
},
|
|
});
|
|
|
|
await session.prompt([
|
|
{ type: "text", text: "Use the random-number skill to pick a number from 1 to 100." },
|
|
]);
|
|
```
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Notes
|
|
|
|
- The sandbox runtime must include Node.js (or your chosen runtime).
|
|
- For persistent skill-source wiring by directory, see [Skills](/skills-config).
|