# SME External Terminal MCP Server

Minimal Model Context Protocol (MCP) server exposing controlled access to
local shell execution. Suited for internal automation and experimentation.

## Provided Tools

| Tool | Purpose | Return Shape |
|------|---------|--------------|
| `list_shells` | Enumerate allowed shell executables detected on host | `{ "value": ["/bin/sh", ...] }` |
| `execute_command` | Run a command via a chosen shell and capture stdout | `{ "value": "<stdout>" }` or `{ "error": "..." }` |

Both tools return explicit `{ "error": str }` objects on failure; exceptions
are avoided so MCP clients receive structured responses.

## Project Layout

```text
src/
  sme_external_terminal_mcp_server/
    __init__.py
    main.py              # launcher
    auth_utils.py        # authentication utilities
    config.py            # configuration management
tests/                   # unit tests (tools + internals)
```

## ⚙️ Key Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `USE_STREAMABLE_HTTP` | `false` | If `true`, run an HTTP server; else stdio transport |
| `HTTP_PORT` | `4100` | Port used when HTTP mode is enabled |
| `TOKEN_FIELD` | `SOME_TOKEN` | Env var name looked up for auth secret |
| `REQUIRE_TOKEN` | `true` | If true, every tool call must authenticate |
| `<TOKEN_FIELD>` | (unset) | Actual secret value (e.g. `SOME_TOKEN=...`) |

Place them in `.env` (auto‑loaded) or export in your shell. Changing
`TOKEN_FIELD` lets you rotate the env var name without code edits.

## 🚀 Quick Start

```bash
# Install dependencies (creates/uses .venv)
uv sync

# Configure auth (optional if REQUIRE_TOKEN=false)
cp .env.shadow .env && $EDITOR .env   # set SOME_TOKEN=<secret>

# Run in stdio mode
uv run sme_external_terminal_mcp_server

# Run in HTTP mode (debug-friendly)
USE_STREAMABLE_HTTP=true HTTP_PORT=4100 uv run sme_external_terminal_mcp_server
```

### Calling the Tools (example JSON for an MCP client)

**Most clients will handle this for you. But this is the contract.....**

`list_shells`:

```json
{ "method": "tools/call", "params": { "name": "list_shells", "arguments": {} } }
```

`execute_command`:

```json
{ "method": "tools/call", "params": { "name": "execute_command", "arguments": { "shell_path": "/bin/sh", "command": "echo hi" } } }
```

## 🧪 Development & Testing

```bash
uv sync --group dev            # install with test deps
uv run pytest -q               # run tests
uv run pytest --cov=src -vv    # with coverage detail
uv build                       # build wheel & sdist
```

### Adding a Tool

Follow the existing pattern in `main.py`:

```python
@mcp.tool(description="Short summary", annotations={"arg1": "Help text"})
def my_new_tool(arg1: str, ctx=None):
  # logic
  return {"value": "ok"}
```
Keep return values JSON‑serializable. Use `ctx` for interactive prompts or
request metadata (e.g., headers in HTTP mode).

## 🔀 Transport Modes

The MPC server can run in two transport modes.

| Mode | How to Enable | Typical Use | Pros | Considerations |
|------|---------------|-------------|------|----------------|
| stdio (default) | Do nothing (env var unset / false) | Embedding in tools that expect MCP over stdio pipes | Simplest, no open port, good for scripting | Harder to live‑debug without extra tooling |
| streamable HTTP | `export USE_STREAMABLE_HTTP=true` (optional `HTTP_PORT`) | Local development with an IDE / remote access | Live debugging: set breakpoints, inspect stack & variables; easier network inspection | Opens a TCP port; add auth / firewall for shared environments |

### Debugging Benefits (HTTP Mode)

* Attach an IDE debugger (breakpoints enabled and persistent across requests).
* Inspect stacks & locals while a client request awaits.
* Restart clients without restarting the server process.

## 📦 Packaging / Publish

```bash
rm -rf dist build
uv build
twine upload dist/*
# or internal index
twine upload --repository-url https://pypi.theorchard.io dist/*
```

## 🛡 Security & Safety

* Never run destructive commands in tests or examples.
* `REQUIRE_TOKEN=true` in production environments.
* Rotate the token (`<TOKEN_FIELD>`) regularly; treat as secret.
* Banned patterns (regex, case‑insensitive) block obviously dangerous
  operations (e.g., recursive delete, shutdown). Extend `BANNED_COMMANDS`
  if needed.
* All unsafe execution failures return `{ "error": "..." }` (no raw tracebacks).

## 🤝 Contributing

Internal / experimental; open a PR or adapt privately.

### License

This repository and its packages are licensed as
**Proprietary - Private Commercial License. All rights reserved.**
See the `LICENSE` file for details.

---

Happy building — extend & keep it lean.
