{"id":"92e93457-6a87-4468-aed1-7feacae9be3a","slug":"nyuwaymcpsandbox","kind":"mcp","name":"nyuwaymcpsandbox","summary":"Open-source behavioral sandbox for Model Context Protocol (MCP) servers. Detonate any MCP server in an isolated container, capture what it actually does at runtime, catch behaviours static analysis ca","owner":"Nyuway-Cybersecurity","repoUrl":"https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":4,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-05-27T09:31:42.000Z","addedAt":"2026-10-21T17:26:05.242Z","logoUrl":"https://avatars.githubusercontent.com/u/182913783?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["cloud-infra","memory-knowledge"],"tags":[],"runtime":"python","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-26T19:40:42.545Z","sample":false,"url":"https://conduits.dev/tools/nyuwaymcpsandbox","language":"Python","transports":["stdio"],"install":{"pypi":"nyuwaymcpsandbox"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# nyuwaymcpsandbox\n\n[![CI](https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/actions/workflows/ci.yml/badge.svg)](https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/actions/workflows/ci.yml) [![PyPI](https://img.shields.io/pypi/v/nyuwaymcpsandbox)](https://pypi.org/project/nyuwaymcpsandbox/) [![Downloads](https://static.pepy.tech/badge/nyuwaymcpsandbox)](https://pepy.tech/project/nyuwaymcpsandbox) [![Python](https://img.shields.io/pypi/pyversions/nyuwaymcpsandbox)](https://pypi.org/project/nyuwaymcpsandbox/) [![License](https://img.shields.io/badge/license-Apache%202.0-blue)](LICENSE) [![Tests](https://img.shields.io/badge/tests-513%20passing-brightgreen)](#) [![Rules](https://img.shields.io/badge/detection%20rules-9-blue)](#detection-rules) [![Status](https://img.shields.io/badge/status-v1.0.0%20stable-brightgreen)](#)\n\n**Open-source behavioral sandbox for Model Context Protocol (MCP) servers.**\n\nDetonate any MCP server in a controlled, instrumented environment. Watch what it actually does at runtime — every network call, file access, environment variable read, subprocess spawn, tool invocation, and timing-based stealth signal. Verifiable behavioral evidence, not inferred intent.\n\n## 🎬 Demo\n\nThe example below shows `nyuwaymcpsandbox` executing an MCP server inside an isolated sandbox and generating a behavioural security report.\n\n<p align=\"center\">\n  <img src=\"docs/images/nyuwaymcpsandbox-demo.gif\"\n       alt=\"Demo showing nyuwaymcpsandbox executing an MCP server inside an isolated sandbox and generating a behavioural security report.\">\n</p>\n\n```\n$ nyuwaymcpsandbox detonate pypi:mcp-server-git --mcp-command \"python -m mcp_server_git --repository .\"\n\nVerdict:  LOW  (score 20/100)              Duration: 00:02   Findings: 1\n| 00:02 | . | Tool 'git_status' invoked\n| 00:02 | X | Tool 'git_commit' invoked   [DETECTION: destructive_tool_invoked]\n| 00:02 | X | Tool 'git_reset'  invoked   [DETECTION: destructive_tool_invoked]\n```\n\n> **v1.0.0 — first stable release.** Core pipeline working end-to-end on Linux, macOS, and Windows (Docker Desktop + WSL2). **513 unit tests passing**, **9 bundled detection rules**, **14 public MCP servers detonated** across Docker and subprocess modes. See the [GitHub releases page](https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/releases) for release notes.\n\n---\n\n## Why a behavioral sandbox?\n\nStatic scanners read source code. They catch what code _looks like_, not what code _does_. A whole class of malicious MCP behavior is invisible to static analysis:\n\n- Runtime-triggered exfiltration that only fires on specific inputs\n- HTTPS-encrypted data theft to endpoints computed at runtime\n- Environment variable harvesting hidden inside otherwise benign-looking handlers\n- Subprocess hijacking with dynamically constructed commands\n- Tool poisoning that only manifests when a real LLM drives the server\n- Stealthy beacon-style startup behaviour that hides behind protocol silence\n- Destructive tool surfaces (`exec_in_pod`, `git_reset`, `kubectl_delete`) that look innocent in the source\n\nnyuwaymcpsandbox runs the server in isolation and **observes behaviour directly**. The output is not inference — it is evidence captured from the running process.\n\n---\n\n## How it fits in\n\nnyuwaymcpsandbox is the middle layer of the Nyuway MCP security trilogy:\n\n| Phase | Product | Question |\n|---|---|---|\n| Pre-deployment static | [nyuwaymcpscanner](https://github.com/Nyuway-Cybersecurity/nyuwaymcpscanner) | What does the code say this server does? |\n| Pre-deployment dynamic | **nyuwaymcpsandbox** | What does this server actually do when it runs? |\n| Production runtime | A2SP | How do I govern its behavior continuously in production? |\n\n---\n\n## Two scan modes\n\n| Mode | What runs | When to use |\n|---|---|---|\n| **`--mode fast`** | Deterministic harness only — container detonation, exercise every declared tool with synthesised inputs, capture all behaviour | CI pipelines, pre-deploy gates, no LLM cost |\n| **`--mode full`** | `fast` + a live LLM driver that probes the server with a curated adversarial prompt library | Tool-poisoning and prompt-injection-triggered behaviour the deterministic harness alone cannot surface |\n\n---\n\n## Quick start\n\n```bash\npip install nyuwaymcpsandbox\n\n# One-time setup: verify Docker, pull base images\nnyuwaymcpsandbox setup\n\n# Verify CLI plumbing without Docker (uses in-memory fakes)\nnyuwaymcpsandbox detonate ./my-server --dry-run\n\n# Fast mode against a real local Python MCP server (no Docker, no sandbox)\nnyuwaymcpsandbox detonate ./my-server \\\n  --mcp-transport subprocess \\\n  --mcp-command \"python server.py\"\n\n# Full mode inside the sandbox, with an LLM driver (Node.js server)\nnyuwaymcpsandbox detonate npm:@modelcontextprotocol/server-everything \\\n  --mode full \\\n  --mcp-transport docker \\\n  --mcp-command \"node dist/index.js\" \\\n  --llm groq/llama-3.3-70b-versatile\n\n# Full mode — browser-based MCP server (needs a playwright-capable image)\nnyuwaymcpsandbox detonate npm:@executeautomation/playwright-mcp-server \\\n  --mode full \\\n  --mcp-transport docker \\\n  --mcp-command \"node dist/index.js\" \\\n  --container-image \"mcr.microsoft.com/playwright:v1.57.0-noble\" \\\n  --llm groq/llama-3.3-70b-versatile\n\n# Full mode with Anthropic LLM\nnyuwaymcpsandbox detonate github:owner/repo \\\n  --mode full \\\n  --mcp-transport docker \\\n  --mcp-command \"python server.py\" \\\n  --llm claude-sonnet-4-5 \\\n  --api-key $ANTHROPIC_API_KEY\n\n# Air-gapped: local Ollama for the LLM driver\nnyuwaymcpsandbox detonate ./my-server --mode full --llm local\n\n# CI gate\nnyuwaymcpsandbox detonate ./server --mode fast --fail-on high --output sarif > results.sarif\n```\n\n---\n\n## See it in action\n\nReal findings from public MCP servers run through the sandbox. Both runs use `--mode fast` (no LLM), so the only signal is what the deterministic harness observed.\n\n### Example 1 — `mcp-server-git` flags state mutation\n\nRunning the official `pypi:mcp-server-git` server against this repository:\n\n```\n+----------------------------- nyuwaymcpsandbox - Behavioral Analysis ----------+\n|   Target:  pypi:mcp-server-git                                                |\n|     Mode:  fast                                                               |\n|  Verdict:  LOW  (score 20/100)                                                |\n| Duration:  00:02                                                              |\n| Findings:  1                                                                  |\n+-------------------------------------------------------------------------------+\n                               Behavioral Timeline\n+-------------------------------------------------------------------------------+\n|  Time |   | Event                                                             |\n|-------+---+-------------------------------------------------------------------|\n| 00:00 | . | Container started, MCP server listening                           |\n| 00:02 | . | MCP server listed tools                                           |\n| 00:02 | . | Tool 'git_status' invoked                                         |\n| 00:02 | . | Tool 'git_diff'   invoked                                         |\n| 00:02 | X | Tool 'git_commit' invoked   [DETECTION: destructive_tool_invoked] |\n| 00:02 | . | Tool 'git_add'    invoked                                         |\n| 00:02 | X | Tool 'git_reset'  invoked   [DETECTION: destructive_tool_invoked] |\n| 00:02 | . | Tool 'git_log'    invoked                                         |\n| 00:02 | . | Tool 'git_branch' invoked                                         |\n| 00:02 | . | Container stopped                                                 |\n+-------------------------------------------------------------------------------+\n| X | HIGH | destructive_tool_invoked | Destructive tool invoked by harness    |\n+-------------------------------------------------------------------------------+\n```\n\nThe server exposes 13 git tools. 11 are read-only and pass clean. `git_commit` and `git_reset` mutate repository state — the sandbox flags them so an operator can decide whether that capability is acceptable for the deployment context (a read-only RAG agent should never need write tools).\n\n### Example 2 — `mcp-server-kubernetes` reveals stealth startup\n\nThe Kubernetes MCP server spent **106 seconds silently retrying connections** to a K8s API server (sinkholed by the sandbox) before answering `tools/list`. The sandbox catches both the protocol-level stealth and the destructive tool surface:\n\n```\n+----------------------------- nyuwaymcpsandbox - Behavioral Analysis ----------+\n|   Target:  mcp-server-kubernetes                                              |\n|     Mode:  fast                                                               |\n|  Verdict:  LOW  (score 35/100)                                                |\n| Duration:  01:57                                                              |\n| Findings:  2                                                                  |\n+-------------------------------------------------------------------------------+\n| 00:00 | . | Container started                                                 |\n| 01:46 | . | MCP server listed tools                                           |\n| 01:46 | ! | Server delayed initialisation: 106.5s before tools/list           |\n|       |   |    [DETECTION: pre_tool_network_activity]                         |\n| 01:46 | X | Tool 'kubectl_apply'  invoked   [DETECTION: destructive_tool_…]   |\n| 01:46 | X | Tool 'kubectl_delete' invoked   [DETECTION: destructive_tool_…]   |\n| 01:47 | X | Tool 'exec_in_pod'    invoked   [DETECTION: destructive_tool_…]   |\n| ...\n+-------------------------------------------------------------------------------+\n| X | HIGH    | destructive_tool_invoked  | (×15 destructive tools)             |\n| ! | MEDIUM  | pre_tool_network_activity | Server delayed first MCP response   |\n+-------------------------------------------------------------------------------+\n```\n\nThe 106-second silent window is the protocol-level analogue of a C2 implant: long initial silence, then ordinary-looking traffic. In static analysis this is invisible — only a runtime sandbox surfaces it.\n\n### Example 3 — `mcp-server-time` (benign baseline)\n\nA boring server should look boring. Running `pypi:mcp-server-time`:\n\n```\n+----------------------------- nyuwaymcpsandbox - Behavioral Analysis ----------+\n|   Target:  pypi:mcp-server-time                                               |\n|  Verdict:  PASS  (score 0/100)                                                |\n| Findings:  0                                                                  |\n+-------------------------------------------------------------------------------+\n| 00:00 | . | Container started                                                 |\n| 00:01 | . | MCP server listed tools                                           |\n| 00:01 | . | Tool 'get_current_time' invoked                                   |\n| 00:01 | . | Tool 'convert_time'     invoked                                   |\n| 00:02 | . | Container stopped                                                 |\n+-------------------------------------------------------------------------------+\n| Deploy. No suspicious behaviour observed during detonation.                   |\n+-------------------------------------------------------------------------------+\n```\n\nNo findings, no false positives. The same rules that flagged `mcp-server-git` and `mcp-server-kubernetes` stay silent here.\n\n---\n\n## Targets\n\nPass any of these as the `TARGET` argument:\n\n| Form | Source |\n|---|---|\n| `./path/to/server` | local directory or file |\n| `github:owner/repo` (optional `@ref`) | GitHub tarball |\n| `npm:package` (optional `@version`) | npm registry |\n| `pypi:package` (optional `@version`) | PyPI (sdist preferred, wheel fallback) |\n\n---\n\n## MCP transports\n\n| Transport | When to use | Sandbox? |\n|---|---|---|\n| `--mcp-transport docker` (default) | Production: real isolation via `docker exec` inside the orchestrator's hardened container | yes |\n| `--mcp-transport subprocess` | Dev / protocol validation: server runs as a host subprocess (the same pattern the official MCP SDK uses) | no |\n\nBoth transports speak the same JSON-RPC 2.0 over stdio. Both go through the same downstream pipeline (capture monitors, detection rules, verdict, output).\n\n### Key flags\n\n| Flag | Default | Purpose |\n|---|---|---|\n| `--mcp-command` | _(required for docker transport)_ | Command run inside the container via `docker exec` |\n| `--mcp-arg` | — | Repeatable; passes args without shell parsing (safe for Windows paths) |\n| `--container-image` | auto-detected | Override the base image. Use for servers that need a non-default runtime (e.g. browser servers). Auto-wires browser-safe container settings. |\n| `--allow-network` | off | Grant real outbound egress (off by default; everything is sinkholed) |\n| `--mode fast\\|full` | `fast` | `fast` = deterministic harness only; `full` = adds LLM adversarial driver |\n| `--llm <model>` | _(required for full mode)_ | Any litellm model identifier, or `local` for Ollama |\n| `--fail-on low\\|medium\\|high\\|critical` | off | Non-zero exit when any finding meets or exceeds the threshold |\n| `--output timeline\\|json\\|sarif` | `timeline` | Output format |\n| `--dry-run` | off | Runs the pipeline with in-memory fakes — no Docker, MCP, or LLM needed |\n\n---\n\n## LLM backend (Full mode)\n\n`--llm` accepts any [litellm](https://docs.litellm.ai/) model identifier. Examples:\n\n| `--llm` value | Routes to |\n|---|---|\n| `claude-sonnet-4-5` | Anthropic (needs `ANTHROPIC_API_KEY`) |\n| `openai/gpt-4o` | OpenAI (needs `OPENAI_API_KEY`) |\n| `ollama/llama3` | Local Ollama daemon |\n| `local` | Alias for `ollama/llama3` (air-gapped default) |\n\nThe API key is picked up from the provider's standard env var unless `--api-key` is explicitly passed.\n\n---\n\n## What gets captured\n\nAll capture monitors run in parallel during the detonation. Each implements the same `Monitor` Protocol so the wiring is uniform.\n\n| Layer | Mechanism | What lands on the timeline |\n|---|---|---|\n| Container | `docker container.run` lifecycle | `container.started`, `container.stopped`, `container.error` |\n| MCP protocol | Real stdio JSON-RPC client | `mcp.tool_list`, `mcp.tool_invocation` (with `duration_seconds`, result summary, error) |\n| MCP timing signals | Harness-derived from tool-call latency | `mcp.delayed_initialization` (server stalled >=60s before `tools/list`), `mcp.slow_tool_response` (single call >=30s) |\n| Filesystem | watchdog (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows) | `filesystem.write`, `filesystem.delete` |\n| Process | `docker container.top()` polling | `process.spawn` (with argv + ppid), `process.exit` |\n| Network (DNS) | `tcpdump` sidecar in the target's network namespace | `network.dns_lookup` |\n| Environment | `sitecustomize.py` shim + `docker exec tail` (Python servers only in v1) | `environment.read` |\n| LLM driver (Full mode only) | litellm + adversarial prompt library | `llm.prompt_sent`, `llm.response_received` |\n\nEvery event is causally linked via `triggered_by` so detection rules can express patterns like \"outbound DNS lookup triggered by an MCP tool invocation triggered by an adversarial prompt.\"\n\n---\n\n## Detection rules\n\n9 bundled rules ship in `nyuwaymcpsandbox/detection/builtin/`:\n\n| Rule | Severity | Fires on |\n|---|---|---|\n| `shell_exec_in_tool` | HIGH | Subprocess spawn caused by an MCP tool invocation |\n| `outbound_network_from_tool` | HIGH | Any outbound network event caused by an MCP tool invocation |\n| `sensitive_file_read` | HIGH | MCP tool invocation whose name or arguments reference `/etc/passwd`, `/etc/shadow`, SSH keys, `~/.aws/credentials`, `~/.ssh/`, Windows credential paths |\n| `destructive_tool_invoked` | HIGH | MCP tool whose name matches a destructive verb (`git_commit`, `git_reset`, `kubectl_delete`, `kubectl_apply`, helm chart lifecycle, `exec_in_pod`, `drop_table`, `force_*`, `purge_*`, etc.) |\n| `credential_env_access` | MEDIUM | Read of an env var matching AWS_/AZURE_/GCP_/GITHUB_/OPENAI_/ANTHROPIC_/SLACK_/`*_SECRET`/`*_TOKEN`/`*_API_KEY` |\n| `suspicious_dns_tld` | MEDIUM | DNS lookup for a domain on `.tk`/`.gq`/`.ml`/`.cf`/`.xyz`/`.top`/`.click`/`.loan`/`.work` |\n| `file_write_outside_workdir` | MEDIUM | Write to `/etc`/`/usr`/`/var`/`/root`/`/home`/`/Users`/`/private`/`/Library`/Windows system paths caused by an MCP tool |\n| `pre_tool_network_activity` | MEDIUM | Server takes 60+ seconds to answer `tools/list` after the container is ready (suggests background network retries or beaconing during the silent window) |\n| `slow_tool_response` | LOW | A single MCP tool call takes 30+ seconds to return (reliability + DoS-vector signal) |\n\nRules are pure YAML, schema-validated, with both exact and regex payload matching plus dotted payload key paths. The two timing-based rules (`pre_tool_network_activity`, `slow_tool_response`) consume derived events the deterministic harness emits when it measures startup latency and per-call duration. See [`docs/detection-rules.md`](docs/detection-rules.md) (TBD) for the schema, or [`detection/rules.py`](nyuwaymcpsandbox/detection/rules.py) for the docstring.\n\n---\n\n## What this catches — and what it does not\n\nWe are deliberate about scope. A behavioral sandbox is one layer in a defence-in-depth strategy, not a silver bullet. This is what v1.0 covers honestly:\n\n### What v1.0 catches\n\n- **Subprocess execution** during tool invocations (`shell_exec_in_tool`)\n- **Outbound network calls** triggered by tools — DNS, TCP, HTTP, HTTPS — including to suspicious TLDs (`outbound_network_from_tool`, `suspicious_dns_tld`)\n- **Credential env-var reads** by Python MCP servers — AWS, Azure, GCP, GitHub, OpenAI, Anthropic, Slack, generic `*_SECRET`/`*_TOKEN`/`*_API_KEY` (`credential_env_access`)\n- **Sensitive file reads** when the tool name and arguments point at `/etc/passwd`, SSH keys, AWS credentials, Windows credential paths (`sensitive_file_read`)\n- **System path writes** outside the working directory (`file_write_outside_workdir`)\n- **Destructive tool surfaces** — git mutations, kubectl deletes/applies, helm chart lifecycle, `exec_in_pod`, database drops, `force_*`/`purge_*` verbs (`destructive_tool_invoked`)\n- **Stealth startup behaviour** — server takes 60+ seconds to answer `tools/list`, typically because it is retrying network connections you cannot see (`pre_tool_network_activity`)\n- **Hanging tool calls** — single tool invocation takes 30+ seconds (`slow_tool_response`)\n- **Tool-poisoning behavior under live LLM driving** (Full mode only) via an adversarial prompt library\n\n### What v1.0 does NOT catch (yet)\n\n- **Env-var reads by non-Python servers.** The `sitecustomize.py` shim only attaches to Python. Node, Go, and other-language servers bypass `credential_env_access`. Fix in v1.1: LD_PRELOAD-based `getenv` hook.\n- **Filesystem read events.** watchdog does not surface `IN_ACCESS` uniformly across platforms; only `write` and `delete` are captured today. A malicious server reading credentials but never writing or exfiltrating during the scan window is invisible. Fix in v1.1: in-container inotify watcher.\n- **In-container overlay writes.** The filesystem monitor watches the bind-mounted source on the host. Writes to the container's anonymous overlay (tmpfs, runtime state) are not seen.\n- **Full packet capture.** The current sidecar only logs DNS. HTTPS host headers, HTTP request lines, and connection metadata require the v1.1 NFQUEUE + scapy work.\n- **Multi-turn attacks.** The LLM driver is single-turn. Attacks that require a multi-turn conversation to manifest are out of scope until v2.0.\n- **Static code analysis.** This tool runs the server. To inspect the source without execution, use [nyuwaymcpscanner](https://github.com/Nyuway-Cybersecurity/nyuwaymcpscanner) — the static counterpart.\n- **Production runtime governance.** The sandbox is a pre-deployment gate. Continuous behavioural enforcement in production is the A2SP product (separate codebase).\n- **Python MCP servers in Docker mode.** Until v1.1 ships a PyPI install layer, Python servers run via subprocess transport (no NetworkMonitor / EnvironmentMonitor / FilesystemMonitor coverage). Node servers, browser-capable servers, and `--container-image` overrides work in full Docker mode today.\n\nA PASS verdict means **no rule fired against the captured timeline**. It does not mean the server is safe for every deployment context — only that, within the limits above, no malicious behaviour was observed.\n\nWhat's planned next is summarised in the [GitHub releases page](https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/releases) and tracked via GitHub issues.\n\n---\n\n## Verdicts\n\nScore = `min(100, max(sum_of_finding_weights, severity_floor))`. A single CRITICAL finding raises the score to at least 60 (HIGH minimum).\n\n| Verdict | Score range | Action |\n|---|---|---|\n| PASS | 0-19 | Deploy. No suspicious behaviour. |\n| LOW | 20-39 | Deploy with monitoring. |\n| MEDIUM | 40-59 | Review before deployment. |\n| HIGH | 60-79 | Block deployment. |\n| CRITICAL | 80-100 | Do not deploy. |\n\n---\n\n## Output formats\n\n```bash\n--output timeline   # Rich terminal view (default, ASCII-safe for cp1252 consoles)\n--output json       # Stable JSON schema for scripting / dashboards\n--output sarif      # SARIF 2.1.0 for GitHub Advanced Security / VS Code Problems / any SARIF-aware CI\n```\n\n`--fail-on low|medium|high|critical` returns a non-zero exit code when any finding meets or exceeds the threshold - drop-in for CI pipelines.\n\n---\n\n## Architecture\n\n```\nTARGET\n  └─ source resolver         (local / github: / npm: / pypi:)\n       └─ Docker orchestrator   (secure-by-default container)\n            └─ monitor session   (filesystem / process / network / env)\n                 └─ MCP client    (stdio over docker exec or subprocess)\n                      ├─ deterministic harness   (probe every tool)\n                      └─ LLM driver              (Full mode only)\n                 └─ detection engine            (YAML rules over timeline)\n                      └─ verdict + renderer     (timeline / JSON / SARIF)\n```\n\nEvery layer is an injection point - tests fake any boundary, `--dry-run` fakes the external ones (Docker, MCP, LLM) to exercise the rest of the pipeline.\n\n---\n\n## Security defaults\n\nEvery detonation runs the target in a container with:\n\n- `network_mode='none'` (sinkholed; only `--allow-network` opts in to real egress)\n- `read_only=True` root filesystem\n- `cap_drop=['ALL']` + `security_opt=['no-new-privileges:true']`\n- Resource caps: memory, CPU, pid count\n- Source mounted read-only at `/src`\n- Full destruction on session exit; nothing persists\n\n**Browser-capable containers** (`--container-image`): Chrome's startup process is incompatible with `read_only=True` and the default seccomp profile. When `--container-image` is set, the sandbox automatically adjusts to `read_only=False`, `seccomp=unconfined`, and `cap_add=SYS_PTRACE` while keeping network sinkholed, resource-capped, and destroyed on exit. The Docker container remains the outer isolation boundary.\n\n---\n\n## Requirements\n\n- Python 3.11+\n- Docker (Linux or macOS with Docker Desktop; Windows via WSL2). Optional - the `subprocess` MCP transport works without Docker.\n- An LLM API key (Full mode only) - any provider [litellm](https://docs.litellm.ai/) supports, or local Ollama for air-gapped runs.\n\n---\n\n## Contributing\n\nThis is an open security tool — community contributions move the threat coverage forward.\n\n- **New detection rules** — drop a YAML file into `nyuwaymcpsandbox/detection/builtin/`, add a unit test in `tests/test_detection_engine.py`, open a PR. See `detection/rules.py` for the schema.\n- **New adversarial prompts** — extend `nyuwaymcpsandbox/drivers/prompts/adversarial_library.yaml`. We currently cover ~2 of ~12 documented MCP/OWASP-Agentic attack vectors; PRs welcome.\n- **Real-world server reports** — file an issue with the server target, the detonation command, and the full timeline output. Findings against real public servers are how we discover new gaps (Phase 6 + Phase 7 in the activity log are entirely community-style testing turned into rules).\n- **Bug reports** — please include the rendered timeline (`--output timeline`) and the raw JSON (`--output json`).\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide (in progress).\n\n---\n\n## License\n\nApache 2.0. See [LICENSE](LICENSE).\n\n---\n\n## Links\n\n- Website: https://nyuway.ai\n- Static scanner: https://github.com/Nyuway-Cybersecurity/nyuwaymcpscanner\n- Issues: https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/issues\n- Releases: https://github.com/Nyuway-Cybersecurity/nyuwaymcpsandbox/releases\n"}