hoppscotch-mcp
by z-illia
README.md
# Hoppscotch MCP Server
MCP server for Hoppscotch Team Collection automation.
It supports:
- Hoppscotch personal and team REST collection operations through Hoppscotch internal GraphQL.
- Safe OpenAPI sync into a dedicated generated collection or folder.
- Source-code endpoint analysis and code-based sync into Hoppscotch.
- A Generated-folder workflow that avoids modifying manual Hoppscotch folders.
## Safety Model
- Sync tools default to `dryRun: true`.
- Write mode creates a backup under `./backups/` before mutating Hoppscotch.
- Sync matching uses stable `METHOD + normalized path` keys.
- Existing request scripts, auth, manual headers, and manual metadata are preserved where possible.
- Sync never deletes Hoppscotch requests automatically.
- Destructive delete tools are intentionally not exposed by this MCP server. Sync workflows never delete requests automatically. Removed endpoints are handled through deprecated markers or a Deprecated folder strategy.
- Use a dedicated Generated collection such as `NMS Backend API/Generated` as the sync target.
- Do not return full large exports through MCP; export tools write files and return compact metadata.
Known NMS target values:
```text
HOPPSCOTCH_GRAPHQL_URL=https://hoppscotch.YOUR_DOMAIN/backend/graphql
Team ID=cmpcn4aya000g12lcnyif0w3w
Team name=NMS ERP
Root collection ID=cmpcn7ozh000h12lc2rtzzx2c
Root collection title=NMS Backend API
Generated collection ID=cmqi7d761003v12pbc2kdtdyj
Generated path=NMS Backend API/Generated
```
## Installation
```bash
npm install
npm run build
npm test
```
Run locally:
```bash
npm start
```
Development mode:
```bash
npm run dev
```
## Environment Configuration
Copy `.env.example` to `.env` and set values.
Required MCP setting:
```env
MCP_AUTH_TOKEN=change-me
```
Hoppscotch settings:
```env
HOPPSCOTCH_GRAPHQL_URL=https://hoppscotch.YOUR_DOMAIN/backend/graphql
HOPPSCOTCH_ORIGIN=https://hoppscotch.YOUR_DOMAIN
HOPPSCOTCH_COOKIE=connect.sid=...; access_token=...; refresh_token=...
HOPPSCOTCH_AUTH_UI_HOST=127.0.0.1
HOPPSCOTCH_AUTH_UI_PORT=3737
HOPPSCOTCH_AUTH_STORAGE_FILE=.hoppscotch-auth.local.json
```
Split cookie values are also supported and take precedence over `HOPPSCOTCH_COOKIE`:
```env
HOPPSCOTCH_CONNECT_SID=...
HOPPSCOTCH_ACCESS_TOKEN=...
HOPPSCOTCH_REFRESH_TOKEN=...
```
Auth precedence:
- Runtime cookies updated from the Authentication Web UI.
- Local ignored auth storage file, default `.hoppscotch-auth.local.json`.
- `HOPPSCOTCH_COOKIE`.
- Split env values: `HOPPSCOTCH_CONNECT_SID`, `HOPPSCOTCH_ACCESS_TOKEN`, `HOPPSCOTCH_REFRESH_TOKEN`.
## Authentication Web UI
`hoppscotch_update_auth` no longer accepts raw cookie or token values in MCP tool calls. This avoids leaking credentials into MCP logs, chat history, or tool call history.
Use the local Web UI flow:
1. In your MCP client, run `hoppscotch_update_auth` with `{ "action": "open_ui" }`.
2. Open the returned URL, for example `http://127.0.0.1:3737/auth?token=...`.
3. In browser DevTools on Hoppscotch, open Network, select a `/backend/graphql` request, and copy the `Cookie` header.
4. Paste the full Cookie header into the local UI, or paste `connect.sid`, `access_token`, and `refresh_token` separately.
5. Click `Parse & Test` to parse the cookies and run the Hoppscotch `me` GraphQL query without exposing cookies.
6. Click `Save cookies` to store normalized cookies locally.
The setup URL contains a random one-time token that expires after 10 minutes. Saving or clearing cookies invalidates the token.
Security notes:
- The auth UI binds to `127.0.0.1` by default.
- Binding to a public host requires `HOPPSCOTCH_AUTH_UI_ALLOW_PUBLIC_BIND=true`.
- Cookies are stored only in runtime memory and the ignored local storage file.
- `.hoppscotch-auth.local.json` is gitignored.
- MCP responses only include masked auth status, never raw cookie values.
Useful actions:
```json
{ "action": "open_ui" }
```
```json
{ "action": "status" }
```
```json
{ "action": "clear" }
```
## How To Copy Hoppscotch Cookies
Cookie header paste is the default supported authentication method.
1. Open Hoppscotch in your browser and log in.
2. Open DevTools → Network.
3. Click any `/backend/graphql` request.
4. In Request Headers, copy the full `Cookie` header.
5. Open the local Auth Web UI returned by `hoppscotch_update_auth`.
6. Paste the Cookie header into the `Paste full Cookie header` textarea.
7. Click `Parse & Test`.
8. If the test succeeds, click `Save`.
Supported pasted formats:
```text
connect.sid=...; access_token=...; refresh_token=...
```
```text
Cookie: connect.sid=...; access_token=...; refresh_token=...
```
The parser only keeps these Hoppscotch cookies:
- `connect.sid`
- `access_token`
- `refresh_token`
Stored cookies are normalized in this order:
```text
connect.sid=<value>; access_token=<value>; refresh_token=<value>
```
Cookie values are not URL-decoded before storage. Encoded values such as `%3A`, `%2F`, and `%2B` are preserved exactly for outbound Cookie headers. The UI only shows masked values and local JWT metadata such as issuer, subject, issued-at, expiration, and expired status.
## Hoppscotch-Like Login Feasibility
OAuth-style login through the local MCP Auth Web UI was investigated and is not implemented.
The safe default remains manual Cookie header paste because:
- Hoppscotch login and Google OAuth complete on the real Hoppscotch domain.
- Browser cookie domain rules prevent a `127.0.0.1` page from receiving cookies scoped to `hoppscotch.YOUR_DOMAIN`.
- `Secure`, `SameSite`, domain scoping, and server-side `connect.sid` session behavior are designed to prevent local pages from collecting those cookies.
- The MCP server must not read browser profile cookie databases, steal cookies, or bypass browser security.
A future safe design could open the official Hoppscotch login in the browser, let the user complete Google OAuth on the real Hoppscotch domain, then return to the local Auth UI and instruct the user to copy the Cookie header manually. Browser extensions or local helpers should only be considered with explicit approval.
OpenAPI settings:
```env
OPENAPI_URL=http://host.docker.internal:3000/api/swagger-json
OPENAPI_BASE_URL=<<baseUrl>>
OPENAPI_AUTH_TYPE=none
OPENAPI_BASIC_AUTH_USER=
OPENAPI_BASIC_AUTH_PASSWORD=
OPENAPI_BEARER_TOKEN=
OPENAPI_CUSTOM_AUTH_HEADER_NAME=
OPENAPI_CUSTOM_AUTH_HEADER_VALUE=
```
Supported `OPENAPI_AUTH_TYPE` values:
- `none`
- `basic`
- `bearer`
- `custom`
## Docker Notes
`localhost` inside Docker points to the MCP container, not your host machine.
If the backend runs on the host, use:
```env
OPENAPI_URL=http://host.docker.internal:3000/api/swagger-json
```
On Linux, add this to Docker Compose:
```yaml
extra_hosts:
- "host.docker.internal:host-gateway"
```
If the backend is another service in the same Docker Compose network, use the service name:
```env
OPENAPI_URL=http://backend:3000/api/swagger-json
```
Start with Docker:
```bash
docker compose up --build -d
```
Health check:
```bash
curl http://localhost:3000/health
```
## Claude Desktop / Claude Code MCP Setup
Example MCP config:
```json
{
"mcpServers": {
"hoppscotch": {
"command": "node",
"args": ["/absolute/path/to/dist/index.js"],
"env": {
"MCP_AUTH_TOKEN": "change-me",
"HOPPSCOTCH_GRAPHQL_URL": "https://hoppscotch.YOUR_DOMAIN/backend/graphql",
"HOPPSCOTCH_COOKIE": "connect.sid=...; access_token=...; refresh_token=...",
"OPENAPI_URL": "http://host.docker.internal:3000/api/swagger-json",
"OPENAPI_BASE_URL": "<<baseUrl>>"
}
}
}
}
```
## Runtime Hoppscotch Auth Update
Credentials are stored in memory only. Restarting the process resets them to env values.
```bash
curl http://localhost:3000/admin/hoppscotch-auth \
-X POST \
-H "Authorization: Bearer $MCP_AUTH_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"connectSid": "...",
"accessToken": "...",
"refreshToken": "..."
}'
```
The same update is available as `hoppscotch_update_auth`.
## MCP Tools
Team collection tools:
- `hoppscotch_list_teams`
- `hoppscotch_list_team_collections`
- `hoppscotch_get_team_collection`
- `hoppscotch_export_team_collection_json`
- `hoppscotch_export_team_collection`
- `hoppscotch_inspect_team_collection_tree`
- `hoppscotch_find_or_create_generated_folder`
- `hoppscotch_export_team_collections_json`
- `hoppscotch_list_team_requests`
- `hoppscotch_get_team_request`
- `hoppscotch_search_team_requests`
- `hoppscotch_create_team_request`
- `hoppscotch_update_team_request`
- `hoppscotch_move_team_request`
OpenAPI sync tool:
- `hoppscotch_sync_openapi_to_team_collection`
Code-based endpoint tools:
- `hoppscotch_analyze_backend_code`
- `hoppscotch_export_code_endpoint_candidates`
- `hoppscotch_plan_code_sync_to_team_collection`
- `hoppscotch_sync_code_to_team_collection`
- `hoppscotch_create_or_update_request`
Personal tools:
- `hoppscotch_me`
- `hoppscotch_list_user_collections`
- `hoppscotch_get_user_collection`
- `hoppscotch_export_user_collection_json`
- `hoppscotch_list_user_requests`
- `hoppscotch_get_user_request`
- `hoppscotch_create_user_request`
- `hoppscotch_update_user_request`
- `hoppscotch_move_user_request`
## Usage Examples
List teams:
```json
{}
```
Use with `hoppscotch_list_teams`.
Inspect collection tree:
```json
{
"collectionID": "cmpcn7ozh000h12lc2rtzzx2c",
"teamID": "cmpcn4aya000g12lcnyif0w3w"
}
```
Use with `hoppscotch_inspect_team_collection_tree`.
Export or backup a collection:
```json
{
"collectionID": "cmqi7d761003v12pbc2kdtdyj",
"teamID": "cmpcn4aya000g12lcnyif0w3w"
}
```
Use with `hoppscotch_export_team_collection`.
OpenAPI dry-run sync:
```json
{
"teamID": "cmpcn4aya000g12lcnyif0w3w",
"rootCollectionID": "cmpcn7ozh000h12lc2rtzzx2c",
"targetCollectionID": "cmqi7d761003v12pbc2kdtdyj",
"dryRun": true
}
```
OpenAPI write sync:
```json
{
"teamID": "cmpcn4aya000g12lcnyif0w3w",
"rootCollectionID": "cmpcn7ozh000h12lc2rtzzx2c",
"targetCollectionID": "cmqi7d761003v12pbc2kdtdyj",
"dryRun": false,
"deprecatedStrategy": "mark"
}
```
Code analysis:
```json
{
"projectPath": "/absolute/path/to/backend",
"framework": "auto",
"maxFiles": 500
}
```
Use with `hoppscotch_analyze_backend_code`. Full JSON is saved under `./analysis/` and the MCP response returns only a compact summary.
Code sync dry-run:
```json
{
"analysisFile": "./analysis/backend-1710000000000.analysis.json",
"teamID": "cmpcn4aya000g12lcnyif0w3w",
"rootCollectionID": "cmpcn7ozh000h12lc2rtzzx2c",
"targetCollectionID": "cmqi7d761003v12pbc2kdtdyj",
"baseUrl": "<<baseUrl>>",
"dryRun": true
}
```
Code sync write mode:
```json
{
"analysisFile": "./analysis/backend-1710000000000.analysis.json",
"teamID": "cmpcn4aya000g12lcnyif0w3w",
"rootCollectionID": "cmpcn7ozh000h12lc2rtzzx2c",
"targetCollectionID": "cmqi7d761003v12pbc2kdtdyj",
"baseUrl": "<<baseUrl>>",
"dryRun": false,
"includeLowConfidence": false,
"deprecatedStrategy": "ignore"
}
```
Single request create/update dry-run:
```json
{
"teamID": "cmpcn4aya000g12lcnyif0w3w",
"targetCollectionID": "cmqi7d761003v12pbc2kdtdyj",
"method": "GET",
"path": "/api/users/{id}",
"title": "Get user",
"folderName": "Users",
"baseUrl": "<<baseUrl>>",
"pathParams": [{ "key": "id" }],
"queryParams": [{ "key": "include" }],
"dryRun": true
}
```
## Code Analysis Coverage
NestJS support uses the TypeScript compiler API and detects:
- `@Controller()`
- `@Get()`, `@Post()`, `@Put()`, `@Patch()`, `@Delete()`
- `@Param()`, `@Query()`, `@Body()`, `@Headers()`
- `@UseGuards()`, `@ApiTags()`, `@ApiOperation()`, `@ApiBearerAuth()`
- DTO class names used in `@Body()` parameters
- source file and line number
Express and Laravel support is heuristic and lower confidence:
- Express: `router.get/post/put/patch/delete` and `app.get/post/put/patch/delete`
- Laravel: `Route::get/post/put/patch/delete`
Mounted routers, Laravel `apiResource/resource`, FormRequest analysis, and complex dynamic route construction are TODOs.
## Security Warnings
- Do not commit cookies or tokens.
- Store secrets in `.env` or MCP client environment variables.
- Rotate cookies if exposed.
- Prefer a dedicated team workspace.
- Use the Generated collection as the sync target.
- Always run dry-run before write mode.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing