Skip to content
Merged
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Makefile for mcpbridge-wrapper

.PHONY: help install install-webui test test-webui lint format format-check typecheck doccheck doccheck-staged doccheck-branch doccheck-all doccheck-all-strict package-assets-check bump-version clean webui webui-health check
.PHONY: help install install-webui test test-webui lint format format-check typecheck doccheck doccheck-staged doccheck-branch doccheck-all doccheck-all-strict package-assets-check bump-version clean webui webui-restart webui-health check

help:
@echo "Available targets:"
Expand All @@ -20,6 +20,7 @@ help:
@echo " package-assets-check - Build artifacts and verify required packaged assets"
@echo " bump-version - Update pyproject.toml and server.json versions (VERSION=x.y.z, add DRY_RUN=1 to preview)"
@echo " webui - Start wrapper with Web UI dashboard (port 8080)"
@echo " webui-restart - Restart Web UI dashboard on chosen port (PORT=8080 by default)"
@echo " webui-health - Check Web UI health status"
@echo " clean - Clean build artifacts"
@echo " check - Run all quality gates (test, lint, format, typecheck, doccheck-all, package-assets-check)"
Expand Down Expand Up @@ -100,6 +101,11 @@ webui:
@echo "Press Ctrl+C to stop"
python -m mcpbridge_wrapper --web-ui --web-ui-port 8080

webui-restart:
@PORT_VALUE=$${PORT:-8080}; \
echo "Restarting Web UI on http://127.0.0.1:$$PORT_VALUE"; \
python -m mcpbridge_wrapper --web-ui-only --web-ui-restart --web-ui-port "$$PORT_VALUE"

webui-health:
@echo "Checking Web UI health..."
@curl -s http://localhost:8080/api/health | python -m json.tool 2>/dev/null || echo "Web UI not accessible at http://localhost:8080"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# PRD: FU-P11-T2-4 — Add one-command Web UI restart workflow

## Objective

Provide a single, reliable restart command for the Web UI server that works in local development and packaged/uvx usage. The restart flow must reclaim the selected port even when a stale listener exists, preferring graceful shutdown and using force-kill only when necessary.

## Deliverables

- CLI restart support in `src/mcpbridge_wrapper/__main__.py` (or delegated helper) that:
- Detects listeners on the target Web UI port
- Attempts graceful termination first
- Falls back to forceful termination when required
- Starts a fresh Web UI process using the existing startup path
- `Makefile` target `webui-restart` for one-command local restart
- Troubleshooting docs updates in:
- `docs/troubleshooting.md`
- `Sources/XcodeMCPWrapper/Documentation.docc/Troubleshooting.md`
- Automated tests for restart behavior and occupied-port edge cases

## Acceptance Criteria

- One documented command restarts Web UI on a chosen port without manual PID lookup.
- Restart flow performs graceful stop first and force-kills only if needed.
- Workflow works for both local/dev install and uvx usage.
- Tests cover restart behavior and practical port-occupied edge cases.

## Dependencies and Constraints

- Depends on `P11-T2` Web UI infrastructure.
- Keep compatibility with current CLI flags and startup flow.
- Avoid introducing platform-only behavior beyond existing macOS assumptions in this repo.

## Test-First Plan

1. Add/extend unit tests for restart helpers:
- Process lookup by port
- Graceful->forceful termination sequence
- No-op when no listener exists
2. Add CLI-level tests for restart command wiring.
3. Implement minimal code to satisfy tests.
4. Add/adjust docs and ensure examples are executable.

## Implementation Phases

### Phase 1: Restart primitives
- Inputs: target port, timeout, startup arguments
- Outputs: deterministic restart routine with logging/messages
- Verification: unit tests for success/fallback/failure handling

### Phase 2: CLI and Makefile integration
- Inputs: CLI argument parsing and existing web-ui commands
- Outputs: command/flag to restart + `make webui-restart`
- Verification: CLI tests and manual command dry-check

