Skip to content

feat(mcp): add host_path and mount_path parameters with unit tests#1131

Open
candlelightner wants to merge 2 commits into
opensandbox-group:mainfrom
candlelightner:main
Open

feat(mcp): add host_path and mount_path parameters with unit tests#1131
candlelightner wants to merge 2 commits into
opensandbox-group:mainfrom
candlelightner:main

Conversation

@candlelightner

Copy link
Copy Markdown

Summary

  • What is changing and why?
    This PR exposes the core platform's native volume-mounting layer through the Python MCP server configuration schema. Currently, the sandbox_create MCP tool omits the underlying Python SDK's volume mapping options. This locks downstream MCP-capable AI clients (such as LibreChat, Claude Code, and Cursor) out of host-bound filesystem persistence workflows.

This change appends keyword-only optional attributes (host_path: str | None = None and mount_path: str | None = None) onto the sandbox_create tool signature, cleanly maps them to native OpenSandbox Volume models, and forwards them to the orchestration layer.

Testing

  • Not run (explain why)
  • Unit tests
  • Integration tests
  • e2e / manual verification

Details:

  1. Unit Testing: Introduced the first unit verification suite for the MCP module (tests/test_server.py). The test initializes the FastMCP application via the create_server factory, extracts the target function from the tool manager, and asserts that input parameters are successfully structured into native Volume specs with accurate snake_case attributes. Passed cleanly locally using uv run pytest tests/.
  2. E2E Verification: Manually verified via a LibreChat instance using a bridge network proxy (socat). Confirmed the new schema updates are broadcasted accurately, allowing an LLM agent to provision a container, mount an ext4 host path (/var/lib/sandboxes/workspaces), write an integrity file, completely destroy the sandbox instance, and verify data persistence upon mounting the same path to an independent subsequent sandbox.

Breaking Changes

  • None
  • Yes (describe impact and migration path)

Details:

The added parameters are fully optional keyword arguments defaulting to None. All existing orchestration blocks, environment mappings, metadata payloads, and progress streams remain 100% backward compatible and unaffected.

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (if needed) — Updated function signatures and tool schema definitions
  • Added/updated tests (if needed)
  • Security impact considered — Volume mounting isolation boundaries match upstream engine policies
  • Backward compatibility considered

Copilot AI review requested due to automatic review settings June 25, 2026 15:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the Python MCP sandbox server’s sandbox_create tool to expose host volume mounting by adding optional host_path and mount_path parameters, mapping them into native OpenSandbox Volume specs, and introducing an initial unit test for the MCP module.

Changes:

  • Added host_path and mount_path keyword-only parameters to sandbox_create and forwarded them as volumes to Sandbox.create.
  • Constructed a native opensandbox.models.sandboxes.Volume (Host bind mount) when both mount parameters are provided.
  • Added a new unit test to validate that sandbox_create passes the expected Volume configuration into the SDK call.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
sdks/mcp/sandbox/python/src/opensandbox_mcp/server.py Adds volume-mount parameters and translates them into an SDK volumes argument during sandbox creation.
sdks/mcp/sandbox/python/tests/test_server.py Adds a unit test ensuring volume parameters are wired into Sandbox.create as a native Volume spec.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +217 to +228
# Dynamically compile the volumes configuration using native SDK models
volumes = None
if host_path and mount_path:
from opensandbox.models.sandboxes import Host, Volume

volumes = [
Volume(
name="mcp-persistent-storage",
host=Host(path=host_path),
mountPath=mount_path,
)
]
@@ -0,0 +1,47 @@
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from opensandbox_mcp.server import create_server

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b9d7b6f9dd

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


# Dynamically compile the volumes configuration using native SDK models
volumes = None
if host_path and mount_path:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject incomplete volume mount inputs

When an MCP caller provides only one of the new mount fields, such as host_path without mount_path, this condition leaves volumes as None and still creates the sandbox successfully. That silently drops the requested host mount, so subsequent writes happen in the container filesystem instead of the intended persisted host path. Since these two fields are a required pair for a valid volume, partial or blank input should be rejected rather than ignored.

Useful? React with 👍 / 👎.

@candlelightner

Copy link
Copy Markdown
Author

⚠️ This PR has no labels. Please add one based on the changes.

Changed directories: sdks.

📋 Recommended labels (based on changed files):

* `sdks` ⬅️

Other available labels:

* `bug` - Something isn't working

* `dependencies` - Pull requests that update a dependency file

* `documentation` - Improvements or additions to documentation

* `feature` - New feature or request

* `packages` - Changes for package, image and configuration

💡 Tip: Use feature for new functionality or improvements, bug for fixes.

cc @candlelightner

I don't have repository write permissions to apply labels via the UI.

Could a maintainer please tag this with the feature and sdks labels? Thank you!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cbea46cad0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if (host_path is not None) != (mount_path is not None):
raise ValueError("Both 'host_path' and 'mount_path' must be provided together to enable persistence.")

if host_path and mount_path:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject empty mount parameters instead of ignoring them

The current None-pair check only fixes missing/null values; fresh evidence in this revision is that this truthiness guard still treats an explicitly supplied "" for either mount field as disabled and leaves volumes=None. In MCP clients that serialize blank optional strings instead of omitting them, sandbox_create succeeds without mounting the requested host path, so data is written to ephemeral container storage instead of the intended persistent host directory. Validate non-blank strings, or construct the Volume whenever both values are not None and let the SDK validators fail.

Useful? React with 👍 / 👎.

Comment on lines +149 to +150
host_path: str | None = None,
mount_path: str | None = None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Document the new mount parameters in MCP docs

This adds user-visible MCP inputs, but I checked docs/sdks/mcp.md and sdks/mcp/sandbox/python/README.md and neither mentions host_path/mount_path or the server allowed_host_paths prerequisite. The repo docs rules require updating docs/ for user-visible behavior, and without that users installing the MCP package only see sandbox_create listed generically, so the new persistence workflow is effectively undocumented outside the generated tool schema.

Useful? React with 👍 / 👎.

@Pangjiping Pangjiping added the feature New feature or request label Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants