ð Anthropic Sandbox Runtimeã§AIãšãŒãžã§ã³ãããã³ãã³ããå®å šã«å®è¡ãã
ð ã¯ããã«
æè¿ãAIãšãŒãžã§ã³ããMCPãµãŒããŒãäœ¿ãæ©äŒãå¢ããŠããŸãããããã®éãã»ãã¥ãªãã£ã確ä¿ããããšã¯éåžžã«éèŠã§ããAnthropic Sandbox RuntimeïŒsrtïŒ ã¯ãOSã¬ãã«ã§ãã¡ã€ã«ã·ã¹ãã ãšãããã¯ãŒã¯ã¢ã¯ã»ã¹ãå¶éã§ãã軜éãªãµã³ãããã¯ã¹ããŒã«ã§ããå
¬åŒããã¥ã¡ã³ããåç
§ããŠãã ããã
ãã®èšäºã§ã¯ãsrtã®åºæ¬çãªäœ¿ãæ¹ããèšå®æ¹æ³ãã»ãã¥ãªãã£äžã®æ³šæç¹ãŸã§ãå®è·µçãªå
容ãäžå¿ã«è§£èª¬ããŸããå®éã«äœ¿ã£ãŠã¿ãææ³ã亀ããªãããŸãšããŸããã
ð srtãšã¯
Anthropic Sandbox RuntimeïŒsrtïŒ ã¯ãã³ã³ãããå¿ èŠãšããã«ãOSãã€ãã£ãã®ãµã³ãããã¯ã¹æ©æ§ã䜿çšããŠããã»ã¹ã®æš©éãæå°åããããŒã«ã§ãã
âš äž»ãªç¹åŸŽ
以äžã®æ©èœãæã£ãŠããŸãã
| æ©èœ | 説æ |
|---|---|
| ãã¡ã€ã«ã·ã¹ãã å¶é | èªã¿åãã»æžã蟌ã¿ã¢ã¯ã»ã¹ãå¶åŸ¡ |
| ãããã¯ãŒã¯å¶é | èš±å¯ããããã¡ã€ã³ã®ã¿ãžã®ã¢ã¯ã»ã¹ãèš±å¯ |
| ãã¥ã¢ã«ã¢ã€ãœã¬ãŒã·ã§ã³ | ãã¡ã€ã«ã·ã¹ãã ãšãããã¯ãŒã¯ã®äž¡æ¹ãåé¢ |
| CLIãšã©ã€ãã©ãª | ã³ãã³ãã©ã€ã³ãšã©ã€ãã©ãªã®äž¡æ¹ã§å©çšå¯èœ |
å ·äœçã«ã¯ãAnthropicãå ¬éããŠããèš±å¯ããã³ãããè¶ ããŠ: Claude Code ãããå®å šãã€èªåŸçã«ããã§è©³ãã説æãããŠããŸãã
以äžã®å³ã®ããã«ãSandboxçµç±ã§ã³ãã³ãå®è¡ããã¡ã€ã«ã¢ã¯ã»ã¹ãè¡ãããšã§ãèš±å¯ãããã¡ã€ã³ããã¡ã€ã«ã®ã¿ã«ã¢ã¯ã»ã¹ã§ããããã«ãªããŸãã

