Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ All notable changes to ReqLab are documented here.

---

## [1.18.0] — 2026-08-29

### Added

- **MCP client**: saved MCP connections as first-class collection/tab items. Connect over Streamable HTTP (2025-06-18, stateful or stateless), legacy HTTP+SSE (2024-11-05, auto-detected), or stdio (desktop only). Browse and call tools, resources, and prompts; subscribe to resource updates; inspect notifications, progress, and a JSON-RPC timeline. Auth, headers, and params reuse the REST editors; tool/prompt arguments and results use the shared code editor and response viewer (body, headers, timing). Activity is mirrored to the Console.
- **Bidirectional MCP**: the client answers `sampling/createMessage`, `roots/list`, and `elicitation/create` so you can test servers that call back.
- **OAuth 2.1 for MCP**: metadata discovery, Dynamic Client Registration, PKCE S256, client-credentials, refresh, and an OAuth debugger log. Interactive authorization-code is desktop-first (loopback); the browser uses paste/non-interactive grants.
- **Sample-server MCP mock**: `POST /mcp`, `POST /mcp/authed` (Bearer + API key), legacy `GET /mcp/sse`, OAuth-protected `POST /mcp/secure`, and `sample-server --stdio` with deterministic tools (`echo`, `add`, `fail`, `slow`, triggers).

### Changed

- MCP workspace uses the same request/response split as HTTP. Connections survive tab switches and disconnect only when the tab is closed.

---

## [1.17.0] — 2026-08-29

### Added
Expand Down
70 changes: 69 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,73 @@ Available endpoints (selected):
| POST | `/v1/chat/ndjson` | Ollama-style NDJSON chat stream |
| POST | `/v1/embeddings` | Fixed-length embedding vector |
| GET | `/v1/chat/slow` | Delayed non-stream chat completion |
| GET | `/sse` | Finite SSE (`text/event-stream`); `?count=` (default 3), `?delayMs=` |
| POST | `/sse` | Finite SSE; last event echoes a body snippet; same `count` / `delayMs` |
| POST | `/mcp` | MCP Streamable HTTP (JSON-RPC) |
| POST | `/mcp/auth/bearer` | MCP Bearer `reqlab-mcp-token` |
| POST | `/mcp/auth/basic` | MCP Basic `admin` / `password` |
| POST | `/mcp/auth/apikey` | MCP header `X-Api-Key: reqlab-key` |
| POST | `/mcp/auth/jwt` | MCP Bearer JWT `reqlab-mcp-jwt` |
| POST | `/mcp/authed` | MCP requiring Bearer `reqlab-mcp-token` and `X-Api-Key: reqlab-key` |
| POST | `/mcp?requireTenant=true&tenant=acme` | MCP query params required by the mock |
| GET | `/mcp` | MCP GET SSE (server-initiated) |
| DELETE | `/mcp` | MCP session terminate (`Mcp-Session-Id`) |
| GET | `/mcp/sse` | Legacy MCP HTTP+SSE |
| POST | `/mcp/messages` | Legacy MCP POST |
| POST | `/mcp/secure` | MCP with Bearer `mcp-oauth-token` |
| GET | `/.well-known/oauth-*` | MCP OAuth 2.1 metadata |
| POST | `/oauth/register` `/oauth/token` | Dynamic registration + token |
| GET | `/oauth/authorize` | Authorization (auto-approve for tests) |
| WS | `/ws` | WebSocket echo |

### MCP stdio and PATH shim

Stdio only (no HTTP port):

```bash
./gradlew :sample-server:run --args='--stdio'
```

To put `sample-server` on your login PATH:

```bash
./gradlew :sample-server:installMcpCommand
```

That writes `~/.local/bin/sample-server` on macOS/Linux, or `%USERPROFILE%\AppData\Local\ReqLab\bin\sample-server.cmd` on Windows. The shim always starts MCP stdio (the Gradle HTTP start script without `--stdio` would print a banner on stdout and break framing). After install, the command field is `sample-server`. On a new machine or after moving the repo, run `installMcpCommand` again (the shim stores an absolute path to this repo’s `mcp-stdio` script).

How ReqLab resolves a stdio command:

