@debugg-ai/debugg-ai-mcp 1.0.58 → 1.0.59

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
@@ -32,7 +32,7 @@ docker run -i --rm --init -e DEBUGGAI_API_KEY=your_api_key quinnosha/debugg-ai-m
32
32
 
33
33
  ## Tools
34
34
 
35
- The server exposes **18** tools. The headline one is `check_app_in_browser`; the rest manage projects, environments, credentials, and workflow execution history.
35
+ The server exposes **21** tools. The headline one is `check_app_in_browser`; the rest manage projects, environments, credentials, workflow execution history, and the teams/repos needed to create new projects.
36
36
 
37
37
  ### `check_app_in_browser`
38
38
 
@@ -55,9 +55,17 @@ Runs an AI browser agent against your app. The agent navigates, interacts, and r
55
55
  |------|---------|
56
56
  | `list_projects` | List projects accessible to your API key. Optional `q` for name/repo search. |
57
57
  | `get_project` | Fetch a project by `uuid`. Simplified shape (no team/runner internals). |
58
+ | `create_project` | Create a new project. Needs `name`, `platform` (e.g. `web`), `teamUuid` (from `list_teams`), and `repoUuid` (from `list_repos`). |
58
59
  | `update_project` | PATCH a project's `name` or `description`. |
59
60
  | `delete_project` | Destructive delete. Cascades envs, creds, and history. |
60
61
 
62
+ ### Teams and repos (prerequisites for `create_project`)
63
+
64
+ | Tool | Purpose |
65
+ |------|---------|
66
+ | `list_teams` | Paginated list of teams accessible to the API key; optional `q` for search. |
67
+ | `list_repos` | Paginated list of GitHub-linked repos; optional `q` for search. Use repos with `isGithubAuthorized: true` when creating a project. |
68
+
61
69
  ### Environment management (scoped to a project)
62
70
 
63
71
  | Tool | Purpose |
@@ -0,0 +1,31 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ import { handleExternalServiceError } from '../utils/errors.js';
3
+ import { DebuggAIServerClient } from '../services/index.js';
4
+ import { config } from '../config/index.js';
5
+ const logger = new Logger({ module: 'createProjectHandler' });
6
+ export async function createProjectHandler(input, _context) {
7
+ const start = Date.now();
8
+ logger.toolStart('create_project', {
9
+ name: input.name,
10
+ platform: input.platform,
11
+ teamUuid: input.teamUuid,
12
+ repoUuid: input.repoUuid,
13
+ });
14
+ try {
15
+ const client = new DebuggAIServerClient(config.api.key);
16
+ await client.init();
17
+ const project = await client.createProject({
18
+ name: input.name,
19
+ platform: input.platform,
20
+ teamUuid: input.teamUuid,
21
+ repoUuid: input.repoUuid,
22
+ });
23
+ const payload = { created: true, project };
24
+ logger.toolComplete('create_project', Date.now() - start);
25
+ return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
26
+ }
27
+ catch (error) {
28
+ logger.toolError('create_project', error, Date.now() - start);
29
+ throw handleExternalServiceError(error, 'DebuggAI', 'create_project');
30
+ }
31
+ }
@@ -16,3 +16,6 @@ export * from './deleteProjectHandler.js';
16
16
  export * from './listExecutionsHandler.js';
17
17
  export * from './getExecutionHandler.js';
18
18
  export * from './cancelExecutionHandler.js';
