Update README.md
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Turnstone MCP Server
|
# Turnstone MCP Server
|
||||||
|
|
||||||
A [Model Context Protocol](https://modelcontextprotocol.io/) server providing four sandboxed tools for LLM-driven workflows. Built with **FastMCP** and **Playwright**, it exposes code execution, headless browser automation, and file-to-Markdown conversion over HTTP.
|
A [Model Context Protocol](https://modelcontextprotocol.io/) server providing five sandboxed tools for LLM-driven workflows. Built with **FastMCP** and **Playwright**, it exposes code execution, headless browser automation, file-to-Markdown conversion, and ephemeral file downloads over HTTP.
|
||||||
|
|
||||||
Designed to run as a Docker container alongside the Turnstone platform, sharing the `turnstone_workspace` volume so tools can read and write files that other services in the ecosystem use.
|
Designed to run as a Docker container alongside the Turnstone platform, sharing the `turnstone_workspace` volume so tools can read and write files that other services in the ecosystem use.
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ Designed to run as a Docker container alongside the Turnstone platform, sharing
|
|||||||
| `playwright_navigate` | Navigates a persistent headless Chromium session to a URL |
|
| `playwright_navigate` | Navigates a persistent headless Chromium session to a URL |
|
||||||
| `playwright_get_page_text` | Extracts rendered text from the current browser page |
|
| `playwright_get_page_text` | Extracts rendered text from the current browser page |
|
||||||
| `extract_to_markdown` | Converts supported files (PDF, DOCX, images, CSV, etc.) to Markdown via `markitdown` |
|
| `extract_to_markdown` | Converts supported files (PDF, DOCX, images, CSV, etc.) to Markdown via `markitdown` |
|
||||||
|
| `generate_download_link` | Creates a single-use, time-limited HTTPS download URL for a file in `/workspace` |
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@ All limits are configurable via environment variables with sensible defaults. Se
|
|||||||
| `PLAYWRIGHT_NAV_TIMEOUT` | `30000` | Browser navigation timeout (ms) |
|
| `PLAYWRIGHT_NAV_TIMEOUT` | `30000` | Browser navigation timeout (ms) |
|
||||||
| `PLAYWRIGHT_TEXT_TIMEOUT` | `15000` | Page text extraction timeout (ms) |
|
| `PLAYWRIGHT_TEXT_TIMEOUT` | `15000` | Page text extraction timeout (ms) |
|
||||||
| `EXTRACT_MAX_FILE_SIZE` | `10485760` | Maximum file size for extraction (10 MB) |
|
| `EXTRACT_MAX_FILE_SIZE` | `10485760` | Maximum file size for extraction (10 MB) |
|
||||||
| `WORKSPACE_MOUNT` | `workspace` | Docker volume name for the shared workspace |
|
| `PUBLIC_BASE_URL` | `http://localhost:8000` | Public HTTPS base URL for ephemeral download links |
|
||||||
|
| `WORKSPACE_MOUNT` | `/workspace` | Absolute path to the shared workspace root (used as the Docker volume name in `compose.yaml`) |
|
||||||
|
|
||||||
Example with custom limits:
|
Example with custom limits:
|
||||||
|
|
||||||
@@ -76,11 +78,26 @@ PYTHON_EXEC_TIMEOUT=60 PYTHON_MAX_MEMORY_MB=512 docker compose up --build
|
|||||||
|
|
||||||
- **Persistent browser session** — A singleton `PlaywrightBrowserManager` holds the Chromium process alive across tool calls, preventing garbage-collection teardowns.
|
- **Persistent browser session** — A singleton `PlaywrightBrowserManager` holds the Chromium process alive across tool calls, preventing garbage-collection teardowns.
|
||||||
- **Sandboxed execution** — Python code runs in a separate process with a per-subprocess memory limit (`resource.setrlimit`) and a wall-clock timeout enforced by `subprocess.run`.
|
- **Sandboxed execution** — Python code runs in a separate process with a per-subprocess memory limit (`resource.setrlimit`) and a wall-clock timeout enforced by `subprocess.run`.
|
||||||
- **Path traversal protection** — `extract_to_markdown` resolves all paths against `WORKSPACE_ROOT` and rejects anything that escapes it.
|
- **Path traversal protection** — `extract_to_markdown` and `generate_download_link` resolve all paths against `WORKSPACE_MOUNT` and reject anything that escapes it.
|
||||||
|
- **Ephemeral download links** — `generate_download_link` mints a 256-bit single-use token linked to a file path; clicking the URL streams the file and immediately invalidates the token. Expired tokens are garbage-collected automatically.
|
||||||
- **Structured JSON logging** — All tool invocations and responses are logged as structured JSON for observability.
|
- **Structured JSON logging** — All tool invocations and responses are logged as structured JSON for observability.
|
||||||
- **CORS enabled** — The server accepts requests from any origin with standard MCP headers.
|
- **CORS enabled** — The server accepts requests from any origin with standard MCP headers.
|
||||||
- **Shared workspace volume** — The container mounts the `turnstone_workspace` Docker volume at `/workspace`, giving the MCP tools read/write access to files used by other Turnstone services.
|
- **Shared workspace volume** — The container mounts the `turnstone_workspace` Docker volume at `/workspace`, giving the MCP tools read/write access to files used by other Turnstone services.
|
||||||
|
|
||||||
|
## Credential Leak Guardrail — Action Required
|
||||||
|
|
||||||
|
The Turnstone credential leak guardrail intercepts outbound messages and flags URLs it considers suspicious. Because `generate_download_link` returns a URL containing a token, the guardrail will block it unless a policy explicitly allows the pattern.
|
||||||
|
|
||||||
|
> **Action:** Add the following pattern to the Turnstone credential leak policy:
|
||||||
|
>
|
||||||
|
> ```
|
||||||
|
> PUBLIC_BASE_URL/download?
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Replace `PUBLIC_BASE_URL` with the actual value of the environment variable (e.g., `https://turnstone.example.com/download?`).
|
||||||
|
|
||||||
|
Without this policy, any attempt by the agent to present a download link to the user will be silently blocked by the credential leak filter.
|
||||||
|
|
||||||
## Docker Configuration
|
## Docker Configuration
|
||||||
|
|
||||||
The service is defined in `compose.yaml`:
|
The service is defined in `compose.yaml`:
|
||||||
@@ -99,6 +116,7 @@ The service is defined in `compose.yaml`:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `POST` | `/` | MCP protocol endpoint (default) |
|
| `POST` | `/` | MCP protocol endpoint (default) |
|
||||||
| `GET` | `/health` | Returns `{"status": "healthy", "service": "turnstone-mcp"}` |
|
| `GET` | `/health` | Returns `{"status": "healthy", "service": "turnstone-mcp"}` |
|
||||||
|
| `GET` | `/download?token=` | Streams a file identified by a single-use token (see `generate_download_link` tool) |
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user