### Phase 3: Documentation and validation
- Inputs: final command syntax and expected behavior
- Outputs: troubleshooting docs updated in both markdown/docc
- Verification: command examples align across docs

## Validation Commands

- `pytest`
- `ruff check src/`
- `mypy src/`
- `pytest --cov=src/mcpbridge_wrapper --cov-report=term-missing`

## Notes

- Keep restart idempotent so repeated calls do not fail when no process is running.
- Reuse existing process management helpers if present instead of duplicating logic.

---
**Archived:** 2026-02-28
**Verdict:** PASS
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Validation Report: FU-P11-T2-4 — Add one-command Web UI restart workflow

**Date:** 2026-02-28
**Task ID:** FU-P11-T2-4
**Verdict:** PASS

## Scope Implemented

- Added `--web-ui-restart` CLI flag parsing.
- Implemented restart helpers to reclaim occupied Web UI ports:
- listener PID discovery via `lsof`
- graceful shutdown (`SIGTERM`) first
- force kill (`SIGKILL`) fallback when needed
- Wired restart behavior into Web UI startup flow in `main()`.
- Added `Makefile` target `webui-restart` with configurable `PORT`.
- Updated troubleshooting docs (markdown + DocC) with one-command restart workflow for local and uvx usage.
- Added/updated unit tests for parser changes, restart helpers, and main restart wiring.

## Quality Gates

- `PYTHONPATH=src pytest` → PASS (`668 passed, 5 skipped`)
- `PYTHONPATH=src ruff check src/` → PASS
- `PYTHONPATH=src mypy src/` → PASS
- `PYTHONPATH=src pytest --cov=src/mcpbridge_wrapper --cov-report=term-missing` → PASS
- Total coverage: **90.89%** (required: >= 90%)

## Acceptance Criteria Check

- [x] A single documented command restarts Web UI on a chosen port without manual PID hunting.
- [x] Restart flow attempts graceful stop first, then force-kill only if needed.
- [x] Works for both local/dev install and uvx usage.
- [x] Tests cover restart behavior and port-occupied edge case(s).

## Notes

- Port listener discovery relies on `lsof` availability (standard on macOS).
- Existing non-restart Web UI startup behavior is preserved.
4 changes: 3 additions & 1 deletion SPECS/ARCHIVE/INDEX.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# mcpbridge-wrapper Tasks Archive

**Last Updated:** 2026-02-28 (FU-P11-T2-3_Reorder_sessions_from_the_last_to_the_first)
**Last Updated:** 2026-02-28 (FU-P11-T2-4_Add_one-command_Web_UI_restart_workflow)

## Archived Tasks

