terminator-mcp-agent 0.13.8 → 0.14.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +339 -48
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -11,6 +11,14 @@ A Model Context Protocol (MCP) server that provides desktop GUI automation capab
11
11
 
12
12
  ## Quick Install
13
13
 
14
+ ### Claude Code
15
+
16
+ Install with a single command:
17
+
18
+ ```bash
19
+ claude mcp add terminator "npx -y terminator-mcp-agent" -s user
20
+ ```
21
+
14
22
  ### Cursor
15
23
 
16
24
  Copy and paste this URL into your browser's address bar:
@@ -81,6 +89,12 @@ terminator mcp run workflow.yml --dry-run
81
89
 
82
90
  # Use specific MCP server version
83
91
  terminator mcp run workflow.yml --command "npx -y terminator-mcp-agent@latest"
92
+
93
+ # Run specific steps (requires step IDs in workflow)
94
+ terminator mcp run workflow.yml --start-from "step_12" --end-at "step_13"
95
+
96
+ # Run single step
97
+ terminator mcp run workflow.yml --start-from "read_json" --end-at "read_json"
84
98
  ```
85
99
 
86
100
  **Workflow File Formats:**
@@ -123,61 +137,63 @@ Execute custom JavaScript or Python with access to desktop automation APIs via `
123
137
 
124
138
  **Passing Data Between Workflow Steps:**
125
139
 
126
- When using `engine` mode, you can pass data between steps using the `set_env` mechanism:
140
+ When using `engine` mode, data automatically flows between steps:
127
141
 
128
142
  ```yaml
129
143
  steps:
130
- # Step 1: Set environment variables for next step
144
+ # Step 1: Return data directly (NEW - simplified!)
131
145
  - tool_name: run_command
132
146
  arguments:
133
147
  engine: "javascript"
134
148
  run: |
135
- // Example: Find files and pass data to next step
136
- const { execSync } = require('child_process');
137
-
138
149
  // Get file info (example)
139
150
  const filePath = 'C:\\data\\report.pdf';
140
151
  const fileSize = 1024;
141
-
142
- // Pass data to next step using set_env
152
+
143
153
  console.log(`Found file: ${filePath}`);
144
-
145
- // Method 1: Return set_env object (preferred)
154
+
155
+ // Just return fields directly - they auto-merge into env
146
156
  return {
147
- set_env: {
148
- file_path: filePath,
149
- file_size: fileSize.toString()
150
- },
151
- status: 'found'
157
+ status: 'success',
158
+ file_path: filePath, // Becomes env.file_path
159
+ file_size: fileSize // Becomes env.file_size
152
160
  };
153
-
154
- // Method 2: GitHub Actions style (alternative)
155
- // console.log(`::set-env name=file_path::${filePath}`);
156
161
 
157
- # Step 2: Access data from previous step
162
+ # Step 2: Access data automatically
158
163
  - tool_name: run_command
159
164
  arguments:
160
165
  engine: "javascript"
161
166
  run: |
162
- // Access environment variables from previous step
163
- const filePath = '{{env.file_path}}';
164
- const fileSize = '{{env.file_size}}';
165
-
166
- console.log(`Processing: ${filePath} (${fileSize} bytes)`);
167
-
167
+ // env is automatically available - no setup needed!
168
+ console.log(`Processing: ${env.file_path} (${env.file_size} bytes)`);
169
+
170
+ // Workflow variables also auto-available
171
+ console.log(`Config: ${variables.max_retries}`);
172
+
173
+ // NEW: Direct variable access also works!
174
+ console.log(`Processing: ${file_path} (${file_size} bytes)`);
175
+ console.log(`Config: ${max_retries}`);
176
+
168
177
  // Continue with desktop automation
169
178
  const elements = await desktop.locator('role:button').all();
170
- log(`Found ${elements.length} buttons`);
171
-
179
+
180
+ // Return more data (auto-merges to env)
172
181
  return {
173
- file_processed: filePath,
182
+ status: 'success',
183
+ file_processed: env.file_path,
174
184
  buttons_found: elements.length
175
185
  };
176
186
  ```
177
187
 
178
188
  **Important Notes on Data Passing:**
