mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 09:01:17 +00:00
docs: add mcp and skill session config (#106)
This commit is contained in:
parent
d236edf35c
commit
4c8d93e077
95 changed files with 10014 additions and 1342 deletions
245
docs/custom-tools.mdx
Normal file
245
docs/custom-tools.mdx
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
---
|
||||
title: "Custom Tools"
|
||||
description: "Give agents custom tools inside the sandbox using MCP servers or skills."
|
||||
sidebarTitle: "Custom Tools"
|
||||
icon: "wrench"
|
||||
---
|
||||
|
||||
There are two ways to give agents custom tools that run inside the sandbox:
|
||||
|
||||
| | MCP Server | Skill |
|
||||
|---|---|---|
|
||||
| **How it works** | Sandbox Agent spawns your MCP server process and routes tool calls to it via stdio | A markdown file that instructs the agent to run your script with `node` (or any command) |
|
||||
| **Tool discovery** | Agent sees tools automatically via MCP protocol | Agent reads instructions from the skill file |
|
||||
| **Best for** | Structured tools with typed inputs/outputs | Lightweight scripts with natural-language instructions |
|
||||
| **Requires** | `@modelcontextprotocol/sdk` dependency | Just a markdown file and a script |
|
||||
|
||||
Both approaches execute code inside the sandbox, so your tools have full access to the sandbox filesystem, network, and installed system tools.
|
||||
|
||||
## Option A: Tools via MCP
|
||||
|
||||
<Steps>
|
||||
<Step title="Write your MCP server">
|
||||
Create an MCP server that exposes tools using `@modelcontextprotocol/sdk` with `StdioServerTransport`. This server will run inside the sandbox.
|
||||
|
||||
```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 (inclusive)",
|
||||
{
|
||||
min: z.number().describe("Minimum value"),
|
||||
max: z.number().describe("Maximum value"),
|
||||
},
|
||||
async ({ min, max }) => ({
|
||||
content: [{ type: "text", text: String(Math.floor(Math.random() * (max - min + 1)) + min) }],
|
||||
}),
|
||||
);
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
This is a simple example. Your MCP server runs inside the sandbox, so you can execute any code you'd like: query databases, call internal APIs, run shell commands, or interact with any service available in the container.
|
||||
</Step>
|
||||
|
||||
<Step title="Package the MCP server">
|
||||
Bundle into a single JS file so it can be uploaded and executed without a `node_modules` folder.
|
||||
|
||||
```bash
|
||||
npx esbuild src/mcp-server.ts --bundle --format=cjs --platform=node --target=node18 --minify --outfile=dist/mcp-server.cjs
|
||||
```
|
||||
|
||||
This creates `dist/mcp-server.cjs` ready to upload.
|
||||
</Step>
|
||||
|
||||
<Step title="Create sandbox and upload MCP server">
|
||||
Start your sandbox, then write the bundled file into it.
|
||||
|
||||
<CodeGroup>
|
||||
```ts TypeScript
|
||||
import { SandboxAgent } from "sandbox-agent";
|
||||
import fs from "node:fs";
|
||||
|
||||
const client = await SandboxAgent.connect({
|
||||
baseUrl: "http://127.0.0.1:2468",
|
||||
token: process.env.SANDBOX_TOKEN,
|
||||
});
|
||||
|
||||
const content = await fs.promises.readFile("./dist/mcp-server.cjs");
|
||||
await client.writeFsFile(
|
||||
{ path: "/opt/mcp/custom-tools/mcp-server.cjs" },
|
||||
content,
|
||||
);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/mcp/custom-tools/mcp-server.cjs" \
|
||||
-H "Authorization: Bearer $SANDBOX_TOKEN" \
|
||||
--data-binary @./dist/mcp-server.cjs
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Create a session">
|
||||
Point an MCP server config at the bundled JS file. When the session starts, Sandbox Agent spawns the MCP server process and routes tool calls to it.
|
||||
|
||||
<CodeGroup>
|
||||
```ts TypeScript
|
||||
await client.createSession("custom-tools", {
|
||||
agent: "claude",
|
||||
mcp: {
|
||||
customTools: {
|
||||
type: "local",
|
||||
command: ["node", "/opt/mcp/custom-tools/mcp-server.cjs"],
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "http://127.0.0.1:2468/v1/sessions/custom-tools" \
|
||||
-H "Authorization: Bearer $SANDBOX_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"agent": "claude",
|
||||
"mcp": {
|
||||
"customTools": {
|
||||
"type": "local",
|
||||
"command": ["node", "/opt/mcp/custom-tools/mcp-server.cjs"]
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Option B: Tools via Skills
|
||||
|
||||
Skills are markdown files that instruct the agent how to use a script. Upload the script and a skill file, then point the session at the skill directory.
|
||||
|
||||
<Steps>
|
||||
<Step title="Write your script">
|
||||
Write a script that the agent will execute. This runs inside the sandbox just like an MCP server, but the agent invokes it directly via its shell tool.
|
||||
|
||||
```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);
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Write a skill file">
|
||||
Create a `SKILL.md` that tells the agent what the script does and how to run it. The frontmatter `name` and `description` fields are required. See [Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices) for tips on writing effective skills.
|
||||
|
||||
```md SKILL.md
|
||||
---
|
||||
name: random-number
|
||||
description: Generate a random integer between min and max (inclusive). Use when the user asks for a random number.
|
||||
---
|
||||
|
||||
To generate a random number, run:
|
||||
|
||||
```bash
|
||||
node /opt/skills/random-number/random-number.cjs <min> <max>
|
||||
```
|
||||
|
||||
This prints a single random integer between min and max (inclusive).
|
||||
</Step>
|
||||
|
||||
<Step title="Package the script">
|
||||
Bundle the script just like an MCP server so it has no dependencies at runtime.
|
||||
|
||||
```bash
|
||||
npx esbuild src/random-number.ts --bundle --format=cjs --platform=node --target=node18 --minify --outfile=dist/random-number.cjs
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Create sandbox and upload files">
|
||||
Upload both the bundled script and the skill file.
|
||||
|
||||
<CodeGroup>
|
||||
```ts TypeScript
|
||||
import { SandboxAgent } from "sandbox-agent";
|
||||
import fs from "node:fs";
|
||||
|
||||
const client = await SandboxAgent.connect({
|
||||
baseUrl: "http://127.0.0.1:2468",
|
||||
token: process.env.SANDBOX_TOKEN,
|
||||
});
|
||||
|
||||
const script = await fs.promises.readFile("./dist/random-number.cjs");
|
||||
await client.writeFsFile(
|
||||
{ path: "/opt/skills/random-number/random-number.cjs" },
|
||||
script,
|
||||
);
|
||||
|
||||
const skill = await fs.promises.readFile("./SKILL.md");
|
||||
await client.writeFsFile(
|
||||
{ path: "/opt/skills/random-number/SKILL.md" },
|
||||
skill,
|
||||
);
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/skills/random-number/random-number.cjs" \
|
||||
-H "Authorization: Bearer $SANDBOX_TOKEN" \
|
||||
--data-binary @./dist/random-number.cjs
|
||||
|
||||
curl -X PUT "http://127.0.0.1:2468/v1/fs/file?path=/opt/skills/random-number/SKILL.md" \
|
||||
-H "Authorization: Bearer $SANDBOX_TOKEN" \
|
||||
--data-binary @./SKILL.md
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
|
||||
<Step title="Create a session">
|
||||
Point the session at the skill directory. The agent reads `SKILL.md` and learns how to use your script.
|
||||
|
||||
<CodeGroup>
|
||||
```ts TypeScript
|
||||
await client.createSession("custom-tools", {
|
||||
agent: "claude",
|
||||
skills: {
|
||||
sources: [
|
||||
{ type: "local", source: "/opt/skills/random-number" },
|
||||
],
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```bash cURL
|
||||
curl -X POST "http://127.0.0.1:2468/v1/sessions/custom-tools" \
|
||||
-H "Authorization: Bearer $SANDBOX_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"agent": "claude",
|
||||
"skills": {
|
||||
"sources": [
|
||||
{ "type": "local", "source": "/opt/skills/random-number" }
|
||||
]
|
||||
}
|
||||
}'
|
||||
```
|
||||
</CodeGroup>
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Notes
|
||||
|
||||
- The sandbox image must include a Node.js runtime that can execute the bundled files.
|
||||
Loading…
Add table
Add a link
Reference in a new issue