ð¥ïž ãã©ãããã©ãŒã ãµããŒã
| ãã©ãããã©ãŒã | ãµããŒãç¶æ³ | äœ¿çšæè¡ |
|---|---|---|
| â macOS | å¯Ÿå¿ |
sandbox-execãäœ¿çš |
| â Linux | å¯Ÿå¿ |
bubblewrapãäœ¿çš |
| â Windows | æªå¯Ÿå¿ | - |
泚æ: Windowsã¯çŸåšæªå¯Ÿå¿ã§ãã
ðŠ ã€ã³ã¹ããŒã«
ð¥ åºæ¬ã€ã³ã¹ããŒã«
以äžã®ã³ãã³ãã§ã€ã³ã¹ããŒã«ã§ããŸãã
npm install -g @anthropic-ai/sandbox-runtime
ð§ 远å äŸåé¢ä¿
ãã ããOSã®æ©èœã䜿ãããã«ã以äžã®ã³ãã³ãã§äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããå¿ èŠããããŸããçè ã¯ãUbuntu 24.04ã§å®è¡ããŸããã
Linuxã®å Žå:
# Ubuntu/Debian
sudo apt install bubblewrap socat ripgrep
ãã ããããã ãã§ã¯srtã³ãã³ãå®è¡æã«bwrap: operation not permittedãçºçããŸããã以äžã®ã³ãã³ããå®è¡ããããšã§ãšã©ãŒãè§£æ¶ããŸããã
# Ubuntu 24.04ã®å Žå
sudo apt update
sudo apt install --only-upgrade apparmor apparmor-utils apparmor-profiles
sudo ln -s /usr/share/apparmor/extra-profiles/bwrap-userns-restrict /etc/apparmor.d/
sudo systemctl reload apparmor
ççŽãªææ³: äŸåé¢ä¿ã¯å°ãªãã§ãå°å
¥ã¯æ¯èŒçç°¡åã§ãããã ããLinuxã§ã¯bubblewrapãå¿
é ãªã®ã§ãæš©éãå¿
èŠãªå ŽåããããŸãã
ð åºæ¬çãªäœ¿ãæ¹
ð» CLIã§ã®äœ¿çš
# ãµã³ãããã¯ã¹å
ã§ã³ãã³ããå®è¡
srt "curl anthropic.com"
# èš±å¯ãããŠããªããã¡ã€ã³ãžã®ã¢ã¯ã»ã¹ã¯ãããã¯
srt "curl example.com"
# Connection blocked by network allowlist
# ãã¡ã€ã«ã·ã¹ãã å¶éã®äŸ
srt "cat ~/.ssh/id_rsa"
# cat: ~/.ssh/id_rsa: Operation not permitted
ð ãããã°ã¢ãŒã
srt --debug <command>
âïž èšå®ãã¡ã€ã«ã®è©³çް
ð èšå®ãã¡ã€ã«ã®å Žæ
ããã©ã«ãã§ã¯ã~/.srt-settings.jsonã䜿çšãããŸããã«ã¹ã¿ã ãã¹ãæå®ããããšãå¯èœã§ãã
srt --settings /path/to/srt-settings.json <command>
ð å®å šãªèšå®ãã¡ã€ã«äŸ
{
"network": {
"allowedDomains": [
"github.com",
"*.github.com",
"lfs.github.com",
"api.github.com",
"npmjs.org",
"*.npmjs.org"
],
"deniedDomains": [
"malicious.com"
],
"allowUnixSockets": ["/var/run/docker.sock"],
"allowLocalBinding": false
},
"filesystem": {
"denyRead": [
"~/.ssh"
],
"allowWrite": [
".",
"src/",
"test/",
"/tmp"
],
"denyWrite": [
".env",
"config/production.json"
]
},
"ignoreViolations": {
"*": ["/usr/bin", "/System"],
"git push": ["/usr/bin/nc"],
"npm": ["/private/tmp"]
},
"enableWeakerNestedSandbox": false
}
ð èšå®ãªãã·ã§ã³ã®æ¯èŒ
ð ãããã¯ãŒã¯èšå®
| èšå®é ç® | 説æ | ããã©ã«ãå€ |
|---|---|---|
allowedDomains |
èš±å¯ãããã¡ã€ã³ã®ãªã¹ãïŒã¯ã€ã«ãã«ãŒãå¯ïŒ | [] |
deniedDomains |
æåŠãããã¡ã€ã³ã®ãªã¹ãïŒåªå 床ãé«ãïŒ | [] |
allowUnixSockets |
Unixãœã±ããã®èš±å¯ïŒmacOSã®ã¿ïŒâ ïž | [] |
allowLocalBinding |
ããŒã«ã«ããŒããã€ã³ãã®èš±å¯ | false |
ðŸ ãã¡ã€ã«ã·ã¹ãã èšå®
| èšå®é ç® | 説æ | ããã©ã«ãå€ |
|---|---|---|
denyRead |
èªã¿åããæåŠãããã¹ã®ãªã¹ã |
[]ïŒå
šèš±å¯ïŒ |
allowWrite |
æžã蟌ã¿ãèš±å¯ãããã¹ã®ãªã¹ã |
["."]ïŒã«ã¬ã³ããã£ã¬ã¯ããªã®ã¿ïŒ |
denyWrite |
æžã蟌ã¿ãæåŠãããã¹ã®ãªã¹ãïŒåªå 床ãé«ãïŒ | [] |
ãã¹æ§æã®éã:
| ãã©ãããã©ãŒã | 察å¿ãã¿ãŒã³ | äŸ |
|---|---|---|
| macOS | globãã¿ãŒã³å¯Ÿå¿ |
src/**/*.tsã*.env
|
| Linux | ãªãã©ã«ãã¹ã®ã¿ |
/home/user/.sshãsrc/
|
ð§ ãã®ä»ã®èšå®
| èšå®é ç® | 説æ | ããã©ã«ãå€ |
|---|---|---|
ignoreViolations |
ã³ãã³ãããšã«éåãç¡èŠãããã¹ | {} |
enableWeakerNestedSandbox |
Dockerç°å¢åãç·©åã¢ãŒã â ïž | false |
ð ããããèšå®ã¬ã·ã
ð GitHubãžã®ã¢ã¯ã»ã¹ã®ã¿èš±å¯
{
"network": {
"allowedDomains": [
"github.com",
"*.github.com",
"lfs.github.com",
"api.github.com"
],
"deniedDomains": []
},
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": []
}
}
ð ç¹å®ãã£ã¬ã¯ããªãžã®æžã蟌ã¿ã®ã¿èš±å¯
{
"network": {
"allowedDomains": [],
"deniedDomains": []
},
"filesystem": {
"denyRead": ["~/.ssh"],
"allowWrite": [".", "src/", "test/"],
"denyWrite": [".env", "secrets/"]
}
}
ð MCPãµãŒããŒã®ãµã³ãããã¯ã¹èšå®
.mcp.jsonã§ã®èšå®:
{
"mcpServers": {
"filesystem": {
"command": "srt",
"args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
}
}
}
察å¿ãã~/.srt-settings.json:
{
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": ["~/.sensitive-folder"]
},
"network": {
"allowedDomains": [],
"deniedDomains": []
}
}
ççŽãªææ³: MCPãµãŒããŒãšã®çµã¿åããã¯å®çšçã§ãç¹ã«ãã¡ã€ã«ã·ã¹ãã ç³»ã®MCPãµãŒããŒã䜿ãå Žåã¯å¿ é ã®èšå®ã ãšæããŸãã
ð€ ç¬èªã®AIãšãŒãžã§ã³ãã§srtã³ãã³ããå©çšãã
Strands AgentãMastraãªã©ã䜿ã£ãŠèªåŸçãªAIãšãŒãžã§ã³ãå ã§ã³ãã³ãå®è¡ãèš±å¯ããå Žåãããã³ããã§srtã³ãã³ãã䜿ã£ãŠå®è¡ããããã«æç€ºããããšã§ããµã³ãããã¯ã¹ãçšããŠã»ãã¥ãªãã£ã確ä¿ã§ããŸãã
çè
ã¯ããããããããã£ããã§ãã
Strands Agentã®äžã§srtã³ãã³ããå©çšããAgentãäœæããŠè©ŠããŠã¿ãŸããã
ð» ãœãŒã¹ã³ãŒã
import os
from strands import Agent
from strands.models.openai import OpenAIModel
from dotenv import load_dotenv
from strands_tools import shell
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
model_name = os.getenv("OPENAI_MODEL_NAME")
base_url = os.getenv("OPENAI_BASE_URL")
openai_model = OpenAIModel(
client_args={"api_key": api_key, "base_url": base_url},
model_id=model_name)
agent = Agent(
model=openai_model,
tools=[shell],
system_prompt= """ããªãã¯ã·ã§ã«ã䜿ã£ãŠã³ãã³ããå®è¡ããããšãã§ããŸãã
**éèŠ** äœããå®è¡æã«ã¯ãsrtã³ãã³ããå
é ã«ä»ããŠå®è¡ããŠãã ããã
äŸ. srt ls -ltr
srtã³ãã³ãã¯ãµã³ãããã¯ã¹çµç±ã§ã³ãã³ããå®è¡ããããšã§ãã»ãã¥ãªãã£ç¢ºä¿ãè¡ããŸãã
ã³ãã³ãå®è¡æã«èš±å¯ãããŠãªãå Žåã¯ã~/.srt-settings.jsonã®æš©éèšå®ã確èªããããã«ãŠãŒã¶ã«åçããŠäžããã
"""
)
print("--- tool.shellã§åç
§ããå Žå ---")
result = agent.tool.shell(command="srt cat ~/.srt-settings.json")
print("--- ããã³ããããåç
§ããå Žå ---")
agent("~/.srt-settings.jsonã®äžèº«ãèŠããŠãã ãããåç
§ãèš±å¯ãããŠããªãå Žåã¯è«ŠããŠäžãã")
ð å®è¡çµæ
以äžã®ã³ãã³ãã§å®è¡ããŠã¿ãŸãã
python srt_tool_agent.py
srtã®å¶åŸ¡ãå¹ããŠãåç §ã§ããªããªã£ãŠããŸããOK!
"denyRead": ["~/.srt-settings.json"],ãšèšå®ããç¶æ
ã§å®è¡ãããšãsrt-settings.jsonãåç
§ããããšã¯ã§ããã«ããšã©ãŒã«ãªããŸãã
--- tool.shellã§åç
§ããå Žå ---
Do you want to proceed with execution? [y/*] y
Running: cat /home/xxxx/.srt-settings.json
cat: /home/xxxx/.srt-settings.json: èš±å¯ããããŸãã
--- ããã³ããããåç
§ããå Žå ---
詊ããŠã¿ãŸããããèªã¿åããæåŠãããŸããïŒèš±å¯ããããŸããïŒããã®ããäžèº«ã衚瀺ã§ããŸããããèŠæã©ããããã以äžã¯è«ŠããŸãã
<çç¥>
ð€ ç¬èªã®AIãšãŒãžã§ã³ãã®ããŒã«ãå©çšãã
以äžã®ãœãŒã¹ã³ãŒãã®ããã«Strands Agentãæã€ããŒã«ãå©çšããŠãã¡ã€ã«åç §ã詊ã¿ãŸãã
ð» ãœãŒã¹ã³ãŒã
import os
from strands import Agent
from strands.models.openai import OpenAIModel
from dotenv import load_dotenv
from strands_tools import shell,file_read
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
model_name = os.getenv("OPENAI_MODEL_NAME")
base_url = os.getenv("OPENAI_BASE_URL")
openai_model = OpenAIModel(
client_args={"api_key": api_key, "base_url": base_url},
model_id=model_name)
agent = Agent(
model=openai_model,
tools=[file_read],
system_prompt=""
)
print("--- tool.file_readã§åç
§ããå Žå ---")
agent.tool.file_read(path="~/.srt-settings.json")
print("--- ããã³ããããåç
§ããå Žå ---")
agent("~/.srt-settings.jsonã®äžèº«ãèŠããŠãã ãããåç
§ãèš±å¯ãããŠããªãå Žåã¯è«ŠããŠã~/.srt-settings.jsonã確èªããããã«ä¿ããŠäžãã")
ð å®è¡çµæ
strçµç±ã§pythonãèµ·åããŸãã
srtã³ãã³ããSOCKSãããã·ã䜿çšããããšããã®ã§ãå®è¡åã«httpx[socks]ãå
¥ããŠãããŸãã
uv pip install 'httpx[socks]'
srt python srt_tool_agent.py
srtã®å¶åŸ¡ãå¹ããŠãåç §ã§ããªããªã£ãŠããŸããOK!
--- tool.file_readã§åç
§ããå Žå ---
--- ããã³ããããåç
§ããå Žå ---
Tool #1: file_read
ãã¡ã€ã«ãèªã¿åãããšããŸããããPermission deniedïŒæš©éæåŠïŒã§éããŸããã§ããããã®ã»ãã·ã§ã³ããã¯äžèº«ã衚瀺ã§ããªãç¶æ
ã§ãããæå
ã§ç¢ºèªããã«ã¯ä»¥äžã®ã³ãã³ãã詊ããŠãã ããã
<çç¥>
ð€ ç¬èªã®AIãšãŒãžã§ã³ãã§stdioãããã³ã«ã®MCPãµãŒããå©çšãã
以äžã®ãœãŒã¹ã³ãŒãã®ããã«MCPClientã䜿çšããŠãMCPãµãŒããŒã«æ¥ç¶ãããšããŸãã
ð» ãœãŒã¹ã³ãŒã
import os
from strands import Agent
from strands.models.openai import OpenAIModel
from dotenv import load_dotenv
from strands_tools import shell
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
model_name = os.getenv("OPENAI_MODEL_NAME")
base_url = os.getenv("OPENAI_BASE_URL")
openai_model = OpenAIModel(
client_args={"api_key": api_key, "base_url": base_url},
model_id=model_name)
# MCPClientã䜿çšããŠãMCPãµãŒããŒã«æ¥ç¶ããŸãã
stdio_mcp_client = MCPClient(lambda: stdio_client(
StdioServerParameters(
command="srt",
args=["npx", "-y","@modelcontextprotocol/server-filesystem" ,"/home/xxxx"],
)
))
with stdio_mcp_client:
document_mcp_tools = stdio_mcp_client.list_tools_sync()
agent = Agent(
model=openai_model,
tools=[document_mcp_tools],
system_prompt="")
print("--- ããã³ããããåç
§ããå Žå ---")
agent("~/.srt-settings.jsonã®äžèº«ãèŠããŠãã ãããåç
§ãèš±å¯ãããŠããªãå Žåã¯è«ŠããŠã~/.srt-settings.jsonã確èªããããã«ä¿ããŠäžãã")
ð å®è¡çµæ(倱æ)
以äžã®ã³ãã³ãã§å®è¡ããŠã¿ãŸãã
python srt_tool_agent.py
ããããšã©ãŒã«ãªããŸãã»ã»ã»ð
æåã§ãå®è¡ããŠã¿ããšã以äžã®ãããªçµæã«ãªããŸãã
$ srt npx -y @modelcontextprotocol/server-filesystem "/home/masato"
Running: npx -y @modelcontextprotocol/server-filesystem /home/masato
Secure MCP Filesystem Server running on stdio
ð©¹ å¯ŸåŠæ¹æ³
stdioãããã³ã«ã ãšãæšæºå
¥åºåã§ããåãããã®ã§ãRunning:ããå§ãŸãè¡ãã
MCPClientåŽã«ãäŒãã£ãŠãæ³å®å€ã®ãããã³ã«ãšããŠãšã©ãŒã«ãªããŸãã
~/.npm-global/lib/node_modules/@anthropic-ai/sandbox-runtime/dist/cli.js
ã®ä»¥äžã®ã³ã³ãœãŒã«ãã°ãã³ã¡ã³ãã¢ãŠãããŸãã
104c104
< console.log(`Running: ${command}`);
---
> //console.log(`Running: ${command}`);
ð å®è¡çµæ(æå)
ããã§ãStrands Agentã®MCPClientãããMCPãµãŒããsrtã®å¶éãæãã£ãç¶æ
ã§ã
å®è¡ããããšãã§ããŸããã
Secure MCP Filesystem Server running on stdio
Client does not support MCP Roots, using allowed directories set from server args: [ '/home/xxxx' ]
--- ããã³ããããåç
§ããå Žå ---
Tool #1: list_allowed_directories
Tool #2: read_text_file
ãã¡ã€ã«ãçŽæ¥éãããšããŸããããæš©éãšã©ãŒã§èªããŸããã§ããïŒpermission deniedïŒããã¡ãããã¯åç
§ã§ããªãã®ã§ãæãå
¥ããŸãããèªèº«ã§äžèº«ã確èªããŠããã ãå¿
èŠããããŸãã
<çç¥>
ð¯ ã©ããªå Žé¢ã§äœ¿ãã¹ãïŒ
å®éã®éçºçŸå Žã§ãã©ããªå Žé¢ã§srtã䜿ãã¹ãããŸãšããŸããã
â 䜿ãã¹ãå Žé¢
| é©çšå Žé¢ | å ·äœäŸ |
|---|---|
| AIãšãŒãžã§ã³ãã®å®è¡ | Claude CodeãCursorçã§AIãšãŒãžã§ã³ããå®è¡ããé |
| MCPãµãŒããŒã®å®è¡ | ãã¡ã€ã«ã·ã¹ãã ããããã¯ãŒã¯ã¢ã¯ã»ã¹ãå¿ èŠãªMCPãµãŒã㌠|
| äžæãªã¹ã¯ãªããã®å®è¡ | ä¿¡é Œã§ããªãã¹ã¯ãªãããããã±ãŒãžãå®è¡ããé |
| CI/CDã§ã®å®è¡ | ãã«ãã¹ã¯ãªããããã¹ãã¹ã¯ãªããã®å®è¡æ |
â 䜿ããªãæ¹ãè¯ãå Žé¢
| å Žé¢ | çç± |
|---|---|
| éçºç°å¢ã®æ§ç¯ | åæã»ããã¢ããæã¯å¶éãéªéã«ãªãå¯èœæ§ |
| ã·ã¹ãã ã³ãã³ãã®å®è¡ | æš©éãå¿ èŠãªæäœãå€ãå Žå |
| Dockerã³ã³ããå | æ¢ã«éé¢ãããŠããããã远å ã®ãµã³ãããã¯ã¹ã¯äžèŠãªå Žåããã |
ççŽãªææ³: AIãšãŒãžã§ã³ããé »ç¹ã«äœ¿ã人ã«ã¯å¿ é ã®ããŒã«ã ãšæããŸããç¹ã«MCPãµãŒããŒã䜿ãå Žåã¯ãèšå®ããŠãããšå®å¿ã§ãã
ð å人çãªçµè«
AIã»å¹çå奜ããšããŠã®ççŽãªææ³ããŸãšãããšïŒ
srtã¯AIãšãŒãžã§ã³ãã䜿ã人ã«ã¯å¿
é ã®ããŒã«ã ãšæããŸããçç±ã¯ïŒ
- ã»ãã¥ãªãã£ã®ç¢ºä¿: ãã¡ã€ã«ã·ã¹ãã ãšãããã¯ãŒã¯ã¢ã¯ã»ã¹ãå¶éã§ãã
- ç°¡åãªå°å ¥: èšå®ãã¡ã€ã«äžã€ã§ç®¡çã§ãã
- å®çšæ§ãé«ã: MCPãµãŒããŒãšã®çµã¿åãããç¹ã«äŸ¿å©
ç¹ã«MCPãµãŒããŒã䜿ãå Žåã¯ãèšå®ããŠãããšå®å¿ã§ããæåã¯ããã©ã«ãèšå®ããå§ããŠãå¿ èŠã«å¿ããŠå¶éã远å ããŠããã®ãè¯ãããã§ãã
ð ãŸãšã
Anthropic Sandbox RuntimeïŒsrtïŒã¯ãAIãšãŒãžã§ã³ããMCPãµãŒããŒãå®å šã«å®è¡ããããã®åŒ·åãªããŒã«ã§ããé©åãªèšå®ã«ããããã¡ã€ã«ã·ã¹ãã ãšãããã¯ãŒã¯ã¢ã¯ã»ã¹ãå¶éããã»ãã¥ãªãã£ãåäžãããããšãã§ããŸãã
ããè©³çŽ°ãªæ å ±ã«ã€ããŠã¯ãå ¬åŒããã¥ã¡ã³ããåç §ããŠãã ããã
ð åè
以äžãåèã«ããå ¬åŒããã¥ã¡ã³ãããªããžããªã§ãã
Discussion