Metadata-Version: 2.4
Name: webscope-mcp
Version: 0.5.1
Summary: MCP server (stdio, standard library only) that gives a coding agent short answers about a project
License-Expression: MIT
Project-URL: Repository, https://github.com/partprogramming09/webscope
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# Webscope

<!-- mcp-name: io.github.partprogramming09/webscope -->

A lightweight, token-efficient MCP server (stdio, JSON-RPC 2.0, Python standard library only). It provides coding agents with short, surgical answers: grouped search hits, isolated symbols instead of whole files, native in-browser testing on the user's open Chrome, and bounded project scripts.

Tool names, parameters, and messages are in English.

**Scope.** The core (`search`, `read`, `run`, `e2e_chrome`) works on any stack. The included adapters are Laravel-first: 16 of the 23 target Laravel, Laravel + Vue, or Vue. Astro, plain Python and other stacks get the core, the Astro map, and their own scripts declared in `webscope.json`.

---

## Quick Start

### 1. Initialize your project
Run in your project root to detect your stack (Laravel, Vue, Astro or Python get stack-specific scripts; anything else gets the generic core) and generate `webscope.json`:

```sh
# Via uvx (no install needed)
uvx webscope-mcp --init

# Or locally with Python
python3 webscope.py --init
```

### 2. Register with your MCP client

```sh
# Claude Code (recommended, writes project .mcp.json)
claude mcp add --scope project webscope -- uvx --from git+https://github.com/partprogramming09/webscope@v0.3.0 webscope-mcp --manifest "$PWD/webscope.json"

# With pip
pip install git+https://github.com/partprogramming09/webscope.git@v0.3.0
claude mcp add --scope project webscope -- webscope-mcp --manifest "$PWD/webscope.json"
```

Start `claude` and verify with `/mcp`: `webscope` will be connected with `search`, `read`, and `run`.

---

## Tools

| Tool | Description |
| :--- | :--- |
| `search(text, where?, limit?, format?, context?, regex?)` | Case-insensitive search grouped by file with relevance ranking. `format="concise"` returns top 5 files. Skips secrets (`.env`, `*.key`). |
| `read(file, symbol?, lines?, max_lines?, tail?, contains?, format?)` | Surgical read: extracts a single function, method, class (PHP, TS, JS, Vue, Python), Markdown section, line range, or log tail (`tail`). |
| `run(name?, args?, detail?)` | Runs a declared read-only script from the manifest. Output trimmed to head and tail limits. |
| `run_write(name, args)` | Runs scripts declared in `writes`. Requires `WEBSCOPE_WRITE=1` and interactive user confirmation. |

Every response starts with a one-line actionable guide and is capped at `token_limit` (~4 characters per token).

---

## In-Browser Testing & Chrome Connector (`e2e_chrome.py`)

Webscope includes an in-browser automation engine that replaces heavy screenshot-based tools with lightweight DOM extraction:

### Native Chrome Connector (`--evaluate`)
Operates directly on the developer's open Google Chrome window without opening clean/incognito profiles, preserving your active cookies, logins, and 2FA:

```sh
# Inspect current screen on active tab
python3 webscope_adapters/e2e_chrome.py --evaluate "window.__f.state()"

# Run on a tab matching a specific URL
python3 webscope_adapters/e2e_chrome.py --evaluate "window.__f.state()" "localhost:5173"

# Run a complete JS test flow
python3 webscope_adapters/e2e_chrome.py --evaluate test_flow.js "localhost:5173"
```

### Key Capabilities
- **Screen & Form Helpers (`__f`)**: Finds inputs by visible label, fills values, coordinates clicks with active settle wait (`calma()`), and verifies persistence.
- **Network Capture (`__e2e`)**: Intercepts `/api/` calls, latency (`ms`), and console errors without screenshots.
- **Self-Healing Across Reloads**: Injected helpers tolerate full page reloads (`window.location.reload()`) with automatic re-initialization.
- **Zero-Token Replay (`--replay <name>`)**: Replays recorded user flows in one call with 0 AI tokens.
- **Playwright Export (`--export <capture> <url>`)**: Converts recorded steps into clean `.spec.js` Playwright tests.

### The Essential Testing Contract: Full Lifecycle (CRUD + Sub-modules)
A module is **never considered tested** by merely reading a view or clicking a button. Webscope enforces a strict full-lifecycle standard:
1. **Create (C)**: Fill mandatory and conditional fields, submit, verify HTTP 200/201, and capture the generated record ID.
2. **Edit (U)**: Reopen the record, mutate fields, and verify data persistence in both UI and database.
3. **Exercise Sub-modules & Lifecycle**: Navigate sub-routes (`:id`), exercise child panels/tabs (e.g. characteristics, tariffs, pre-settlements, notes, print), and trigger state transitions (e.g. approve, reopen, duplicate).
4. **Delete & Clean (D)**: Delete the test record, confirm UI removal, and verify database clean state (`ZZ_E2E`).