179
- - `set_env` only works with `engine` mode (JavaScript/Python), NOT with shell commands
180
- - Use `{{env.variable_name}}` syntax to access variables in subsequent steps
189
+
190
+ - **NEW:** `env` and `variables` are automatically injected into all scripts
191
+ - **NEW:** Non-reserved fields in return values auto-merge into env (no `set_env` wrapper needed)
192
+ - **NEW:** Valid env fields are also available as individual variables (e.g., `file_path` instead of `env.file_path`)
193
+ - Reserved fields that don't auto-merge: `status`, `error`, `logs`, `duration_ms`, `set_env`
194
+ - Data passing only works with `engine` mode (JavaScript/Python), NOT with shell commands
195
+ - Backward compatible: explicit `set_env` still works if needed
196
+ - Individual variable names must be valid JavaScript identifiers (no spaces, special chars, or reserved keywords)
181
197
  - Watch for backslash escaping issues in Windows paths (may need double escaping)
182
198
  - Consider combining related operations in a single step if data passing becomes complex
183
199
 
@@ -269,12 +285,14 @@ The `execute_browser_script` tool enables direct JavaScript execution in browser
269
285
  #### When to Use DOM vs Accessibility Tree
270
286
 
271
287
  **Use Accessibility Tree (default) when:**
288
+
272
289
  - Navigating and interacting with UI elements
273
290
  - Working with semantic page structure
274
291
  - Building reliable automation workflows
275
292
  - Performance is critical (faster, cleaner data)
276
293
 
277
294
  **Use DOM Inspection when:**
295
+
278
296
  - Extracting data attributes, meta tags, or hidden inputs
279
297
  - Debugging why elements aren't appearing in accessibility tree
280
298
  - Scraping structured data from specific HTML patterns
@@ -286,19 +304,19 @@ The `execute_browser_script` tool enables direct JavaScript execution in browser
286
304
  // Get full HTML DOM (be mindful of size limits)
287
305
  execute_browser_script({
288
306
  selector: "role:Window|name:Google Chrome",
289
- script: "document.documentElement.outerHTML"
290
- })
307
+ script: "document.documentElement.outerHTML",
308
+ });
291
309
 
292
310
  // Get structured page information
293
311
  execute_browser_script({
294
- selector: "role:Window|name:Google Chrome",
312
+ selector: "role:Window|name:Google Chrome",
295
313
  script: `({
296
314
  url: window.location.href,
297
315
  title: document.title,
298
316
  html: document.documentElement.outerHTML,
299
317
  bodyText: document.body.innerText.substring(0, 1000)
300
- })`
301
- })
318
+ })`,
319
+ });
302
320
 
303
321
  // Extract specific data (forms, hidden inputs, meta tags)
304
322
  execute_browser_script({
@@ -322,8 +340,8 @@ execute_browser_script({
322
340
  name: m.name || m.property,
323
341
  content: m.content
324
342
  }))
325
- })`
326
- })
343
+ })`,
344
+ });
327
345
  ```
328
346
 
329
347
  #### Handling Large DOMs
@@ -346,8 +364,8 @@ execute_browser_script({
346
364
  totalLength: html.length,
347
365
  truncated: html.length > maxLength
348
366
  })
349
- `
350
- })
367
+ `,
368
+ });
351
369
  ```
352
370
 
353
371
  #### Advanced DOM Analysis
@@ -382,8 +400,98 @@ execute_browser_script({
382
400
  .map(s => { try { return JSON.parse(s.textContent); } catch { return null; } })
383
401
  .filter(Boolean)
384
402
  })
385
- `
386
- })
403
+ `,
404
+ });
405
+ ```
406
+
407
+ #### Passing Data with Environment Variables
408
+
409
+ The `execute_browser_script` tool now supports passing data through `env` and `outputs` parameters:
410
+
411
+ ```javascript
412
+ // Step 1: Set environment variables in JavaScript
413
+ run_command({
414
+ engine: "javascript",
415
+ run: `
416
+ return {
417
+ set_env: {
418
+ userName: 'John Doe',
419
+ userId: '12345',
420
+ apiKey: 'secret-key'
421
+ }
422
+ };
423
+ `,
424
+ });
425
+
426
+ // Step 2: Use environment variables in browser script
427
+ execute_browser_script({
428
+ selector: "role:Window",
429
+ env: {
430
+ userName: "{{env.userName}}",
431
+ userId: "{{env.userId}}",
432
+ },
433
+ script: `
434
+ // Parse env if it's a JSON string (for backward compatibility)
435
+ const parsedEnv = typeof env === 'string' ? JSON.parse(env) : env;
436
+
437
+ // Use the data - traditional way
438
+ console.log('Processing user:', parsedEnv.userName);
439
+
440
+ // NEW: Direct variable access also works!
441
+ console.log('Processing user:', userName); // Direct access
442
+ console.log('User ID:', userId); // No env prefix needed
443
+
444
+ // Fill form with data
445
+ document.querySelector('#username').value = userName;
446
+ document.querySelector('#userid').value = userId;
447
+
448
+ // Return result and set new variables
449
+ JSON.stringify({
450
+ status: 'form_filled',
451
+ set_env: {
452
+ form_submitted: 'true',
453
+ timestamp: new Date().toISOString()
454
+ }
455
+ });
456
+ `,
457
+ });
458
+ ```
459
+
460
+ #### Loading Scripts from Files
461
+
462
+ You can load JavaScript from external files using the `script_file` parameter:
463
+
464
+ ```javascript
465
+ // browser_scripts/extract_data.js
466
+ const parsedEnv = typeof env === "string" ? JSON.parse(env) : env;
467
+ const parsedOutputs =
468
+ typeof outputs === "string" ? JSON.parse(outputs) : outputs;
469
+
470
+ console.log("Script loaded from file");
471
+ console.log("User:", parsedEnv?.userName);
472
+ console.log("Previous result:", parsedOutputs?.previousStep);
473
+
474
+ // Extract and return data
475
+ JSON.stringify({
476
+ extractedData: {
477
+ url: window.location.href,
478
+ title: document.title,
479
+ forms: document.forms.length,
480
+ },
481
+ set_env: {
482
+ extraction_complete: "true",
483
+ },
484
+ });
485
+
486
+ // In your workflow:
487
+ execute_browser_script({
488
+ selector: "role:Window",
489
+ script_file: "browser_scripts/extract_data.js",
490
+ env: {
491
+ userName: "{{env.userName}}",
492
+ previousStep: "{{env.previousStep}}",
493
+ },
494
+ });
387
495
  ```
