MCP server exposing a hosted boxkite control-plane (sandbox lifecycle, exec, files) as native tools for MCP-compatible clients (Claude Code, Claude Desktop, Cursor, etc.).
Project description
boxkite-mcp
An MCP (Model Context Protocol) server over a hosted boxkite control-plane -- lets any MCP-compatible client (Claude Code, Claude Desktop, Cursor, etc.) attach a real sandboxed code-execution backend as a native tool source, with zero custom integration code.
Built on top of boxkite-client, the existing Python SDK for
the hosted control-plane API -- this package adds no HTTP logic of its own,
only the MCP tool surface.
Install
Not yet published to PyPI -- install both packages from this repo:
pip install -e ../sdk-python
pip install -e .
Configuration
Two environment variables, read at startup. The process fails fast with a clear error if either is missing:
| Variable | Meaning |
|---|---|
BOXKITE_BASE_URL |
Base URL of the boxkite control-plane, e.g. https://boxkite-control-plane-316016512837.us-central1.run.app |
BOXKITE_API_KEY |
A bxk_live_... API key for your account |
Run
BOXKITE_BASE_URL=https://your-control-plane.example.com \
BOXKITE_API_KEY=bxk_live_... \
boxkite-mcp
Speaks MCP over stdio -- point an MCP client's config at the boxkite-mcp
command (see the hosted docs site's MCP page for Claude Desktop / Claude Code
config snippets).
Tools
Every per-sandbox tool takes session_id as a parameter (unlike
boxkite_client.langchain_tools.create_sandbox_tools, which binds one
pre-created session at factory time) -- the calling agent owns the full
lifecycle: create a sandbox, run several things in it, destroy it, all
within one conversation.
create_sandbox(label?, size?, storage_gb?, lifetime_minutes?, count?)-- create a sandbox (or a batch ofcountsandboxes), returns id/status per sandbox.sizeis a CPU/memory preset ("small"default,"medium", or"large");storage_gbandlifetime_minutesoverride the sandbox's volume size and how long it stays alive. All four are optional and bounded by fair-use ceilings on the account, never a paid upgrade.destroy_sandbox(session_id)-- tear one downget_sandbox(session_id)-- look up one sandbox's statuslist_sandboxes(active_only?)-- list the account's sandboxesexec(session_id, command, timeout?)-- run a shell commandfile_create(session_id, path, content)-- create/overwrite a fileview(session_id, path, view_range?)-- view a file or list a directorystr_replace(session_id, path, old_str, new_str, replace_all?)-- edit a filels(session_id, path?)-- list the direct children of a directoryglob(session_id, pattern, path?)-- find files by name pattern (e.g.**/*.py)grep(session_id, pattern, path?, glob?, max_matches?)-- search file contents by regex
Security: the sandbox's own isolation is the trust boundary
exec runs arbitrary shell commands inside the sandbox with no client-side
allowlist, confirmation step, or command-scoping; view/file_create/
str_replace operate on any path within the sandbox with no additional
restriction at this layer. That's the correct design for a code-execution
sandbox product -- the isolation boundary is the Kubernetes sandbox itself
(see the root repo's SECURITY.md/README for what that isolation actually
provides), not these MCP tools' argument validation. Two things follow
from that:
- Whatever the
BOXKITE_API_KEYyou configure can reach (network access, mounted storage, any other capability your control-plane deployment grants that account's sandboxes) is reachable by any MCP client wired up to this server, unconditionally. Don't point this at an account/control-plane whose sandboxes have broader privileges than you want an LLM agent to have unsupervised access to. exec/viewresults are returned to the calling LLM as plain tool-result text, unsanitized. If a sandbox command produces attacker-influenced output (e.g. the agent clones an untrusted repo and then views a file from it), that content flows into the LLM's context like any other tool result -- treat it as untrusted input, same as you would for a web-fetch or file-read tool, not as trusted system output.
Error handling
Every tool catches BoxkiteApiError/BoxkiteConnectionError and returns a
descriptive string as the tool result instead of raising -- mirrors the
defensive pattern in boxkite_client.langchain_tools so a control-plane
error (quota hit, sandbox not found, network failure) shows up as normal
tool output the calling agent can react to, not a server crash.
Development
pip install -e ".[dev]"
pytest tests/
Unit tests mock the control-plane with httpx.MockTransport (same pattern as
sdk-python/tests/) -- no real deployment needed. tests/live_smoke.py is a
separate, non-CI manual script that drives the real server process over
stdio via mcp's own ClientSession against a live control-plane:
BOXKITE_BASE_URL=https://your-control-plane.example.com \
BOXKITE_API_KEY=bxk_live_... \
python tests/live_smoke.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file boxkite_mcp-0.1.0.tar.gz.
File metadata
- Download URL: boxkite_mcp-0.1.0.tar.gz
- Upload date:
- Size: 14.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
366f0260b6a431343434e62997c18ed15660d481e040e49c00ee9396671d93b2
|
|
| MD5 |
88153f2d9dd160a5bd3f4d4f9f43e942
|
|
| BLAKE2b-256 |
3a51514193a73e8cec23845cff3baaa6dba8714183301fe0b0b897c7677a5629
|
File details
Details for the file boxkite_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: boxkite_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0665b34e6e822e93251bcf5a916d0eb9e42618f5139bbd68f7983984e3c036ba
|
|
| MD5 |
4961ab09885ae1f2e3f4ef26996d1455
|
|
| BLAKE2b-256 |
16aa59a6554e9b5089624d9a4f315e46a38dca116bd947fe737ad4891eb8c6e6
|