| Task ID | Folder | Archived | Verdict |
|---------|--------|----------|---------|
| FU-P11-T2-4 | [FU-P11-T2-4_Add_one-command_Web_UI_restart_workflow/](FU-P11-T2-4_Add_one-command_Web_UI_restart_workflow/) | 2026-02-28 | PASS |
| FU-P11-T2-3 | [FU-P11-T2-3_Reorder_sessions_from_the_last_to_the_first/](FU-P11-T2-3_Reorder_sessions_from_the_last_to_the_first/) | 2026-02-28 | PASS |
| BUG-T18 | [BUG-T18_Error_Breakdown_full_width_layout_fix/](BUG-T18_Error_Breakdown_full_width_layout_fix/) | 2026-02-26 | PASS |
| BUG-T9 | [BUG-T9_Orphaned_Web_UI_server_process_blocks_port_after_MCP_client_disconnect_or_config_change/](BUG-T9_Orphaned_Web_UI_server_process_blocks_port_after_MCP_client_disconnect_or_config_change/) | 2026-02-25 | PASS |
Expand Down Expand Up @@ -212,6 +213,7 @@
| [REVIEW_P12-T3_error_classification_categorization.md](P12-T3_Add_Error_Classification_and_Categorization/REVIEW_P12-T3_error_classification_categorization.md) | Review report for P12-T3 |
| [REVIEW_P12-T4_data_storage_documentation.md](P12-T4_Add_documentation_about_data_storage/REVIEW_P12-T4_data_storage_documentation.md) | Review report for P12-T4 |
| [REVIEW_P12-T2_param_frequency_analysis.md](P12-T2_Add_Tool_Parameter_Frequency_Analysis/REVIEW_P12-T2_param_frequency_analysis.md) | Review report for P12-T2 |
| [REVIEW_fu-p11-t2-4-restart-workflow.md](_Historical/REVIEW_fu-p11-t2-4-restart-workflow.md) | Review report for FU-P11-T2-4 |
| [REVIEW_fu_p11_t2_3_session_ordering.md](_Historical/REVIEW_fu_p11_t2_3_session_ordering.md) | Review report for FU-P11-T2-3 |
| [REVIEW_FU-P11-T2-2_limit_query_param.md](_Historical/REVIEW_FU-P11-T2-2_limit_query_param.md) | Review report for FU-P11-T2-2 |
| [REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor.md](_Historical/REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor.md) | Review report for FU-P11-T1-1 |
Expand Down
32 changes: 32 additions & 0 deletions SPECS/ARCHIVE/_Historical/REVIEW_fu-p11-t2-4-restart-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## REVIEW REPORT — FU-P11-T2-4 restart workflow

**Scope:** origin/main..HEAD
**Files:** 10

### Summary Verdict
- [x] Approve
- [ ] Approve with comments
- [ ] Request changes
- [ ] Block

### Critical Issues
- None.

### Secondary Issues
- [Low] `lsof` dependency is macOS-standard in this repository context; behavior remains deterministic when unavailable (restart helper no-ops), and tests cover fallback paths.

### Architectural Notes
- Restart logic is isolated into helpers (`_find_listener_pids_for_port`, `_terminate_pids_gracefully_then_force`, `_restart_webui_listener`) to keep `main()` readable and testable.
- Existing non-restart startup behavior remains unchanged.

### Tests
- Quality gates executed and passing:
- `PYTHONPATH=src pytest`
- `PYTHONPATH=src ruff check src/`
- `PYTHONPATH=src mypy src/`
- `PYTHONPATH=src pytest --cov=src/mcpbridge_wrapper --cov-report=term-missing`
- Coverage remains >= 90%: 90.89%.

### Next Steps
- No actionable follow-up tasks identified.
- FOLLOW-UP step can be skipped for this task.
2 changes: 1 addition & 1 deletion SPECS/INPROGRESS/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Recently Archived

- **FU-P11-T2-4** — Add one-command Web UI restart workflow (2026-02-28, PASS)
- **FU-P11-T2-3** — Reorder sessions from the last to the first (2026-02-28, PASS)
- **BUG-T9** — Orphaned Web UI server process blocks port after MCP client disconnect or config change (2026-02-25, PASS)
- **BUG-T18** — Error Breakdown widget must be full width streatched (2026-02-26, PASS)

## Suggested Next Tasks

Expand Down
2 changes: 1 addition & 1 deletion SPECS/Workplan.md
Original file line number Diff line number Diff line change
Expand Up @@ -2097,7 +2097,7 @@ Phase 9 Follow-up Backlog

---

#### ⬜️ FU-P11-T2-4: Add one-command Web UI restart workflow
#### FU-P11-T2-4: Add one-command Web UI restart workflow
- **Description:** Add a simple restart workflow for developers and users that reliably frees the configured Web UI port and starts a fresh dashboard process after updates.
- **Priority:** P2
- **Dependencies:** P11-T2
Expand Down
19 changes: 10 additions & 9 deletions Sources/XcodeMCPWrapper/Documentation.docc/Troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,20 +225,21 @@ Error: Web UI port 8080 is already in use. Stop the existing process and retry.