388
496
 
389
497
  #### Important Notes
@@ -396,6 +504,8 @@ execute_browser_script({
396
504
 
397
505
  4. **Error Handling**: Always wrap complex DOM operations in try-catch blocks and return meaningful error messages.
398
506
 
507
+ 5. **Data Injection**: When using `env` or `outputs` parameters, they are injected as JavaScript variables at the beginning of your script. Always parse them if they might be JSON strings.
508
+
399
509
  ## Local Development
400
510
 
401
511
  To build and test the agent from the source code:
@@ -541,6 +651,7 @@ The agent automatically detects headless environments and initializes a virtual
541
651
  **Activation**:
542
652
 
543
653
  Virtual display activates automatically when:
654
+
544
655
  - Environment variable `TERMINATOR_HEADLESS=true` is set
545
656
  - No console window is available (common in VM/container scenarios)
546
657
  - Running as a Windows service or scheduled task
@@ -698,11 +809,100 @@ For additional help, see the [Terminator CLI documentation](../terminator-cli/RE
698
809
  4. **Groups & Control Flow** – Add `group_name`, `skippable`, `if`, or `continue_on_error` to any step for advanced branching.
699
810
  5. **Output Parsing** – Always end with a step that includes the UI tree, then use the declarative JSON DSL to mine the data you need.
700
811
 
701
- ### 3. Running the Workflow
812
+ ### 3. State Persistence & Partial Execution
813
+
814
+ The `execute_sequence` tool supports powerful features for workflow debugging and resumption:
815
+
816
+ #### Partial Execution with Step Ranges
817
+
818
+ You can run specific portions of a workflow using `start_from_step` and `end_at_step` parameters:
819
+
820
+ ```jsonc
821
+ {
822
+ "tool_name": "execute_sequence",
823
+ "arguments": {
824
+ "url": "file://path/to/workflow.yml",
825
+ "start_from_step": "read_json_file", // Start from this step ID
826
+ "end_at_step": "fill_journal_entries", // Stop after this step (inclusive)
827
+ "follow_fallback": false // Don't follow fallback_id beyond end_at_step (default: false)
828
+ }
829
+ }
830
+ ```
831
+
832
+ **Examples:**
833
+ - Run single step: Set both `start_from_step` and `end_at_step` to the same ID
834
+ - Run step range: Set different IDs for start and end
835
+ - Run from step to end: Only set `start_from_step`
836
+ - Run from beginning to step: Only set `end_at_step`
837
+ - Debug without fallback: Use `follow_fallback: false` to prevent jumping to troubleshooting steps when a bounded step fails
838
+
839
+ #### Automatic State Persistence
840
+
841
+ When using `file://` URLs, the workflow state (environment variables) is automatically saved to a `.workflow_state` folder:
842
+
843
+ 1. **State is saved** after each step that modifies environment variables via `set_env` or has a tool result with an ID
844
+ 2. **State is loaded** when starting from a specific step
845
+ 3. **Location**: `.workflow_state/<workflow_hash>.json` in the workflow's directory
846
+ 4. **Tool results** from all tools (not just scripts) are automatically stored as `{step_id}_result` and `{step_id}_status`
847
+
848
+ This enables:
849
+ - **Debugging**: Run steps individually to inspect state between executions
850
+ - **Recovery**: Resume failed workflows from the last successful step
851
+ - **Testing**: Test specific steps without re-running the entire workflow
852
+
853
+ #### Data Passing Between Steps
854
+
855
+ Steps can pass data using multiple methods:
856
+
857
+ ##### 1. Tool Result Storage (NEW)
858
+
859
+ ALL tools with an `id` field automatically store their results in the environment:
860
+
861
+ ```yaml
862
+ steps:
863
+ # Any tool with an ID stores its result
864
+ - id: check_apps
865
+ tool_name: get_applications
866
+ arguments:
867
+ include_tree: false
868
+
869
+ # Access the result in JavaScript
870
+ - tool_name: run_command
871
+ arguments:
872
+ engine: javascript
873
+ run: |
874
+ // Direct variable access - auto-injected!
875
+ const apps = check_apps_result || [];
876
+ const status = check_apps_status; // "success" or "error"
877
+ console.log(`Found ${apps[0]?.applications?.length} apps`);
878
+ ```
879
+
880
+ ##### 2. Script Return Values
881
+
882
+ Steps can pass data using the `set_env` mechanism in `run_command` with engine mode:
883
+
884
+ ```javascript
885
+ // Step 12: Read and process data
886
+ return {
887
+ set_env: {
888
+ file_path: "C:/data/input.json",
889
+ journal_entries: JSON.stringify(entries),
890
+ total_debit: "100.50"
891
+ }
892
+ };
893
+
894
+ // Step 13: Use the data (NEW - simplified access!)
895
+ const filePath = file_path; // Direct access, no {{env.}} needed!
896
+ const entries = JSON.parse(journal_entries);
897
+ const debit = total_debit;
898
+ ```
899
+
900
+ ### 4. Running the Workflow
702
901
 
703
902
  1. Ensure the Terminator MCP agent is running (it will auto-start in supported editors).
704
903
  2. Send the JSON above as the body of an `execute_sequence` tool call from your LLM or test harness.
705
- 3. Inspect the response: if parsing succeeds youll see something like
904
+ 3. Inspect the response: if parsing succeeds you'll see something like
905
+
706
906
  ### Realtime events (SSE)
707
907
 
708
908
  When running with the HTTP transport, you can subscribe to realtime workflow events at a separate endpoint outside `/mcp`:
@@ -713,12 +913,11 @@ When running with the HTTP transport, you can subscribe to realtime workflow eve
713
913
  Example in Node.js:
714
914
 
715
915
  ```js
716
- import EventSource from 'eventsource';
717
- const es = new EventSource('http://127.0.0.1:3000/events');
718
- es.onmessage = (e) => console.log('event', e.data);
916
+ import EventSource from "eventsource";
917
+ const es = new EventSource("http://127.0.0.1:3000/events");
918
+ es.onmessage = (e) => console.log("event", e.data);
719
919
  ```
720
920
 
721
-
722
921
  ```jsonc
723
922
  {
724
923
  "parsed_output": {
@@ -727,11 +926,103 @@ es.onmessage = (e) => console.log('event', e.data);
727
926
  }
728
927
  ```
729
928
 
730
- ### 4. Tips for Production Workflows
929
+ ### 5. Working with Tool Results
930
+
931
+ Every tool that has an `id` field automatically stores its result for use in later steps:
932
+
933
+ ```yaml
934
+ steps:
935
+ # Capture browser DOM
936
+ - id: capture_dom
937
+ tool_name: execute_browser_script
938
+ arguments:
939
+ selector: "role:Window"
940
+ script: "return document.documentElement.innerHTML;"
941
+
942
+ # Validate an element exists
943
+ - id: check_button
944
+ tool_name: validate_element
945
+ arguments:
946
+ selector: "role:Button|name:Submit"
947
+
948
+ # Use both results in script
949
+ - tool_name: run_command
950
+ arguments:
951
+ engine: javascript
952
+ run: |
953
+ // All tool results are auto-injected as variables
954
+ const dom = capture_dom_result?.content || '';
955
+ const buttonExists = check_button_status === 'success';
956
+
957
+ if (buttonExists) {
958
+ const button = check_button_result[0]?.element;
959
+ console.log(`Submit button at: ${button?.bounds?.x}, ${button?.bounds?.y}`);
960
+ }
961
+
962
+ return { dom_length: dom.length, has_button: buttonExists };
963
+ ```
964
+
965
+ Tool results are accessible as:
966
+ - `{step_id}_result`: The tool's return value (content, element info, etc.)
967
+ - `{step_id}_status`: Either "success" or "error"
968
+
969
+ ### 6. Tips for Production Workflows
731
970
 
732
971
  - **Never hard-code credentials** – use environment variables or your secret manager.
733
972
  - **Keep workflows short** – <100 steps is ideal. Break large tasks into multiple sequences.
734
- - **Capture errors** – `continue_on_error` is useful, but also log `result.status` codes to catch silent failures.
973
+ - **Capture errors** – `continue_on_error` is useful, but also check `{step_id}_status` for tool failures.
735
974
  - **Version control** – Store workflow JSON in a repo and use PR reviews just like regular code.
975
+ - **Use step IDs** – Give meaningful IDs to steps whose results you'll need later.
976
+
977
+ ## 🔍 Troubleshooting & Debugging
978
+
979
+ ### Finding MCP Server Logs
980
+
981
+ MCP logs are saved to:
982
+ - **Windows:** `%LOCALAPPDATA%\claude-cli-nodejs\Cache\<encoded-project-path>\mcp-logs-terminator-mcp-agent\`
983
+ - **macOS/Linux:** `~/.local/share/claude-cli-nodejs/Cache/<encoded-project-path>/mcp-logs-terminator-mcp-agent/`
984
+
985
+ Where `<encoded-project-path>` is your project path with special chars replaced (e.g., `C--Users-username-project`).
986
+ Note: Logs are saved as `.txt` files, not `.log` files.
987
+
988
+ **Read logs:**
989
+ ```powershell
990
+ # Windows - Find and read latest logs (run in PowerShell)
991
+ Get-ChildItem (Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'claude-cli-nodejs\Cache\*\mcp-logs-terminator-mcp-agent\*.txt') | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | Get-Content -Tail 50
992
+ ```
993
+
994
+ ### Enable Debug Logging
995
+
996
+ In your Claude MCP configuration (`claude_desktop_config.json`):
997
+ ```json
998
+ {
999
+ "mcpServers": {
1000
+ "terminator-mcp-agent": {
1001
+ "command": "path/to/terminator-mcp-agent",
1002
+ "env": {
1003
+ "LOG_LEVEL": "debug", // or "info", "warn", "error"
1004
+ "RUST_BACKTRACE": "1" // for stack traces on errors
1005
+ }
1006
+ }
1007
+ }
1008
+ }
1009
+ ```
1010
+
1011
+ ### Common Debug Scenarios
1012
+
1013
+ | Issue | What to Look For in Logs |
1014
+ |-------|--------------------------|
1015
+ | Workflow failures | Search for `fallback_id` triggers and `critical_error_occurred` |
1016
+ | Element not found | Look for selector resolution attempts, `find_element` timeouts |
1017
+ | Browser script errors | Check for `EVAL_ERROR`, Promise rejections, JavaScript exceptions |
1018
+ | Binary version issues | Startup logs show binary path and build timestamp |
1019
+ | MCP connection lost | Check for panic messages, ensure binary path is correct |
1020
+
1021
+ ### Fallback Mechanism
1022
+
1023
+ Workflows support `fallback_id` to handle errors gracefully:
1024
+ - If a step fails and has `fallback_id`, it jumps to that step instead of stopping
1025
+ - Without `fallback_id`, errors may set `critical_error_occurred` and skip remaining steps
1026
+ - Use `troubleshooting:` section for recovery steps only accessed via fallback
736
1027
 
737
1028
  > Need more help? Browse the examples under `examples/` in this repo or open a discussion on GitHub.
package/package.json CHANGED
@@ -15,10 +15,10 @@
15
15
  ],
16
16
  "name": "terminator-mcp-agent",
17
17
  "optionalDependencies": {
18
- "terminator-mcp-darwin-arm64": "0.13.8",
19
- "terminator-mcp-darwin-x64": "0.13.8",
20
- "terminator-mcp-linux-x64-gnu": "0.13.8",
21
- "terminator-mcp-win32-x64-msvc": "0.13.8"
18
+ "terminator-mcp-darwin-arm64": "0.14.10",
19
+ "terminator-mcp-darwin-x64": "0.14.10",
20
+ "terminator-mcp-linux-x64-gnu": "0.14.10",
21
+ "terminator-mcp-win32-x64-msvc": "0.14.10"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
@@ -30,5 +30,5 @@
30
30
  "sync-version": "node ./utils/sync-version.js",
31
31
  "update-badges": "node ./utils/update-badges.js"
32
32
  },
33
- "version": "0.13.8"
33
+ "version": "0.14.10"
34
34
  }