---

## Configuration (`webscope.json`)

All behavior is project-contained. See [`webscope.example.json`](webscope.example.json).

```json
{
  "root": ".",
  "trim": { "head": 10, "tail": 70 },
  "token_limit": 5000,
  "storage": ".agents/webscope",
  "test_prefix": "ZZ_E2E",
  "search": { "dirs": ["src"], "extensions": ["ts", "vue", "php", "py"] },
  "allowed_env": ["DATABASE_URL"],
  "scripts": {
    "report": {
      "cmd": ["python3", "-I", "scripts/report.py"],
      "description": "Summarises a database table",
      "usage": "<table>",
      "rejects": ["--out"],
      "writes": ["--fix"],
      "timeout": 120
    }
  }
}
```

| Key | Description |
| :--- | :--- |
| `root` | Project root relative to manifest directory. |
| `extra_roots` | Folders outside `root`, relative to the manifest directory, that `search` and `read` may also read (for example a logs folder). Secret files stay blocked. |
| `token_limit` | Hard limit on response size in approximate tokens. |
| `trim` | Default head (`head`) and tail (`tail`) lines kept from script outputs. |
| `storage` | Internal storage for `module-map.json`, `flows/`, `walkthroughs/`. Autodetects `.agents/webscope/`, `.claude/webscope/`, or `.webscope/`. |
| `test_prefix` | Prefix for test entities (default `ZZ_E2E`). |
| `search.dirs`, `extensions` | Folders and extensions searched by default. |
| `allowed_env` | Environment variables passed to child scripts. |
| `scripts.<name>` | Fixed command list (`cmd`), `rejects` (blocked flags), `writes` (write flags). |

### The `project` section

The included adapters read the `project` section (container, boot code, module folders, frontends, audit settings…). Every key is optional and has a default. Each one is documented, with its default, who uses it and a minimal example, in [`docs/project.md`](docs/project.md).

Database adapters run inside a transaction that is rolled back. `sql` also puts the database session in read-only mode, so the database itself refuses writes. Only `cleanup_test_rows --delete --confirm` and `tinker --commit` (both behind `run_write`) commit.


---

## Included Adapters (`{adapters}`)

Ready-made scripts shipped in the package. Use `{adapters}` in `cmd`:

Grouped by the stack they need. The core tools (`search`, `read`, `run`) need none.

**Any stack**

| Script | Purpose |
| :--- | :--- |
| `e2e_chrome.py` | Browser walk, form automation (`__f`), replay, and open Chrome connector (`--evaluate`). Any SPA. |
| `triage.py` | Classifies failing pieces of a run summary as known, CHANGED or NEW (`project.known_failures`). |
| `session_cost.py` | Token and USD cost auditor per model for Claude Code sessions. |
| `agent_usage.py`, `webscope_usage.py`, `session_state.py` | Subagent usage, webscope usage and session bootstrap for Claude Code. |

**Laravel** (a database adapter needs `project.container` or `project.workdir`)

| Script | Purpose |
| :--- | :--- |
| `laravel.py` (`map_back`) | Resolves endpoint → controller → service → model → database table. |
| `tinker.py` | Runs PHP in `artisan tinker` inside a transaction rolled back unless `--commit`; `project.boot` prepares the connection. |
| `sql.py` | Read-only SQL (one SELECT/SHOW/DESCRIBE/EXPLAIN/WITH) through `tinker.py`, in a read-only database session; prints TSV with a header. |
| `fields.py` | Column sheet of a table: type, nullability, rows with a value, backend readers and writers. |
| `consumers.py` | Who reads and who writes a column: `file:line` in the backend (and `project.legacy`). |
| `unique_indexes.py` | Unique indexes on tables with a status column and whether the backend covers each (`project.status_columns`). |
| `tenant_queries.py` | `DB::` queries on tenant tables without an explicit connection (`project.tenant_tables`). |
| `snap.py` | Snapshot and diff of a query: what an on-screen action really wrote. |
| `db_check.php` | SELECT-only database integrity checks by prefix marker from `.env` (MySQL / Postgres). |
| `payload_check.py` | Compares captures against FormRequest rules, Resources, and columns. |
| `cleanup_test_rows.py` | Lists and safely cleans test rows matching the test prefix. |

**Laravel + Vue**