19
+ export * from './listTeamsHandler.js';
20
+ export * from './listReposHandler.js';
21
+ export * from './createProjectHandler.js';
@@ -0,0 +1,27 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ import { handleExternalServiceError } from '../utils/errors.js';
3
+ import { DebuggAIServerClient } from '../services/index.js';
4
+ import { config } from '../config/index.js';
5
+ import { toPaginationParams } from '../utils/pagination.js';
6
+ const logger = new Logger({ module: 'listReposHandler' });
7
+ export async function listReposHandler(input, _context) {
8
+ const start = Date.now();
9
+ const pagination = toPaginationParams({ page: input.page, pageSize: input.pageSize });
10
+ logger.toolStart('list_repos', { q: input.q, ...pagination });
11
+ try {
12
+ const client = new DebuggAIServerClient(config.api.key);
13
+ await client.init();
14
+ const { pageInfo, repos } = await client.listRepos(pagination, input.q);
15
+ const payload = {
16
+ filter: { q: input.q ?? null },
17
+ pageInfo,
18
+ repos,
19
+ };
20
+ logger.toolComplete('list_repos', Date.now() - start);
21
+ return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
22
+ }
23
+ catch (error) {
24
+ logger.toolError('list_repos', error, Date.now() - start);
25
+ throw handleExternalServiceError(error, 'DebuggAI', 'list_repos');
26
+ }
27
+ }
@@ -0,0 +1,27 @@
1
+ import { Logger } from '../utils/logger.js';
2
+ import { handleExternalServiceError } from '../utils/errors.js';
3
+ import { DebuggAIServerClient } from '../services/index.js';
4
+ import { config } from '../config/index.js';
5
+ import { toPaginationParams } from '../utils/pagination.js';
6
+ const logger = new Logger({ module: 'listTeamsHandler' });
7
+ export async function listTeamsHandler(input, _context) {
8
+ const start = Date.now();
9
+ const pagination = toPaginationParams({ page: input.page, pageSize: input.pageSize });
10
+ logger.toolStart('list_teams', { q: input.q, ...pagination });
11
+ try {
12
+ const client = new DebuggAIServerClient(config.api.key);
13
+ await client.init();
14
+ const { pageInfo, teams } = await client.listTeams(pagination, input.q);
15
+ const payload = {
16
+ filter: { q: input.q ?? null },
17
+ pageInfo,
18
+ teams,
19
+ };
20
+ logger.toolComplete('list_teams', Date.now() - start);
21
+ return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
22
+ }
23
+ catch (error) {
24
+ logger.toolError('list_teams', error, Date.now() - start);
25
+ throw handleExternalServiceError(error, 'DebuggAI', 'list_teams');
26
+ }
27
+ }
@@ -132,6 +132,61 @@ export class DebuggAIServerClient {
132
132
  projects: response?.results ?? [],
133
133
  };
134
134
  }
