@minicor/mcp-server 3.1.4 → 3.2.0
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.
- package/README.md +251 -61
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/laminar-client.d.ts +5 -0
- package/dist/laminar-client.d.ts.map +1 -1
- package/dist/laminar-client.js +6 -0
- package/dist/laminar-client.js.map +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +2 -0
- package/dist/lib.js.map +1 -1
- package/dist/prompts/build-rpa.d.ts.map +1 -1
- package/dist/prompts/build-rpa.js +86 -272
- package/dist/prompts/build-rpa.js.map +1 -1
- package/dist/prompts/debug-execution.js +1 -1
- package/dist/seed-skills.d.ts +13 -0
- package/dist/seed-skills.d.ts.map +1 -0
- package/dist/seed-skills.js +82 -0
- package/dist/seed-skills.js.map +1 -0
- package/dist/skills-service-client.d.ts +54 -0
- package/dist/skills-service-client.d.ts.map +1 -0
- package/dist/skills-service-client.js +93 -0
- package/dist/skills-service-client.js.map +1 -0
- package/dist/skills.d.ts +34 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +152 -0
- package/dist/skills.js.map +1 -0
- package/dist/sync.d.ts +18 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +404 -104
- package/dist/sync.js.map +1 -1
- package/dist/tools/core.d.ts.map +1 -1
- package/dist/tools/core.js +12 -0
- package/dist/tools/core.js.map +1 -1
- package/dist/tools/skills.d.ts +3 -0
- package/dist/tools/skills.d.ts.map +1 -0
- package/dist/tools/skills.js +429 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/sync-tools.d.ts.map +1 -1
- package/dist/tools/sync-tools.js +53 -12
- package/dist/tools/sync-tools.js.map +1 -1
- package/dist/tools/vm.js +2 -2
- package/dist/tools/vm.js.map +1 -1
- package/dist/tools/workflow-ops.js +1 -1
- package/dist/tools/workflow-ops.js.map +1 -1
- package/package.json +4 -2
- package/skills/general/cdp-browser-automation.md +97 -0
- package/skills/general/data-extraction-strategies.md +64 -0
- package/skills/general/data-hydration-patterns.md +167 -0
- package/skills/general/data-passing-between-steps.md +46 -0
- package/skills/general/desktop-uiautomation.md +80 -0
- package/skills/general/rpa-testing-workflow.md +145 -0
- package/skills/general/session-keepalive.md +101 -0
- package/skills/general/smart-launch-patterns.md +213 -0
- package/skills/general/state-verification.md +56 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: smart-launch-patterns
|
|
3
|
+
description: Patterns for building Smart Launch workflows that ensure an app is running and authenticated before data workflows execute. Browser launch via CDP, desktop app launch via uiautomation, login/unlock detection, credential injection, MFA handling, popup dismissal. Use when building session management or app launch automation.
|
|
4
|
+
category: general
|
|
5
|
+
tags: [smart-launch, session, login, authentication, browser, desktop, cdp, mfa]
|
|
6
|
+
priority: 9
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Smart Launch Patterns
|
|
10
|
+
|
|
11
|
+
A Smart Launch workflow ensures the target application is running and authenticated before any data workflow executes. Every production workspace needs one.
|
|
12
|
+
|
|
13
|
+
## When to Build a Smart Launch
|
|
14
|
+
|
|
15
|
+
- **Production**: Always. Data workflows depend on an active session.
|
|
16
|
+
- **POC**: Skip it. Test with a manually opened app.
|
|
17
|
+
|
|
18
|
+
## Browser Smart Launch (CDP)
|
|
19
|
+
|
|
20
|
+
Pattern from PracticeFusion (Hillside workspace):
|
|
21
|
+
|
|
22
|
+
### Step 1: Check if browser is running
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import urllib.request, json
|
|
26
|
+
|
|
27
|
+
def get_cdp_ws(tab_filter='myapp'):
|
|
28
|
+
try:
|
|
29
|
+
resp = urllib.request.urlopen('http://127.0.0.1:9222/json')
|
|
30
|
+
tabs = json.loads(resp.read())
|
|
31
|
+
for tab in tabs:
|
|
32
|
+
if tab_filter in tab.get('url', ''):
|
|
33
|
+
return tab['webSocketDebuggerUrl']
|
|
34
|
+
return tabs[0]['webSocketDebuggerUrl'] if tabs else None
|
|
35
|
+
except:
|
|
36
|
+
return None
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Step 2: Launch browser if not running
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import subprocess, time
|
|
43
|
+
|
|
44
|
+
def launch_browser(url):
|
|
45
|
+
subprocess.Popen([
|
|
46
|
+
r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe',
|
|
47
|
+
'--remote-debugging-port=9222',
|
|
48
|
+
'--remote-allow-origins=*',
|
|
49
|
+
'--start-maximized',
|
|
50
|
+
'--no-first-run',
|
|
51
|
+
url
|
|
52
|
+
])
|
|
53
|
+
time.sleep(8)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Step 3: Detect state (login vs locked vs logged-in)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
current_url = cdp_eval(ws, 'window.location.href')
|
|
60
|
+
|
|
61
|
+
if '/lock' in current_url:
|
|
62
|
+
# Screen locked — unlock with password
|
|
63
|
+
unlock_screen(ws, password)
|
|
64
|
+
elif '/login' in current_url:
|
|
65
|
+
# On login page — enter credentials
|
|
66
|
+
login(ws, username, password)
|
|
67
|
+
elif '/app/' in current_url:
|
|
68
|
+
# Already logged in — ready
|
|
69
|
+
pass
|
|
70
|
+
else:
|
|
71
|
+
# Unknown state — navigate to login
|
|
72
|
+
cdp_navigate(ws, login_url)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Step 4: Inject credentials (React-safe)
|
|
76
|
+
|
|
77
|
+
Escape credentials before injecting into JS to handle special characters (`'`, `\`, etc.):
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
safe_user = username.replace('\\', '\\\\').replace("'", "\\'")
|
|
81
|
+
safe_pass = password.replace('\\', '\\\\').replace("'", "\\'")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Then use the escaped values in the CDP eval:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
cdp_eval(ws, f"""
|
|
88
|
+
(function() {{
|
|
89
|
+
var emailInput = document.querySelector('input[type="email"]');
|
|
90
|
+
var pwInput = document.querySelector('input[type="password"]');
|
|
91
|
+
var setter = Object.getOwnPropertyDescriptor(
|
|
92
|
+
window.HTMLInputElement.prototype, "value"
|
|
93
|
+
).set;
|
|
94
|
+
if (emailInput) {{
|
|
95
|
+
setter.call(emailInput, '{username}');
|
|
96
|
+
emailInput.dispatchEvent(new Event('input', {{bubbles: true}}));
|
|
97
|
+
emailInput.dispatchEvent(new Event('change', {{bubbles: true}}));
|
|
98
|
+
}}
|
|
99
|
+
if (pwInput) {{
|
|
100
|
+
setter.call(pwInput, '{password}');
|
|
101
|
+
pwInput.dispatchEvent(new Event('input', {{bubbles: true}}));
|
|
102
|
+
pwInput.dispatchEvent(new Event('change', {{bubbles: true}}));
|
|
103
|
+
}}
|
|
104
|
+
var btns = document.querySelectorAll('button');
|
|
105
|
+
for (var i = 0; i < btns.length; i++) {{
|
|
106
|
+
if (btns[i].textContent.trim().toLowerCase().includes('log in')) {{
|
|
107
|
+
btns[i].click(); break;
|
|
108
|
+
}}
|
|
109
|
+
}}
|
|
110
|
+
}})();
|
|
111
|
+
""")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Step 5: Handle MFA
|
|
115
|
+
|
|
116
|
+
After login, check if MFA is required:
|
|
117
|
+
- If URL contains 'securitycheck' or 'securitycode', MFA is needed
|
|
118
|
+
- Use `tfa_generate_totp` or `tfa_request_sms_otp` to get the code
|
|
119
|
+
- Inject the code via CDP
|
|
120
|
+
|
|
121
|
+
## Desktop Smart Launch (uiautomation)
|
|
122
|
+
|
|
123
|
+
Pattern from athenaPractice (Novelle workspace):
|
|
124
|
+
|
|
125
|
+
### Step 1: Check if window exists
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import uiautomation as auto
|
|
129
|
+
|
|
130
|
+
win = auto.WindowControl(searchDepth=1, Name='athenaPractice')
|
|
131
|
+
window_exists = win.Exists(3)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Step 2: Conditional launch
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
if not window_exists:
|
|
138
|
+
import subprocess, os
|
|
139
|
+
app_path = os.path.join(os.environ["PUBLIC"], "Desktop", "MyApp.lnk")
|
|
140
|
+
subprocess.Popen(["powershell", "-Command", f'Start-Process "{app_path}"'])
|
|
141
|
+
time.sleep(15)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Step 3: Check if signed in
|
|
145
|
+
|
|
146
|
+
Look for a known UI element that only appears when logged in:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
window = auto.WindowControl(searchDepth=1, Name='athenaPractice')
|
|
150
|
+
window.SetActive()
|
|
151
|
+
|
|
152
|
+
# Look for an element that proves we're signed in
|
|
153
|
+
chart = window.HyperlinkControl(Name='Chart')
|
|
154
|
+
signed_in = chart.Exists(3)
|
|
155
|
+
|
|
156
|
+
if not signed_in:
|
|
157
|
+
# Also try other control types
|
|
158
|
+
chart = window.TextControl(Name='Chart')
|
|
159
|
+
signed_in = chart.Exists(1)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Step 4: Conditional login
|
|
163
|
+
|
|
164
|
+
Use data passing to skip steps that aren't needed:
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
(data) => {
|
|
168
|
+
const windowExists = data.step_1?.response?.resultData?.windowExists ?? false;
|
|
169
|
+
if (windowExists) {
|
|
170
|
+
return {"skipped": true, "message": "Window already exists"};
|
|
171
|
+
}
|
|
172
|
+
// Otherwise return the launch script
|
|
173
|
+
return { "lam.rpa": { script: launchScript, channelId: "{{config.channelId}}" } };
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Step 5: Dismiss popups
|
|
178
|
+
|
|
179
|
+
After login, dismiss any startup dialogs:
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
import time
|
|
183
|
+
time.sleep(3)
|
|
184
|
+
popup = auto.WindowControl(searchDepth=1, RegexName=".*Update.*|.*Notice.*|.*Alert.*")
|
|
185
|
+
if popup.Exists(2):
|
|
186
|
+
ok_btn = popup.ButtonControl(Name="OK") or popup.ButtonControl(Name="Close")
|
|
187
|
+
if ok_btn.Exists(1):
|
|
188
|
+
ok_btn.Click()
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Workflow Structure
|
|
192
|
+
|
|
193
|
+
A typical Smart Launch workflow has 4-6 steps:
|
|
194
|
+
1. Check if app/browser is running
|
|
195
|
+
2. Launch if not running
|
|
196
|
+
3. Check if signed in
|
|
197
|
+
4. Login if not signed in
|
|
198
|
+
5. Handle MFA (if applicable)
|
|
199
|
+
6. Dismiss popups
|
|
200
|
+
|
|
201
|
+
Use conditional execution via the JS wrapper — steps can return `{"skipped": true}` when not needed.
|
|
202
|
+
|
|
203
|
+
## Config Store Setup
|
|
204
|
+
|
|
205
|
+
Smart Launch workflows reference credentials from config stores:
|
|
206
|
+
- `{{config.username}}` / `{{config.password}}` — app credentials
|
|
207
|
+
- `{{config.url}}` — login URL
|
|
208
|
+
- `{{config.channelId}}` — RPA channel ID for desktop dispatch
|
|
209
|
+
- `{{config.totp_secret_id}}` — for TOTP-based MFA
|
|
210
|
+
|
|
211
|
+
## Health Check Pattern
|
|
212
|
+
|
|
213
|
+
Create a simple workflow that runs the Smart Launch and reports status. Schedule it via `create_agent mode: "scheduled"` with a cron expression (e.g., every 5 minutes). This keeps the session alive and auto-recovers from timeouts.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: state-verification
|
|
3
|
+
description: LLM-based UI state verification for RPA steps using expectedPreState and expectedPostState. How to use generate_state_description and debug_rpa_step for regression detection. Use when adding verification to RPA steps or debugging flaky automations.
|
|
4
|
+
category: general
|
|
5
|
+
tags: [verification, state, debugging, regression, screenshots]
|
|
6
|
+
priority: 7
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# State Verification
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
Every RPA step can include `expectedPreState` and `expectedPostState` — natural language descriptions of what the screen should look like before and after the step runs. The MDS uses LLM-based screenshot analysis to verify these conditions, catching regressions when the target app's UI changes.
|
|
14
|
+
|
|
15
|
+
## Using `debug_rpa_step`
|
|
16
|
+
|
|
17
|
+
`debug_rpa_step` runs a script with full diagnostics:
|
|
18
|
+
|
|
19
|
+
- Takes a **before screenshot**
|
|
20
|
+
- Executes the script
|
|
21
|
+
- Takes an **after screenshot**
|
|
22
|
+
- Returns stdout, stderr, exit code, and both screenshots
|
|
23
|
+
- Optionally verifies against `expectedPreState` / `expectedPostState`
|
|
24
|
+
|
|
25
|
+
Use during development to validate each step before saving.
|
|
26
|
+
|
|
27
|
+
## Writing State Descriptions
|
|
28
|
+
|
|
29
|
+
Use `generate_state_description` to author state descriptions from the current screen. Descriptions should be:
|
|
30
|
+
|
|
31
|
+
- **Specific enough** to catch real regressions (e.g., "The Patient Search dialog is open with an empty MRN field")
|
|
32
|
+
- **General enough** to not break on minor UI changes (e.g., don't mention exact pixel positions or colors)
|
|
33
|
+
- **Focused on the relevant area** — describe what matters for this step, not the entire screen
|
|
34
|
+
|
|
35
|
+
## Workflow
|
|
36
|
+
|
|
37
|
+
1. Navigate to the pre-state → `generate_state_description` → save as `expectedPreState`
|
|
38
|
+
2. Run the automation step
|
|
39
|
+
3. Verify the result → `generate_state_description` → save as `expectedPostState`
|
|
40
|
+
4. Pass both to `create_rpa_flow` when saving the step
|
|
41
|
+
|
|
42
|
+
## When State Verification Catches Issues
|
|
43
|
+
|
|
44
|
+
- App updated its UI (new buttons, moved fields, changed labels)
|
|
45
|
+
- Login session expired (expected app screen, got login page)
|
|
46
|
+
- Popup or error dialog appeared unexpectedly
|
|
47
|
+
- Previous step failed silently, leaving the app in wrong state
|
|
48
|
+
|
|
49
|
+
## Debugging Tools
|
|
50
|
+
|
|
51
|
+
- `**debug_rpa_step`** — runs script with before/after screenshots + full diagnostics
|
|
52
|
+
- `**vm_reset_state`** — manage windows: focus an app, minimize all, close dialogs
|
|
53
|
+
- `**vm_read_clipboard**` — read clipboard after a copy operation
|
|
54
|
+
- `**vm_screenshot_region**` — crop/zoom a specific screen region
|
|
55
|
+
- `**batch_test_rpa**` — run the workflow with multiple test inputs
|
|
56
|
+
- **Video Recordings** — use `get_full_execution` to see recording references
|