| Script | Purpose |
| :--- | :--- |
| `module_graph.py` (`graph`) | Screen → frontend module → endpoints → backend module → tables (`project.frontends`, `project.stores`). |
| `audit_types.py` | Crosses columns with FormRequest rules, Resource casts and frontend numeric conversions, with real data. |
| `simulate.py` | Lists what could break in a module from request, form and schema; `--out` writes the walk spec. |
| `changed.py` | Specs affected by uncommitted changes, resolved to screens (`project.repos`, `project.spec_files`). |

**Vue 3 + TS**: `vue_ts.py` (`map`) maps routes, subroutes, clickable actions, API calls and E2E coverage.
**Astro**: `astro.py` (`map_web`) maps file-based routes, components, form fields and client scripts.

---

## Subagents Integration

Webscope keeps subagents light. Two separate numbers:

- **The server itself** costs about 1.6k tokens per session (`tools/list` plus `instructions`, measured 2026-10-20 with a 26-script manifest and with the example manifest). It does not grow with the number of included adapters: they are not in `tools/list`; only the scripts your manifest declares add a short line to `instructions`.
- **A subagent** that declares `tools:` loads about 9.3k tokens at start, against 28.8k when it loads every tool and skill name (measured before the adapters grew from 8 to 20; the adapters are not part of that number).

### Exporting the `walkthrough` Agent
Export the ready-made walk agent without overwriting existing agents:

```sh
# Autodetects .agents/ or .claude/agents/
webscope-mcp --agent

# Or targeting a specific folder
webscope-mcp --agent [directory]
```

- **Non-destructive**: Never overwrites existing agent files unless `--force` is passed.
- **Isolation**: Leaves all other user-defined agents untouched.

### Declaring Tools in Agents
In your `.agents/<name>.md` or `.claude/agents/<name>.md`:
```yaml
---
name: navegador
tools: Read, Grep, Glob, mcp__webscope__search, mcp__webscope__read, mcp__webscope__run
model: sonnet
effort: high
---
```

---

## Configuration in Other Clients

### Claude Desktop (`claude_desktop_config.json`)
```json
{
  "mcpServers": {
    "webscope": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/partprogramming09/webscope@v0.3.0", "webscope-mcp", "--manifest", "/absolute/path/to/webscope.json"]
    }
  }
}
```

### Cursor / VS Code / Cline (`.cursor/mcp.json` or `.vscode/mcp.json`)
```json
{
  "mcpServers": {
    "webscope": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/partprogramming09/webscope@v0.3.0", "webscope-mcp", "--manifest", "${workspaceFolder}/webscope.json"]
    }
  }
}
```

### Zed (`settings.json`)
```json
{
  "context_servers": {
    "webscope": {
      "command": {
        "path": "uvx",
        "args": ["--from", "git+https://github.com/partprogramming09/webscope@v0.3.0", "webscope-mcp", "--manifest", "/absolute/path/to/webscope.json"]
      }
    }
  }
}
```

---

## Updating

```sh
# uvx: refresh package cache
uv cache clean webscope-mcp

# pip: force reinstall
pip install --upgrade --force-reinstall git+https://github.com/partprogramming09/webscope.git@v0.3.0
```

---

## Security Model

- **Root Sandbox**: `search` and `read` resolve strictly within `root` and reject outside paths.
- **Invisible Secrets**: Automatically hides `.env*`, `*.pem`, `*.key`, `*.p12`, `id_rsa*`, `id_ed25519*`, `auth.json`, and credentials.
- **No Shell Injection**: Scripts execute as fixed argument lists without intermediate shell.
- **Read-Only Default**: Destructive arguments (`writes`) require `run_write`, `WEBSCOPE_WRITE=1`, and explicit approval.
- **SQL guard (`sql.py`)**: a regex accepts one statement starting with SELECT, SHOW, DESCRIBE, DESC, EXPLAIN or WITH and rejects `;`. It is a convenience filter, not a parser: `WITH ... DELETE` passes it. The real guard is that the database session is read-only (`SET SESSION TRANSACTION READ ONLY` on MySQL/MariaDB, `default_transaction_read_only` on PostgreSQL, `query_only` on SQLite) inside a rolled-back transaction. Verified on MySQL: a `WITH ... DELETE` fails with «Cannot execute statement in a READ ONLY transaction». Not covered by rollback: file output such as `SELECT ... INTO OUTFILE`, locks and sleeps, PostgreSQL sequences and non-transactional engines. For a hard guarantee, connect with a database user that only has SELECT.
- **`tinker.py`** only runs PHP files from the system temp folder or the project's storage folder, never arbitrary project code.

### Recommended `.gitignore`
```gitignore
# Temporary Webscope artifacts
captures/
.webscope/captures/
```

Commit `webscope.json`, `.claude/webscope/walkthroughs/` (or `.agents/webscope/`), and `module-map.json`.

---

## Tests

```sh
python3 -I test_webscope.py
```

## License

[MIT](LICENSE)