135
+ async listTeams(pagination, q) {
136
+ if (!this.tx)
137
+ throw new Error('Client not initialized — call init() first');
138
+ const { makePageInfo } = await import('../utils/pagination.js');
139
+ const params = { page: pagination.page, pageSize: pagination.pageSize };
140
+ if (q)
141
+ params.search = q;
142
+ const response = await this.tx.get('api/v1/teams/', params);
143
+ return {
144
+ pageInfo: makePageInfo(pagination.page, pagination.pageSize, response?.count ?? 0, response?.next),
145
+ teams: (response?.results ?? []).map((t) => ({
146
+ uuid: t.uuid,
147
+ name: t.name,
148
+ description: t.description ?? null,
149
+ memberCount: t.memberCount ?? 0,
150
+ ownerCount: t.ownerCount ?? 0,
151
+ currentUserRole: t.currentUserRole ?? null,
152
+ })),
153
+ };
154
+ }
155
+ async listRepos(pagination, q) {
156
+ if (!this.tx)
157
+ throw new Error('Client not initialized — call init() first');
158
+ const { makePageInfo } = await import('../utils/pagination.js');
159
+ const params = { page: pagination.page, pageSize: pagination.pageSize };
160
+ if (q)
161
+ params.search = q;
162
+ const response = await this.tx.get('api/v1/repos/', params);
163
+ return {
164
+ pageInfo: makePageInfo(pagination.page, pagination.pageSize, response?.count ?? 0, response?.next),
165
+ repos: (response?.results ?? []).map((r) => ({
166
+ uuid: r.uuid,
167
+ name: r.name,
168
+ url: r.url ?? '',
169
+ description: r.description ?? null,
170
+ isPrivate: !!r.isPrivate,
171
+ isGithubAuthorized: !!r.isGithubAuthorized,
172
+ githubAccountLogin: r.githubAccountLogin ?? null,
173
+ })),
174
+ };
175
+ }
176
+ async createProject(input) {
177
+ if (!this.tx)
178
+ throw new Error('Client not initialized — call init() first');
179
+ // Backend expects `team` and `repo` keys (UUIDs). MCP surfaces them as
180
+ // teamUuid/repoUuid for clarity about what kind of UUID they are.
181
+ const body = {
182
+ name: input.name,
183
+ platform: input.platform,
184
+ team: input.teamUuid,
185
+ repo: input.repoUuid,
186
+ };
187
+ const p = await this.tx.post('api/v1/projects/', body);
188
+ return this.mapProjectDetail(p);
189
+ }
135
190
  /**
136
191
  * List environments for a project. Paginated.
137
192
  * Optional q filters by name via backend ?search=.
@@ -0,0 +1,25 @@
1
+ import { CreateProjectInputSchema } from '../types/index.js';
2
+ import { createProjectHandler } from '../handlers/createProjectHandler.js';
3
+ const DESCRIPTION = `Create a new DebuggAI project. Required: name, platform (e.g. "web"), teamUuid (from list_teams), repoUuid (from list_repos). Returns {created: true, project: {uuid, name, slug, platform, repoName, ...}}. The repo must be GitHub-linked to the account. Use list_teams + list_repos first to discover valid UUIDs.`;
4
+ export function buildCreateProjectTool() {
5
+ return {
6
+ name: 'create_project',
7
+ title: 'Create Project',
8
+ description: DESCRIPTION,
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ name: { type: 'string', description: 'Project name. Required.', minLength: 1 },
13
+ platform: { type: 'string', description: 'Platform (e.g. "web"). Required.', minLength: 1 },
14
+ teamUuid: { type: 'string', description: 'Team UUID (from list_teams). Required.' },
15
+ repoUuid: { type: 'string', description: 'GitHub repo UUID (from list_repos). Required — repo must be GitHub-linked.' },
16
+ },
17
+ required: ['name', 'platform', 'teamUuid', 'repoUuid'],
18
+ additionalProperties: false,
19
+ },
20
+ };
21
+ }
22
+ export function buildValidatedCreateProjectTool() {
23
+ const tool = buildCreateProjectTool();
24
+ return { ...tool, inputSchema: CreateProjectInputSchema, handler: createProjectHandler };
25
+ }
@@ -16,6 +16,9 @@ import { buildDeleteProjectTool, buildValidatedDeleteProjectTool } from './delet
16
16
  import { buildListExecutionsTool, buildValidatedListExecutionsTool } from './listExecutions.js';
17
17
  import { buildGetExecutionTool, buildValidatedGetExecutionTool } from './getExecution.js';
18
18
  import { buildCancelExecutionTool, buildValidatedCancelExecutionTool } from './cancelExecution.js';
19
+ import { buildListTeamsTool, buildValidatedListTeamsTool } from './listTeams.js';
20
+ import { buildListReposTool, buildValidatedListReposTool } from './listRepos.js';
21
+ import { buildCreateProjectTool, buildValidatedCreateProjectTool } from './createProject.js';
19
22
  let _tools = null;
20
23
  let _validatedTools = null;
21
24
  const toolRegistry = new Map();
@@ -42,6 +45,9 @@ export function initTools(ctx) {
42
45
  buildListExecutionsTool(),
43
46
  buildGetExecutionTool(),
44
47
  buildCancelExecutionTool(),
48
+ buildListTeamsTool(),
49
+ buildListReposTool(),
50
+ buildCreateProjectTool(),
45
51
  ];
46
52
  const validated = [
47
53
  buildValidatedTestPageChangesTool(ctx),
@@ -62,6 +68,9 @@ export function initTools(ctx) {
62
68
  buildValidatedListExecutionsTool(),
63
69
  buildValidatedGetExecutionTool(),
64
70
  buildValidatedCancelExecutionTool(),
71
+ buildValidatedListTeamsTool(),
72
+ buildValidatedListReposTool(),
73
+ buildValidatedCreateProjectTool(),
65
74
  ];
66
75
  _tools = tools;
67
76
  _validatedTools = validated;
@@ -0,0 +1,23 @@
1
+ import { ListReposInputSchema } from '../types/index.js';
2
+ import { listReposHandler } from '../handlers/listReposHandler.js';
3
+ const DESCRIPTION = `List GitHub repos linked to the current account. Paginated — every response includes pageInfo {page, pageSize, totalCount, totalPages, hasMore}; default pageSize 20, max 200. Optional q filters by repo name via backend search. Use this to discover repoUuid values required by create_project. Prefer repos with isGithubAuthorized:true since the backend needs a valid GitHub installation.`;
4
+ export function buildListReposTool() {
5
+ return {
6
+ name: 'list_repos',
7
+ title: 'List Linked Repos',
8
+ description: DESCRIPTION,
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ q: { type: 'string', description: 'Optional: filter by repo name.' },
13
+ page: { type: 'number', description: 'Optional: 1-indexed page number.', minimum: 1 },
14
+ pageSize: { type: 'number', description: 'Optional: items per page. Default 20, max 200.', minimum: 1, maximum: 200 },
15
+ },
16
+ additionalProperties: false,
17
+ },
18
+ };
19
+ }
20
+ export function buildValidatedListReposTool() {
21
+ const tool = buildListReposTool();
22
+ return { ...tool, inputSchema: ListReposInputSchema, handler: listReposHandler };
23
+ }
@@ -0,0 +1,23 @@
1
+ import { ListTeamsInputSchema } from '../types/index.js';
2
+ import { listTeamsHandler } from '../handlers/listTeamsHandler.js';
3
+ const DESCRIPTION = `List teams accessible to the current API key. Paginated — every response includes pageInfo {page, pageSize, totalCount, totalPages, hasMore}; default pageSize 20, max 200. Optional q filters by team name via backend search. Use this to discover teamUuid values required by create_project.`;
4
+ export function buildListTeamsTool() {
5
+ return {
6
+ name: 'list_teams',
7
+ title: 'List Teams',
8
+ description: DESCRIPTION,
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ q: { type: 'string', description: 'Optional: filter by team name.' },
13
+ page: { type: 'number', description: 'Optional: 1-indexed page number.', minimum: 1 },
14
+ pageSize: { type: 'number', description: 'Optional: items per page. Default 20, max 200.', minimum: 1, maximum: 200 },
15
+ },
16
+ additionalProperties: false,
17
+ },
18
+ };
19
+ }
20
+ export function buildValidatedListTeamsTool() {
21
+ const tool = buildListTeamsTool();
22
+ return { ...tool, inputSchema: ListTeamsInputSchema, handler: listTeamsHandler };
23
+ }
@@ -106,6 +106,22 @@ export const ListProjectsInputSchema = z.object({
106
106
  page: z.number().int().min(1).optional(),
107
107
  pageSize: z.number().int().min(1).optional(),
108
108
  }).strict();
109
+ export const ListTeamsInputSchema = z.object({
110
+ q: z.string().min(1).optional(),
111
+ page: z.number().int().min(1).optional(),
112
+ pageSize: z.number().int().min(1).optional(),
113
+ }).strict();
114
+ export const ListReposInputSchema = z.object({
115
+ q: z.string().min(1).optional(),
116
+ page: z.number().int().min(1).optional(),
117
+ pageSize: z.number().int().min(1).optional(),
118
+ }).strict();
119
+ export const CreateProjectInputSchema = z.object({
120
+ name: z.string().min(1),
121
+ platform: z.string().min(1),
122
+ teamUuid: z.string().uuid(),
123
+ repoUuid: z.string().uuid(),
124
+ }).strict();
109
125
  /**
110
126
  * Error types
111
127
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "1.0.58",
3
+ "version": "1.0.59",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "bin": {