@debugg-ai/debugg-ai-mcp 1.0.30 → 1.0.31

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 CHANGED
@@ -1,42 +1,14 @@
1
- # Official MCP Server for Debugg AI
1
+ # Debugg AI — MCP Server
2
2
 
3
- **AI-powered browser testing and monitoring** via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). Gives AI agents the ability to run end-to-end browser tests, monitor live sessions, and validate UI changes against your running application.
3
+ AI-powered browser testing via the [Model Context Protocol](https://modelcontextprotocol.io). Point it at any URL (or localhost) and describe what to test an AI agent browses your app and returns pass/fail with screenshots.
4
4
 
5
5
  <a href="https://glama.ai/mcp/servers/@debugg-ai/debugg-ai-mcp">
6
6
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@debugg-ai/debugg-ai-mcp/badge" alt="Debugg AI MCP server" />
7
7
  </a>
8
8
 
9
- ---
10
-
11
- ## What it does
12
-
13
- - **Run browser tests with natural language** — describe what to test, the AI agent clicks through your app and returns screenshots + results
14
- - **Monitor live browser sessions** — capture console logs, network requests, and screenshots in real time
15
- - **Manage test suites** — create, organize, and track E2E tests tied to features or commits
16
- - **Seamless CI/CD** — view all results in your [Debugg.AI dashboard](https://app.debugg.ai)
17
-
18
- ---
19
-
20
- ## Demo
21
-
22
- ### Prompt: "Test the ability to create an account and login"
23
-
24
- ![Test Create Account and Login](/assets/recordings/test-create-account-login.gif)
25
-
26
- **Result:**
27
- - Duration: 86.80 seconds
28
- - Status: Success — signed up and logged in with `alice.wonderland1234@example.com`
9
+ ## Setup
29
10
 
30
- > [Full Use Case Demo](https://debugg.ai/demo)
31
-
32
- ---
33
-
34
- ## Quick Setup
35
-
36
- ### 1. Get your API key
37
- Create a free account at [debugg.ai](https://debugg.ai) and generate your API key.
38
-
39
- ### 2. Add to Claude Desktop
11
+ Get an API key at [debugg.ai](https://debugg.ai), then add to your MCP client config:
40
12
 
41
13
  ```json
42
14
  {
@@ -52,101 +24,42 @@ Create a free account at [debugg.ai](https://debugg.ai) and generate your API ke
52
24
  }
53
25
  ```
54
26
 
55
- **Or with Docker:**
27
+ Or with Docker:
28
+
56
29
  ```bash
57
- docker run -i --rm --init \
58
- -e DEBUGGAI_API_KEY=your_api_key \
59
- quinnosha/debugg-ai-mcp
30
+ docker run -i --rm --init -e DEBUGGAI_API_KEY=your_api_key quinnosha/debugg-ai-mcp
60
31
  ```
61
32
 
62
- ---
33
+ ## `check_app_in_browser`
63
34
 
64
- ## Tools
65
-
66
- ### E2E Testing
67
- | Tool | Description |
68
- |------|-------------|
69
- | `check_app_in_browser` | Run a browser test with a natural language description. Returns screenshots and pass/fail result. |
70
- | `create_test_suite` | Generate a suite of browser tests for a feature or workflow |
71
- | `create_commit_suite` | Auto-generate tests from recent git commits |
72
- | `get_test_status` | Check progress and results of a running or completed test suite |
73
-
74
- ### Test Management
75
- | Tool | Description |
76
- |------|-------------|
77
- | `list_tests` | List all E2E tests with filtering and pagination |
78
- | `list_test_suites` | List all test suites |
79
- | `list_commit_suites` | List all commit-based test suites |
80
-
81
- ### Live Session Monitoring
82
- | Tool | Description |
83
- |------|-------------|
84
- | `start_live_session` | Launch a remote browser session with real-time monitoring |
85
- | `stop_live_session` | Stop an active session and save captured data |
86
- | `get_live_session_status` | Check session status, current URL, and uptime |
87
- | `get_live_session_logs` | Retrieve console logs, network requests, and JS errors |
88
- | `get_live_session_screenshot` | Capture a screenshot of what the browser currently shows |
89
-
90
- ### Quick Operations
91
- | Tool | Description |
92
- |------|-------------|
93
- | `quick_screenshot` | Capture a screenshot of any URL — no session setup required |
35
+ Runs an AI browser agent against your app. The agent navigates, interacts, and reports back with screenshots.
94
36
 
95
- ---
37
+ | Parameter | Type | Description |
38
+ |-----------|------|-------------|
39
+ | `description` | string **required** | What to test (natural language) |
40
+ | `url` | string | Target URL — required if `localPort` not set |
41
+ | `localPort` | number | Local dev server port — tunnel created automatically |
42
+ | `environmentId` | string | UUID of a specific environment |
43
+ | `credentialId` | string | UUID of a specific credential |
44
+ | `credentialRole` | string | Pick a credential by role (e.g. `admin`, `guest`) |
45
+ | `username` | string | Username for login |
46
+ | `password` | string | Password for login |
96
47
 
97
48
  ## Configuration
98
49
 
99
50
  ```bash
100
- # Required
101
51
  DEBUGGAI_API_KEY=your_api_key
102
-
103
- # Optional — provide defaults so you don't have to pass them every time
104
- DEBUGGAI_LOCAL_PORT=3000 # Your app's local port
105
- DEBUGGAI_LOCAL_REPO_NAME=your-org/repo # GitHub repo name
106
- DEBUGGAI_LOCAL_REPO_PATH=/path/to/project # Absolute path to project root
107
- DEBUGGAI_LOCAL_BRANCH_NAME=main # Current branch
108
-
109
- # Override API endpoint (defaults to https://api.debugg.ai)
110
- DEBUGGAI_API_URL=https://api.debugg.ai
111
52
  ```
112
53
 
113
- ---
114
-
115
- ## Usage examples
116
-
117
- ```
118
- "Test the user login flow on my app running on port 3000"
119
-
120
- "Check that the checkout process works end to end"
121
-
122
- "Take a screenshot of localhost:3000 and tell me if anything looks broken"
123
-
124
- "Create a test suite for the user authentication feature"
125
-
126
- "Generate browser tests for my last 3 commits"
127
- ```
128
-
129
- ---
130
-
131
54
  ## Local Development
132
55
 
133
56
  ```bash
134
- npm install
135
- npm test
136
- npm run build
137
-
138
- # Test with MCP inspector
139
- npx @modelcontextprotocol/inspector --config test-config.json --server debugg-ai
57
+ npm install && npm test && npm run build
140
58
  ```
141
59
 
142
- ---
143
-
144
60
  ## Links
145
61
 
146
- - **Dashboard**: [app.debugg.ai](https://app.debugg.ai)
147
- - **Docs**: [debugg.ai/docs](https://debugg.ai/docs)
148
- - **Issues**: [GitHub Issues](https://github.com/debugg-ai/debugg-ai-mcp/issues)
149
- - **Discord**: [debugg.ai/discord](https://debugg.ai/discord)
62
+ [Dashboard](https://app.debugg.ai) · [Docs](https://debugg.ai/docs) · [Issues](https://github.com/debugg-ai/debugg-ai-mcp/issues) · [Discord](https://debugg.ai/discord)
150
63
 
151
64
  ---
152
65
 
@@ -20,6 +20,9 @@ export async function testPageChangesHandler(input, context, progressCallback) {
20
20
  const originalUrl = resolveTargetUrl(input);
21
21
  let ctx = buildContext(originalUrl);
22
22
  let ngrokKeyId;
23
+ const abortController = new AbortController();
24
+ const onStdinClose = () => abortController.abort();
25
+ process.stdin.once('close', onStdinClose);
23
26
  try {
24
27
  // --- Find workflow template ---
25
28
  if (progressCallback) {
@@ -93,7 +96,7 @@ export async function testPageChangesHandler(input, context, progressCallback) {
93
96
  : exec.status;
94
97
  await progressCallback({ progress, total: 10, message });
95
98
  }
96
- });
99
+ }, abortController.signal);
97
100
  const duration = Date.now() - startTime;
98
101
  // --- Format result ---
99
102
  const outcome = finalExecution.state?.outcome ?? finalExecution.status;
@@ -152,6 +155,7 @@ export async function testPageChangesHandler(input, context, progressCallback) {
152
155
  throw handleExternalServiceError(error, 'DebuggAI', 'test execution');
153
156
  }
154
157
  finally {
158
+ process.stdin.removeListener('close', onStdinClose);
155
159
  if (ngrokKeyId) {
156
160
  client.revokeNgrokKey(ngrokKeyId).catch(err => logger.warn(`Failed to revoke ngrok key ${ngrokKeyId}: ${err}`));
157
161
  }
@@ -10,8 +10,15 @@ export const createWorkflowsService = (tx) => {
10
10
  async findEvaluationTemplate() {
11
11
  const response = await tx.get('api/v1/workflows/', { isTemplate: true });
12
12
  const templates = response?.results ?? [];
13
+ if (templates.length === 0)
14
+ return null;
13
15
  const evalTemplate = templates.find(t => t.name.toLowerCase().includes('app evaluation'));
14
- return evalTemplate ?? templates[0] ?? null;
16
+ if (!evalTemplate) {
17
+ throw new Error(`No "App Evaluation" workflow template found. ` +
18
+ `Available templates: ${templates.map(t => `"${t.name}"`).join(', ')}. ` +
19
+ `Ensure the backend has a template with "App Evaluation" in its name.`);
20
+ }
21
+ return evalTemplate;
15
22
  },
16
23
  async executeWorkflow(workflowUuid, contextData, env) {
17
24
  const body = { contextData };
@@ -38,9 +45,12 @@ export const createWorkflowsService = (tx) => {
38
45
  }
39
46
  return response;
40
47
  },
41
- async pollExecution(executionUuid, onUpdate) {
48
+ async pollExecution(executionUuid, onUpdate, signal) {
42
49
  const deadline = Date.now() + EXECUTION_TIMEOUT_MS;
43
50
  while (Date.now() < deadline) {
51
+ if (signal?.aborted) {
52
+ throw new Error(`Polling cancelled for execution ${executionUuid}`);
53
+ }
44
54
  const execution = await service.getExecution(executionUuid);
45
55
  if (onUpdate) {
46
56
  await onUpdate(execution).catch(() => { });
@@ -48,7 +58,15 @@ export const createWorkflowsService = (tx) => {
48
58
  if (TERMINAL_STATUSES.has(execution.status)) {
49
59
  return execution;
50
60
  }
51
- await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
61
+ await new Promise((resolve, reject) => {
62
+ const timer = setTimeout(resolve, POLL_INTERVAL_MS);
63
+ if (signal) {
64
+ signal.addEventListener('abort', () => {
65
+ clearTimeout(timer);
66
+ reject(new Error(`Polling cancelled for execution ${executionUuid}`));
67
+ }, { once: true });
68
+ }
69
+ });
52
70
  }
53
71
  throw new Error(`Execution ${executionUuid} timed out after ${EXECUTION_TIMEOUT_MS / 1000}s`);
54
72
  }
@@ -15,79 +15,7 @@ export const TestPageChangesInputSchema = z.object({
15
15
  credentialRole: z.string().optional(),
16
16
  username: z.string().optional(),
17
17
  password: z.string().optional(),
18
- });
19
- /**
20
- * E2E Suite Tool Schemas
21
- */
22
- export const ListTestsInputSchema = z.object({
23
- repoName: z.string().optional(),
24
- branchName: z.string().optional(),
25
- status: z.enum(['pending', 'running', 'completed', 'failed']).optional(),
26
- page: z.number().int().positive().optional().default(1),
27
- limit: z.number().int().min(1).max(100).optional().default(20),
28
- });
29
- export const ListTestSuitesInputSchema = z.object({
30
- repoName: z.string().optional(),
31
- branchName: z.string().optional(),
32
- status: z.enum(['pending', 'running', 'completed', 'failed']).optional(),
33
- page: z.number().int().positive().optional().default(1),
34
- limit: z.number().int().min(1).max(100).optional().default(20),
35
- });
36
- export const CreateTestSuiteInputSchema = z.object({
37
- description: z.string().min(1, 'Description is required'),
38
- repoName: z.string().optional(),
39
- branchName: z.string().optional(),
40
- repoPath: z.string().optional(),
41
- filePath: z.string().optional(),
42
- });
43
- export const CreateCommitSuiteInputSchema = z.object({
44
- description: z.string().min(1, 'Description is required'),
45
- repoName: z.string().optional(),
46
- branchName: z.string().optional(),
47
- repoPath: z.string().optional(),
48
- filePath: z.string().optional(),
49
- });
50
- export const ListCommitSuitesInputSchema = z.object({
51
- repoName: z.string().optional(),
52
- branchName: z.string().optional(),
53
- status: z.enum(['pending', 'running', 'completed', 'failed']).optional(),
54
- page: z.number().int().positive().optional().default(1),
55
- limit: z.number().int().min(1).max(100).optional().default(20),
56
- });
57
- export const GetTestStatusInputSchema = z.object({
58
- suiteUuid: z.string().uuid('Invalid suite UUID'),
59
- suiteType: z.enum(['test', 'commit']).optional().default('test'),
60
- });
61
- /**
62
- * Live Session Tool Schemas
63
- */
64
- export const StartLiveSessionInputSchema = z.object({
65
- url: z.string().min(1, 'URL is required'),
66
- localPort: z.number().int().min(1).max(65535).optional(),
67
- sessionName: z.string().max(100).optional(),
68
- monitorConsole: z.boolean().optional().default(true),
69
- monitorNetwork: z.boolean().optional().default(true),
70
- takeScreenshots: z.boolean().optional().default(false),
71
- screenshotInterval: z.number().int().min(1).max(300).optional().default(10),
72
- });
73
- export const StopLiveSessionInputSchema = z.object({
74
- sessionId: z.string().optional(),
75
- });
76
- export const GetLiveSessionStatusInputSchema = z.object({
77
- sessionId: z.string().optional(),
78
- });
79
- export const GetLiveSessionLogsInputSchema = z.object({
80
- sessionId: z.string().optional(),
81
- logType: z.enum(['console', 'network', 'errors', 'all']).optional().default('all'),
82
- since: z.string().datetime().optional(),
83
- limit: z.number().int().min(1).max(1000).optional().default(100),
84
- });
85
- export const GetLiveSessionScreenshotInputSchema = z.object({
86
- sessionId: z.string().optional(),
87
- fullPage: z.boolean().optional().default(false),
88
- quality: z.number().int().min(1).max(100).optional().default(90),
89
- format: z.enum(['png', 'jpeg']).optional().default('png'),
90
- });
18
+ }).refine((data) => data.url !== undefined || data.localPort !== undefined, { message: 'Provide a target via "url" (e.g. "https://example.com") or "localPort" for a local dev server' });
91
19
  /**
92
20
  * Error types
93
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "1.0.30",
3
+ "version": "1.0.31",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "bin": {