1. Parse the command line (tokens and quoting). Quoted paths with spaces work.
2. Resolve PATH from your login shell (`zsh`/`bash -ilc 'echo $PATH'`), merged with the process PATH, then look up the first token. On Windows, `.cmd` / `.exe` / `.bat` are tried.
3. If the first token looks like a path (`/` or `\`), resolve it against the process working directory once if that file exists.
4. Otherwise spawn the token as given. GUI apps often see a short PATH; the login-shell PATH is why `npx` and Homebrew binaries still resolve.

### MCP mock tools

| Tool | Role |
|---|---|
| `echo` | Returns the `text` argument |
| `add` | Adds numbers |
| `fail` | Error result |
| `slow` | Delayed result |
| `trigger_sampling` | Server requests `sampling/createMessage`; tool result is the client’s sampling reply |
| `trigger_roots` | Server requests `roots/list`; tool result is the client’s roots JSON |
| `trigger_elicitation` | Server requests `elicitation/create`; tool result is accept/decline |
| `trigger_ping` | Server requests `ping`; tool result is the client’s empty ping result |

Resources, prompts, and logging are also advertised so you can exercise those tabs. Product guide: [docs/mcp.md](docs/mcp.md).

### MCP sample-server troubleshooting

| Symptom | Likely cause | What to do |
|---|---|---|
| `Cannot run program "sample-server"` | Not on login PATH | `./gradlew :sample-server:installMcpCommand`, or an absolute path, or `./gradlew :sample-server:run --args='--stdio'` |
| Handshake is garbage / HTTP banner on stdout | PATH `sample-server` is the Gradle HTTP script without `--stdio` | Use the shim from `installMcpCommand` |
| `Cannot run program "sample-server --stdio"` | Whole string used as the executable (fixed in current builds) | Use current ReqLab; command can be `sample-server` once it is on PATH |
| Timed out waiting for legacy SSE endpoint | Sample HTTP server not running, or GET `/mcp/sse` not streaming | `./gradlew :sample-server:run`; URL is `/mcp/sse` not `/mcp` |
| `Lost pending id` on legacy SSE | Reply arrived on SSE before POST returned (fixed in current builds) | Use current ReqLab; **Legacy** and `http://localhost:8080/mcp/sse` |

LLM mock query parameters:

- `?demo=true` — longer assistant reply; streaming uses ~200ms per token (visible typewriter)
Expand Down Expand Up @@ -244,7 +309,10 @@ GitHub Actions release packaging is defined in [`.github/workflows/release.yml`]
- **Push to `main`** — runs a quality gate first, then builds desktop artifacts for macOS/Linux/Windows.
- **Push tag `v*`** — runs the same quality gate, then builds artifacts and publishes a GitHub release.
- **Manual dispatch** — allows on-demand artifact builds.

```
git tag -a v1.18.0 -m "<MSG>"
git push origin v1.18.0
```
---

## Project Architecture
Expand Down
10 changes: 6 additions & 4 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ ReqLab supports end-to-end API testing with:
- URL editing with query parameter table synchronization
- Header editing and request body editing
- Request body support for JSON, GraphQL, form-style payloads, and raw text
- JSON bodies accept JSON5 by default (comments, trailing commas, unquoted keys). Send converts to strict JSON; turn off in Settings to restore strict JSON.
- Authentication modes: None, Basic, Bearer, API Key, JWT (OAuth2 planned)
- Retry controls and timeout behavior
- HTTP streaming for SSE (`text/event-stream`) and NDJSON (OpenAI-style `"stream": true`)
- HTTP streaming for SSE (`text/event-stream`) and NDJSON (OpenAI-style `"stream": true`). Items with `Accept: text/event-stream` show an **SSE** badge in the HTTP method color; folder ⋮ → **New SSE Request**.
- **MCP client** for Streamable HTTP (2025-06-18), legacy HTTP+SSE, and desktop stdio. Tools (Form/JSON arguments), resources (read + subscribe), prompts, Activity JSON-RPC inspector, sampling/roots/elicitation, and auth (None, Basic, Bearer, API Key, JWT) match the REST workspace. See [docs/mcp.md](docs/mcp.md).
- Copy request as `curl`

### Response Validation and Inspection
Expand Down Expand Up @@ -61,7 +63,7 @@ ReqLab features a full-featured code editor used across request body editing, sc
- Keyboard-driven toggle (toolbar button)

**Formatting** — Auto-format source code:
- JSON pretty-print (indented with 2-space indent)
- JSON pretty-print (indented with 2-space indent). With JSON5 on, Format pretty-prints JSON5 and keeps comments, unquoted keys, single quotes, and trailing commas; Send still converts to strict JSON. With JSON5 off, Format is a no-op on invalid JSON.
- XML / HTML indentation
- JavaScript formatting (including script editor)
- Toggle on/off from toolbar
Expand Down Expand Up @@ -125,15 +127,15 @@ Pre-request scripts can mutate outgoing request values:

### Collections and Test Automation

- Collection import/export using `qa-tests/fixtures/reqlab-test-collection.json`
- Collection import/export using `qa-tests/fixtures/reqlab-test-collection.json` (includes a **JSON5** folder under Body Types)
- **Postman Collection v2 / v2.1 import** — auto-detected and converted to ReqLab format
- Folders, requests, headers, auth (bearer / basic / API key), body (raw JSON, form-data, urlencoded, GraphQL, binary), and scripts
- Postman `pm.*` script namespace automatically rewritten to `reqlab.*`
- `pm.sendRequest` rewritten to `reqlab.sendRequest` (supported)
- `pm.execution.setNextRequest`, `pm.execution.skipRequest`, and `postman.setNextRequest` rewritten to `reqlab.execution.*`
- **Postman Environment import** — name and enabled variables imported; disabled variables skipped
- Request-level pre-request and post-request scripts in collection items
- Automated collection validation via `qa-tests/collection-validator.mjs`
- Automated collection validation via `qa-tests/collection-validator.mjs` (JSON5 requests are skipped, not counted as passed; Kotlin `SampleCollectionE2ETest` is the JSON5 send coverage)
- Deterministic sample-server endpoints for reproducible test runs

### Sample Server
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ You can import these sample fixtures from the repo:
- Collection sample: [qa-tests/fixtures/reqlab-test-collection.json](qa-tests/fixtures/reqlab-test-collection.json)
- Environment sample: [qa-tests/fixtures/reqlab-test-environment.json](qa-tests/fixtures/reqlab-test-environment.json)

The collection includes an **LLM (OpenAI-compatible)** folder. Start the sample server, then send **LLM Chat Completions Stream (visible)** to watch a token stream on one POST.
The collection includes an **LLM (OpenAI-compatible)** folder, an **SSE** folder, and an **MCP (Model Context Protocol)** folder. Start the sample server, then send **LLM Chat Completions Stream (visible)** or an SSE item to watch events arrive, or open an MCP item and Connect. See [docs/mcp.md](docs/mcp.md).

## Features

Expand All @@ -65,12 +65,27 @@ The collection includes an **LLM (OpenAI-compatible)** folder. Start the sample
- Methods: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `HEAD`
- URL editing with live query-parameter table synchronisation
- Request headers editor (key/value table)
- Body types: JSON, GraphQL, form-data, x-www-form-urlencoded, raw text, binary
- Body types: JSON (JSON5 authoring by default; Send converts to strict JSON), GraphQL, form-data, x-www-form-urlencoded, raw text, binary
- Auth: None, Basic, Bearer Token, API Key, JWT
- Retry controls and per-request timeout
- HTTP streaming: SSE (`text/event-stream`) and NDJSON on a single request (OpenAI-style `"stream": true`)
- HTTP streaming: SSE (`text/event-stream`) and NDJSON on a single request (OpenAI-style `"stream": true`). Collection items with `Accept: text/event-stream` show an **SSE** badge in the HTTP method color; folder ⋮ → **New SSE Request**
- Copy request as `curl`

### MCP

ReqLab is an [MCP](https://modelcontextprotocol.io/) client in the same workspace as REST: collections, environments, auth, and a shared Response pane.

![ReqLab MCP tools — connected session, tool list, Form/JSON arguments, JSON-RPC result](docs/images/mcp-tools.png)

- Transports: Streamable HTTP, Auto (legacy fallback), Legacy HTTP+SSE, desktop stdio
- Tools (Form/JSON), resources (read + subscribe), prompts — results in the shared Response pane
- Activity JSON-RPC inspector; Logs vs Console
- Sampling, roots, elicitation on the Client tab
- Same auth editors as REST (None / Basic / Bearer / API Key / JWT); `{{variables}}` in URL, command, headers, and auth
- Collection save, import, and export of MCP items

Full guide: [docs/mcp.md](docs/mcp.md)

### 📬 Response Inspection

- Status code, status text, and response headers
Expand Down Expand Up @@ -191,6 +206,7 @@ Open from the toolbar `Help` icon or via **Settings → Open Help & About**:
| [DEVELOPMENT.md](DEVELOPMENT.md) | Build, run, and contribute locally |
| [docs/architecture.md](docs/architecture.md) | Module structure and data flow |
| [docs/editor-architecture.md](docs/editor-architecture.md) | Code editor internals |
| [docs/mcp.md](docs/mcp.md) | MCP client: tools, resources, prompts, Activity, sampling |
| [docs/scripts.md](docs/scripts.md) | Scripting API and variable scopes |
| [docs/shortcuts.md](docs/shortcuts.md) | Keyboard shortcut reference |
| [docs/testing.md](docs/testing.md) | Test strategy and coverage matrix |
Expand Down
Loading
Loading