**Cause:** A stale wrapper process from a previous run (or a crashed client restart) is still occupying the port. Multiple processes can exist simultaneously — for example after a Cursor restart — because the old process is never explicitly stopped.

**Diagnosis:**
**One-command restart (recommended):**

```bash
# Find the PID of the process listening on the Web UI port (default 8080)
PORT=8080
lsof -i TCP:$PORT -sTCP:LISTEN
# Local development (from repo root)
make webui-restart PORT=8080
```

# Alternatively, search by process name
ps aux | grep mcpbridge
```bash
# uvx usage
uvx --from 'mcpbridge-wrapper[webui]' mcpbridge-wrapper --web-ui-only --web-ui-restart --web-ui-port 8080
```

Both commands show the PID in the second column (`PID`).
The restart flow attempts graceful shutdown first (`SIGTERM`) and only uses force-kill (`SIGKILL`) for listeners that do not exit in time.

**Recovery:**
**Manual fallback (if needed):**

```bash
# Kill the listener bound to the port
Expand All @@ -257,7 +258,7 @@ pkill -f -i "mcpbridge_wrapper --web-ui" || true
lsof -nP -iTCP:$PORT -sTCP:LISTEN
```

After stopping the stale process, restart your MCP client (Cursor / Zed / Claude Code) or re-run the `--web-ui-only` command and the port should now be free.
After stopping the stale process, restart your MCP client (Cursor / Zed / Claude Code) or rerun one of the restart commands above.
Prefer `kill` (`SIGTERM`) first; use `kill -9` only when the process does not exit.

**Note:** Multiple wrapper processes can run simultaneously on *different* ports. Make sure you identify the PID bound specifically to the port you want, not just any `mcpbridge` process. If the port is immediately re-occupied, close/restart MCP clients (Cursor/Zed/Claude) that may auto-spawn a new wrapper process.
Expand Down
19 changes: 10 additions & 9 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,20 +259,21 @@ Error: Web UI port 8080 is already in use. Stop the existing process and retry.

**Cause:** A stale wrapper process from a previous run (or a crashed client restart) is still occupying the port. Multiple processes can exist simultaneously — for example after a Cursor restart — because the old process is never explicitly stopped.

**Diagnosis:**
**One-command restart (recommended):**

```bash
# Find the PID of the process listening on the Web UI port (default 8080)
PORT=8080
lsof -i TCP:$PORT -sTCP:LISTEN
# Local development (from repo root)
make webui-restart PORT=8080
```

# Alternatively, search by process name
ps aux | grep mcpbridge
```bash
# uvx usage
uvx --from 'mcpbridge-wrapper[webui]' mcpbridge-wrapper --web-ui-only --web-ui-restart --web-ui-port 8080
```

Both commands show the PID in the second column (`PID`).
The restart flow attempts graceful shutdown first (`SIGTERM`) and only uses force-kill (`SIGKILL`) for listeners that do not exit in time.

**Recovery:**
**Manual fallback (if needed):**

```bash
# Kill the listener bound to the port
Expand All @@ -291,7 +292,7 @@ pkill -f -i "mcpbridge_wrapper --web-ui" || true
lsof -nP -iTCP:$PORT -sTCP:LISTEN
```

After stopping the stale process, restart your MCP client (Cursor / Zed / Claude Code) or re-run the `--web-ui-only` command and the port should now be free.
After stopping the stale process, restart your MCP client (Cursor / Zed / Claude Code) or rerun one of the restart commands above.
Prefer `kill` (`SIGTERM`) first; use `kill -9` only when the process does not exit.

**Note:** Multiple wrapper processes can run simultaneously on *different* ports. Make sure you identify the PID bound specifically to the port you want, not just any `mcpbridge` process. If the port is immediately re-occupied, close/restart MCP clients (Cursor/Zed/Claude) that may auto-spawn a new wrapper process.
Expand Down
Loading