@qulib/mcp 0.2.0 → 0.2.2
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 +23 -2
- package/dist/index.js +25 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
Tools:
|
|
8
8
|
|
|
9
|
-
- **`
|
|
10
|
-
- **`
|
|
9
|
+
- **`explore_auth(url, timeoutMs?)`** — list all sign-in paths (OAuth, unknown SSO heuristics, forms, magic link) and what the agent must collect before `analyze_app`. Prefer this on unfamiliar apps.
|
|
10
|
+
- **`analyze_app(url, auth?)`** — full quality scan (optional form-login or storage-state auth).
|
|
11
|
+
- **`detect_auth(url, timeoutMs?)`** — single-pattern auth guess with a short recommendation (lighter than `explore_auth`).
|
|
11
12
|
|
|
12
13
|
Returns from `analyze_app`:
|
|
13
14
|
|
|
@@ -40,6 +41,26 @@ Add this under `mcpServers` in `claude_desktop_config.json` (Claude Desktop) or
|
|
|
40
41
|
}
|
|
41
42
|
```
|
|
42
43
|
|
|
44
|
+
## One-time browser setup
|
|
45
|
+
|
|
46
|
+
qulib uses Playwright under the hood. After your MCP host first runs the qulib server, you'll need to install Chromium:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx playwright install chromium
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This is a one-time step. You'll only need to do it again if Playwright's browser version is bumped in a future qulib release.
|
|
53
|
+
|
|
54
|
+
If you skip this step, the first tool call will return a clear error telling you to run the command.
|
|
55
|
+
|
|
56
|
+
## Agentic auth exploration (`explore_auth`)
|
|
57
|
+
|
|
58
|
+
On unfamiliar apps, call **`explore_auth`** before **`analyze_app`**. The response lists each sign-in path (curated public OAuth/SSO, password forms, magic-link wording, and **heuristic** unknown buttons such as tenant-specific SSO). Each path includes **`requirements`** (e.g. storage-state vs credentials) and **`suggestedAgentBehavior`**.
|
|
59
|
+
|
|
60
|
+
When the model sees **`unrecognizedButtons`**, it can ask the user to register a label on the **MCP host** with the CLI:
|
|
61
|
+
|
|
62
|
+
`qulib auth providers add --id <kebab-id> --label "..." --pattern "..."` — patterns are saved under **`~/.qulib/providers.json`** and merged with the built-in list on the next `explore_auth` / `explore-auth`. Nothing is auto-written without an explicit `providers add`.
|
|
63
|
+
|
|
43
64
|
## Example usage
|
|
44
65
|
|
|
45
66
|
Ask Claude:
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
-
import { analyzeApp, detectAuth } from '@qulib/core';
|
|
5
|
+
import { analyzeApp, detectAuth, exploreAuth } from '@qulib/core';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
const FormLoginMcpAuthSchema = z.object({
|
|
8
8
|
type: z.literal('form-login'),
|
|
@@ -34,6 +34,18 @@ const server = new Server({
|
|
|
34
34
|
});
|
|
35
35
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
36
36
|
tools: [
|
|
37
|
+
{
|
|
38
|
+
name: 'explore_auth',
|
|
39
|
+
description: 'Use this BEFORE analyze_app when scanning unfamiliar apps. Returns all detected sign-in paths with per-path requirements describing what credentials or actions the agent must collect from the user before calling analyze_app. Combines built-in OAuth/SSO labels, user-local patterns from ~/.qulib/providers.json, and heuristic unknown buttons.',
|
|
40
|
+
inputSchema: {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
url: { type: 'string', description: 'Full URL of the deployed app or login page' },
|
|
44
|
+
timeoutMs: { type: 'number', description: 'Navigation timeout in milliseconds (default 20000)' },
|
|
45
|
+
},
|
|
46
|
+
required: ['url'],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
37
49
|
{
|
|
38
50
|
name: 'analyze_app',
|
|
39
51
|
description: 'Analyze a deployed web app for quality gaps. Returns a release confidence score (0-100), accessibility violations, broken links, and prioritized risks. Supports optional form-login or storage-state (Playwright) authentication.',
|
|
@@ -97,6 +109,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
97
109
|
],
|
|
98
110
|
}));
|
|
99
111
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
112
|
+
if (request.params.name === 'explore_auth') {
|
|
113
|
+
const { url, timeoutMs } = z
|
|
114
|
+
.object({
|
|
115
|
+
url: z.string().url(),
|
|
116
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
117
|
+
})
|
|
118
|
+
.parse(request.params.arguments ?? {});
|
|
119
|
+
const result = await exploreAuth(url, timeoutMs);
|
|
120
|
+
return {
|
|
121
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
100
124
|
if (request.params.name === 'detect_auth') {
|
|
101
125
|
const { url, timeoutMs } = z
|
|
102
126
|
.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qulib/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "MCP server for Qulib — AI-callable QA gap analysis",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tapesh Nagarwal",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"dev": "tsx src/index.ts"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@qulib/core": "0.2.
|
|
34
|
+
"@qulib/core": "0.2.2",
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
36
36
|
"zod": "^3.23.0"
|
|
37
37
|
},
|