Metadata-Version: 2.4
Name: scry-connect
Version: 0.1.0
Summary: MCP server for ROS 2 — exposes robot capabilities as AI-callable tools
Project-URL: Homepage, https://github.com/phaneron-robotics/scry
Project-URL: Documentation, https://phaneron-robotics.github.io/scry-docs/
Project-URL: Repository, https://github.com/phaneron-robotics/scry-connect
Project-URL: Issues, https://github.com/phaneron-robotics/scry-connect/issues
Project-URL: Changelog, https://github.com/phaneron-robotics/scry-connect/blob/master/CHANGELOG.md
Author-email: "Phaneron Robotics, Inc." <info@phaneronrobotics.com>
Maintainer-email: Deep Kotadiya <deep@phaneronrobotics.com>
License: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Keywords: agent,ai,debugging,fleet,introspection,mcp,rclpy,robotics,ros2
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: System :: Networking
Classifier: Typing :: Typed
Requires-Dist: mcp>=1.0.0
Requires-Dist: qrcode>=7.4
Requires-Dist: sse-starlette>=1.8.0
Requires-Dist: starlette>=0.36.0
Requires-Dist: uvicorn>=0.27.0
Requires-Dist: zeroconf>=0.131
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: pre-commit>=3.6.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.2.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# scry-connect

MCP server for ROS 2 — exposes your robot's topics, nodes, services, parameters, actions, diagnostics, and introspection tools to AI agents.

Pairs with the Scry Android app.

## Install

Pick the path that matches how your robot is deployed. All three install
the same `scry-connect` from PyPI — they just package it differently.

### Option A — one-line installer (Docker or bare-metal, auto-detect)

```bash
curl -fsSL https://raw.githubusercontent.com/phaneron-robotics/scry-connect/master/install.sh | bash
```

The script detects your ROS distro, picks Docker if available else pip,
writes a systemd `--user` unit, starts the service, and prints a
pairing QR. Re-running upgrades in place. Mode override:
`SCRY_INSTALL_MODE=docker bash` or `SCRY_INSTALL_MODE=pip bash`.

### Option B — sidecar Docker container

Drop into your existing `docker-compose.yml`:

```yaml
services:
  scry-connect:
    image: ghcr.io/phaneron-robotics/scry-connect:${ROS_DISTRO:-jazzy}
    network_mode: host
    ipc: host
    pid: host
    restart: unless-stopped
    environment:
      - ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-0}
    volumes:
      - scry_config:/home/scry/.config/scry
      - scry_audit:/var/log/scry

volumes:
  scry_config:
  scry_audit:
```

A turnkey reference compose with every tunable surfaced lives at
[docker/docker-compose.yml](docker/docker-compose.yml).

| Tag | Resolves to |
|-----|------|
| `:humble`, `:jazzy`, `:kilted`, `:rolling` | Per-ROS-distro images (multi-arch: amd64 + arm64) |
| `:0.1.0-jazzy` | Pinned version on jazzy |
| `:latest` | Most recent stable release on the LTS distro (jazzy today) |

### Option C — add scry-connect to your own robot image

If you already publish a robot Docker image, append one line to your
Dockerfile and run `scry-connect` alongside your existing nodes:

```dockerfile
RUN pip install scry-connect
```

No second ROS install required — `scry-connect` uses the `rclpy`
that's already in your image.

### Option D — bare-metal pip (no Docker)

```bash
source /opt/ros/$ROS_DISTRO/setup.bash
pip install --user scry-connect
scry-connect
```

A reference [systemd user unit](install.sh) is written automatically
by Option A in pip mode.

Prereleases (alpha / beta / rc) live on TestPyPI:

```bash
pip install -i https://test.pypi.org/simple/ scry-connect
```

## Run

```bash
# Defaults to 0.0.0.0:5339 in open mode (LAN-only, no token).
scry-connect

# Common overrides
scry-connect --port 5339 --log-level INFO
scry-connect --token              # token mode; prints QR for the phone
scry-connect --mtls               # client-cert mode
scry-connect --skip-ros-check     # smoke test without rclpy
```

## Endpoints

| Path | Method | Description |
|------|--------|-------------|
| `/mcp` | POST/GET | MCP JSON-RPC (Streamable HTTP) |
| `/stream?topic=/odom&rate=10` | GET | SSE topic stream |
| `/health` | GET | Health check |

## Tools exposed

22 tools grouped into: Topics, Nodes, Services, Parameters, Actions, Diagnostics, Logs, Introspection, System. See [docs/mcp-tools-reference.md](../docs/mcp-tools-reference.md).

## Config (env vars)

| Variable | Default | Description |
|----------|---------|-------------|
| `SCRY_HOST` | `0.0.0.0` | Bind address |
| `SCRY_PORT` | `5339` | HTTP port |
| `SCRY_RATE_LIMIT` | `10` | Tool calls per second |
| `SCRY_LOG_LEVEL` | `INFO` | Log level |
| `SCRY_AUTH_MODE` | `open` | `open` \| `token` \| `mtls` |
| `SCRY_TOKEN` | (unset) | Force token mode with this shared token |
| `SCRY_PUBLIC_INTERNET` | `0` | In open mode, accept non-LAN callers |
| `SCRY_REQUIRE_DEADMAN` | `0` | Writes need `/scry/enable` heartbeat |
| `SCRY_AUDIT_LOG` | (unset) | Append JSONL audit trail to this path |
| `SCRY_MDNS` | `1` | Advertise `_scry._tcp` via Zeroconf |
| `ROS_DOMAIN_ID` | (inherited) | ROS 2 domain ID |
| `RMW_IMPLEMENTATION` | (inherited) | DDS/RMW implementation |

## Development

### Setup

```bash
# Editable install + dev dependencies
pip install -e ".[dev]"

# Install pre-commit hooks (run once per fresh clone)
pip install pre-commit
pre-commit install
```

After `pre-commit install`, every `git commit` automatically runs `ruff`
(auto-fix) + `ruff format` on the staged Python files. If anything was
fixed, the commit is rejected — `git add` the fixes and commit again.

### Manual lint commands

```bash
# Run pre-commit against every file (not just staged)
pre-commit run --all-files

# Run ruff directly
ruff check scry_connect tests          # report issues
ruff check --fix scry_connect tests    # auto-fix what can be fixed
ruff format scry_connect tests         # apply formatter
```

### Tests

```bash
pytest tests/
```

Note: many tests require a working ROS 2 environment (rclpy). In CI we
only run lint + build; tests run on a real robot or local ROS 2 install.

### CI / release pipeline

| Workflow | Trigger | What it does |
|----------|---------|--------------|
| **CI** | PR to master, push to master, manual | ruff check + format check, `python -m build` (sdist + wheel) |
| **Release** | Tag matching `v*`, manual | Build, publish to PyPI / TestPyPI (Trusted Publishing — no API key needed), push to `ghcr.io/phaneron-robotics/scry-connect`, create GitHub Release |
| **Dependency Graph** | Auto-managed | Tracks third-party deps for security alerts |

To cut a release: bump `version` in `pyproject.toml`, merge the bump PR,
then tag the merge commit. Prerelease tags (`v0.1.0-beta.1`) route to
TestPyPI + a prerelease GitHub Release. Stable tags (`v0.1.0`) route
to PyPI proper and the Docker image gets the `latest` tag.

See [docs/PYPI_SETUP.md](docs/PYPI_SETUP.md) for the one-time PyPI
Trusted Publishing setup.
