@perfai/mcp 1.0.24

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 (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +352 -0
  3. package/dist/auth/authManager.d.ts +83 -0
  4. package/dist/auth/authManager.d.ts.map +1 -0
  5. package/dist/auth/authManager.js +555 -0
  6. package/dist/auth/sessionCache.d.ts +5 -0
  7. package/dist/auth/sessionCache.d.ts.map +1 -0
  8. package/dist/auth/sessionCache.js +29 -0
  9. package/dist/auth/sessionStorage.d.ts +53 -0
  10. package/dist/auth/sessionStorage.d.ts.map +1 -0
  11. package/dist/auth/sessionStorage.js +234 -0
  12. package/dist/auth/types.d.ts +28 -0
  13. package/dist/auth/types.d.ts.map +1 -0
  14. package/dist/auth/types.js +1 -0
  15. package/dist/config.d.ts +65 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +74 -0
  18. package/dist/server.d.ts +3 -0
  19. package/dist/server.d.ts.map +1 -0
  20. package/dist/server.js +144 -0
  21. package/dist/setup-config.d.ts +4 -0
  22. package/dist/setup-config.d.ts.map +1 -0
  23. package/dist/setup-config.js +69 -0
  24. package/dist/tools/index.d.ts +361 -0
  25. package/dist/tools/index.d.ts.map +1 -0
  26. package/dist/tools/index.js +275 -0
  27. package/dist/tools/protected/aiFixDesignIssue.d.ts +17 -0
  28. package/dist/tools/protected/aiFixDesignIssue.d.ts.map +1 -0
  29. package/dist/tools/protected/aiFixDesignIssue.js +205 -0
  30. package/dist/tools/protected/aiFixQualityIssue.d.ts +17 -0
  31. package/dist/tools/protected/aiFixQualityIssue.d.ts.map +1 -0
  32. package/dist/tools/protected/aiFixQualityIssue.js +188 -0
  33. package/dist/tools/protected/aiFixSecurityIssue.d.ts +17 -0
  34. package/dist/tools/protected/aiFixSecurityIssue.d.ts.map +1 -0
  35. package/dist/tools/protected/aiFixSecurityIssue.js +205 -0
  36. package/dist/tools/protected/checkDesignFixes.d.ts +17 -0
  37. package/dist/tools/protected/checkDesignFixes.d.ts.map +1 -0
  38. package/dist/tools/protected/checkDesignFixes.js +199 -0
  39. package/dist/tools/protected/checkQualityFixes.d.ts +17 -0
  40. package/dist/tools/protected/checkQualityFixes.d.ts.map +1 -0
  41. package/dist/tools/protected/checkQualityFixes.js +199 -0
  42. package/dist/tools/protected/checkSecurityFixes.d.ts +17 -0
  43. package/dist/tools/protected/checkSecurityFixes.d.ts.map +1 -0
  44. package/dist/tools/protected/checkSecurityFixes.js +177 -0
  45. package/dist/tools/protected/listApis.d.ts +28 -0
  46. package/dist/tools/protected/listApis.d.ts.map +1 -0
  47. package/dist/tools/protected/listApis.js +102 -0
  48. package/dist/tools/protected/logout.d.ts +11 -0
  49. package/dist/tools/protected/logout.d.ts.map +1 -0
  50. package/dist/tools/protected/logout.js +22 -0
  51. package/dist/tools/protected/manageOrganizations.d.ts +26 -0
  52. package/dist/tools/protected/manageOrganizations.d.ts.map +1 -0
  53. package/dist/tools/protected/manageOrganizations.js +147 -0
  54. package/dist/tools/protected/runDesignTest.d.ts +21 -0
  55. package/dist/tools/protected/runDesignTest.d.ts.map +1 -0
  56. package/dist/tools/protected/runDesignTest.js +132 -0
  57. package/dist/tools/protected/runQualityTest.d.ts +21 -0
  58. package/dist/tools/protected/runQualityTest.d.ts.map +1 -0
  59. package/dist/tools/protected/runQualityTest.js +150 -0
  60. package/dist/tools/protected/runSecurityTest.d.ts +21 -0
  61. package/dist/tools/protected/runSecurityTest.d.ts.map +1 -0
  62. package/dist/tools/protected/runSecurityTest.js +107 -0
  63. package/dist/tools/protected/selectApi.d.ts +24 -0
  64. package/dist/tools/protected/selectApi.d.ts.map +1 -0
  65. package/dist/tools/protected/selectApi.js +172 -0
  66. package/dist/tools/protected/setup.d.ts +11 -0
  67. package/dist/tools/protected/setup.d.ts.map +1 -0
  68. package/dist/tools/protected/setup.js +151 -0
  69. package/dist/tools/protected/showDesignIssues.d.ts +38 -0
  70. package/dist/tools/protected/showDesignIssues.d.ts.map +1 -0
  71. package/dist/tools/protected/showDesignIssues.js +201 -0
  72. package/dist/tools/protected/showFixedIssues.d.ts +11 -0
  73. package/dist/tools/protected/showFixedIssues.d.ts.map +1 -0
  74. package/dist/tools/protected/showFixedIssues.js +36 -0
  75. package/dist/tools/protected/showQualityIssues.d.ts +33 -0
  76. package/dist/tools/protected/showQualityIssues.d.ts.map +1 -0
  77. package/dist/tools/protected/showQualityIssues.js +225 -0
  78. package/dist/tools/protected/showSecurityIssues.d.ts +47 -0
  79. package/dist/tools/protected/showSecurityIssues.d.ts.map +1 -0
  80. package/dist/tools/protected/showSecurityIssues.js +212 -0
  81. package/dist/tools/protected/summarizeIssues.d.ts +11 -0
  82. package/dist/tools/protected/summarizeIssues.d.ts.map +1 -0
  83. package/dist/tools/protected/summarizeIssues.js +161 -0
  84. package/dist/tools/protected/userInfo.d.ts +11 -0
  85. package/dist/tools/protected/userInfo.d.ts.map +1 -0
  86. package/dist/tools/protected/userInfo.js +21 -0
  87. package/dist/tools/protected/visionAiAppLearning.d.ts +37 -0
  88. package/dist/tools/protected/visionAiAppLearning.d.ts.map +1 -0
  89. package/dist/tools/protected/visionAiAppLearning.js +122 -0
  90. package/dist/tools/public/authStatus.d.ts +11 -0
  91. package/dist/tools/public/authStatus.d.ts.map +1 -0
  92. package/dist/tools/public/authStatus.js +78 -0
  93. package/dist/tools/public/login.d.ts +12 -0
  94. package/dist/tools/public/login.d.ts.map +1 -0
  95. package/dist/tools/public/login.js +230 -0
  96. package/dist/types/api.d.ts +12 -0
  97. package/dist/types/api.d.ts.map +1 -0
  98. package/dist/types/api.js +1 -0
  99. package/dist/utils/dockerRunner.d.ts +44 -0
  100. package/dist/utils/dockerRunner.d.ts.map +1 -0
  101. package/dist/utils/dockerRunner.js +300 -0
  102. package/dist/utils/formatters.d.ts +14 -0
  103. package/dist/utils/formatters.d.ts.map +1 -0
  104. package/dist/utils/formatters.js +510 -0
  105. package/dist/utils/promptBuilder.d.ts +4 -0
  106. package/dist/utils/promptBuilder.d.ts.map +1 -0
  107. package/dist/utils/promptBuilder.js +132 -0
  108. package/package.json +67 -0
@@ -0,0 +1,205 @@
1
+ import axios from "axios";
2
+ import { API_ENDPOINTS } from "../../config.js";
3
+ import { buildAIFixDesignPrompt } from "../../utils/promptBuilder.js";
4
+ export const aiFixDesignIssueTool = {
5
+ name: "ai_fix_design_issue",
6
+ description: "šŸŽØ Generate AI-powered fix prompt for a design issue by sequence number or description (requires authentication)",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ issue_id: {
11
+ type: "string",
12
+ description: "The design issue ID, sequence number (e.g., '14'), or descriptive text like 'Application Design Issues/Inconsistent Naming • GET /users'"
13
+ }
14
+ },
15
+ required: ["issue_id"],
16
+ additionalProperties: false,
17
+ },
18
+ };
19
+ export async function handleAiFixDesignIssue(authManager, args) {
20
+ try {
21
+ const issueIdOrDescription = args.issue_id;
22
+ const accessToken = authManager.getAccessToken();
23
+ const tokenType = authManager.getTokenType();
24
+ const orgId = authManager.getSelectedOrgId();
25
+ if (!accessToken) {
26
+ throw new Error('No access token available');
27
+ }
28
+ if (!orgId) {
29
+ throw new Error('No organization selected. Please select an organization first using manage_organizations tool.');
30
+ }
31
+ if (!issueIdOrDescription) {
32
+ throw new Error('Issue ID or description is required');
33
+ }
34
+ // Get the selected APP and design app ID (same logic as security)
35
+ const selectedAppId = authManager.getSelectedApiId();
36
+ const selectedAppData = authManager.getSelectedApiData();
37
+ if (!selectedAppId) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `āŒ **No APP Selected**\n\nšŸŽÆ **Required**: You must select an APP first to fix its design issues.\n\nšŸ“‹ **Steps**:\n1. Run \`list_apps\` to see available APPs\n2. Run \`select_app\` with an APP ID\n3. Then run this tool again`,
43
+ },
44
+ ],
45
+ };
46
+ }
47
+ // First, get the app details using the catalog ID to get the design app ID
48
+ const catalogUrl = `${API_ENDPOINTS.API_CATALOG_SERVICE_IDS}/${selectedAppId}`;
49
+ let appDetails;
50
+ try {
51
+ const catalogResponse = await axios.get(catalogUrl, {
52
+ headers: {
53
+ 'Authorization': `${tokenType} ${accessToken}`,
54
+ 'Content-Type': 'application/json',
55
+ 'X-Org-ID': orgId
56
+ },
57
+ timeout: 30000
58
+ });
59
+ if (catalogResponse.status !== 200 || !catalogResponse.data) {
60
+ throw new Error(`Failed to fetch app details with status ${catalogResponse.status}`);
61
+ }
62
+ appDetails = catalogResponse.data;
63
+ if (!appDetails.design_test_appId) {
64
+ throw new Error('No design_test_appId found for this app');
65
+ }
66
+ }
67
+ catch (error) {
68
+ const errorMessage = error instanceof Error ? error.message : String(error);
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: `āŒ **Error fetching app details**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure the selected app has design testing enabled.`,
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ // Use the design_test_appId for fetching design issues
79
+ const designAppId = appDetails.design_test_appId;
80
+ // Fetch design issues for the specific API
81
+ const url = `${API_ENDPOINTS.DESIGN_ISSUES_BY_APP}?app_id=${encodeURIComponent(designAppId)}&limit=100`;
82
+ const response = await axios.get(url, {
83
+ headers: {
84
+ 'Authorization': `${tokenType} ${accessToken}`,
85
+ 'Content-Type': 'application/json',
86
+ 'X-Org-ID': orgId
87
+ },
88
+ timeout: 30000
89
+ });
90
+ if (response.status !== 200 || !response.data) {
91
+ throw new Error(`Failed to fetch design issues: ${response.status}`);
92
+ }
93
+ const issues = response.data.issues || [];
94
+ let targetIssue = null;
95
+ let issueId = '';
96
+ // Check if input is a sequence number (numeric string)
97
+ const sequenceNumber = parseInt(issueIdOrDescription);
98
+ if (!isNaN(sequenceNumber) && sequenceNumber > 0) {
99
+ // Input is a sequence number, get the issue by index (1-based)
100
+ const issueIndex = sequenceNumber - 1;
101
+ if (issueIndex >= 0 && issueIndex < issues.length) {
102
+ targetIssue = issues[issueIndex];
103
+ issueId = targetIssue._id;
104
+ }
105
+ else {
106
+ return {
107
+ content: [
108
+ {
109
+ type: "text",
110
+ text: `āŒ **Invalid Sequence Number**\n\nšŸ”“ **Error**: Sequence number '${sequenceNumber}' is out of range\n\nšŸ“‹ **Available range**: 1 to ${issues.length}\n\nšŸ’” **Tip**: Use show_design_issues to see the current list of issues with their sequence numbers.`,
111
+ },
112
+ ],
113
+ };
114
+ }
115
+ }
116
+ else {
117
+ // Try to find issue by exact ID first
118
+ targetIssue = issues.find((issue) => issue._id === issueIdOrDescription);
119
+ if (targetIssue) {
120
+ issueId = targetIssue._id;
121
+ }
122
+ else {
123
+ // Parse descriptive text to find matching issue
124
+ // Format: "Application Design Issues/Inconsistent Naming • GET /users"
125
+ const descriptionLower = issueIdOrDescription.toLowerCase();
126
+ for (const issue of issues) {
127
+ const category = (issue.category || '').toLowerCase();
128
+ const method = (issue.method || 'multiple').toLowerCase();
129
+ const path = (issue.path || '').toLowerCase();
130
+ // Check if description matches this issue
131
+ const categoryMatch = category && descriptionLower.includes(category);
132
+ const methodMatch = method && descriptionLower.includes(method);
133
+ const pathMatch = path && descriptionLower.includes(path);
134
+ // Additional fuzzy matching for common patterns
135
+ const isApiDesign = descriptionLower.includes('api design');
136
+ const isInconsistent = descriptionLower.includes('inconsistent');
137
+ const isNaming = descriptionLower.includes('naming');
138
+ if ((categoryMatch && (methodMatch || pathMatch)) ||
139
+ (isApiDesign && isInconsistent && isNaming && pathMatch)) {
140
+ targetIssue = issue;
141
+ issueId = issue._id;
142
+ break;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ if (!targetIssue) {
148
+ // Try partial matching as last resort
149
+ const firstIssueOfType = issues.find((issue) => {
150
+ const category = (issue.category || '').toLowerCase();
151
+ return issueIdOrDescription.toLowerCase().includes(category) ||
152
+ category.includes(issueIdOrDescription.toLowerCase().split('•')[0].trim());
153
+ });
154
+ if (firstIssueOfType) {
155
+ targetIssue = firstIssueOfType;
156
+ issueId = firstIssueOfType._id;
157
+ }
158
+ else {
159
+ const availableIssues = issues.slice(0, 3).map((issue) => {
160
+ const method = issue.method || 'MULTIPLE';
161
+ const path = issue.path || '/unknown';
162
+ return `${issue.category || issue.label} • ${method} ${path}`;
163
+ });
164
+ return {
165
+ content: [
166
+ {
167
+ type: "text",
168
+ text: `āŒ **Issue Not Found**\n\nšŸ”“ **Error**: Could not find design issue matching: "${issueIdOrDescription}"\n\nšŸ“‹ **Available Issues** (first 3):\n${availableIssues.map((issue) => `• ${issue}`).join('\n')}\n\nšŸ’” **Tip**: Use show_design_issues tool to see all issues, or try a more specific description.`,
169
+ },
170
+ ],
171
+ };
172
+ }
173
+ }
174
+ // Check if issue is already fixed and show previous fix info, but allow re-fixing
175
+ const isRefix = authManager.isDesignIssueFixed(issueId);
176
+ if (isRefix) {
177
+ const fixedIssue = authManager.getFixedDesignIssues().find((fi) => fi.issueId === issueId);
178
+ console.error(`šŸ”„ Re-fixing design issue: ${issueId} (previously fixed at ${fixedIssue?.fixedAt.toLocaleString()})`);
179
+ }
180
+ // Generate AI fix prompt (matching extension logic)
181
+ const prompt = buildAIFixDesignPrompt(targetIssue, isRefix);
182
+ // Mark issue as fixed in session (like the extension does)
183
+ const fixedIssue = authManager.markDesignIssueAsFixed(issueId, targetIssue, prompt);
184
+ // Return the prompt directly for MCP to execute
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: prompt,
190
+ },
191
+ ],
192
+ };
193
+ }
194
+ catch (error) {
195
+ const errorMessage = error instanceof Error ? error.message : String(error);
196
+ return {
197
+ content: [
198
+ {
199
+ type: "text",
200
+ text: `āŒ **Error generating AI design fix**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure you're authenticated, have an organization selected, and the issue ID is valid.\n\nšŸ”„ **Try**: Using show_design_issues tool first to see available issues.`,
201
+ },
202
+ ],
203
+ };
204
+ }
205
+ }
@@ -0,0 +1,17 @@
1
+ export declare const aiFixQualityIssueTool: {
2
+ readonly name: "ai_fix_quality_issue";
3
+ readonly description: "šŸ¤– Generate AI-powered fix prompt for a quality issue by sequence number or description (requires authentication)";
4
+ readonly inputSchema: {
5
+ readonly type: "object";
6
+ readonly properties: {
7
+ readonly issue_id: {
8
+ readonly type: "string";
9
+ readonly description: "The quality issue ID, sequence number (e.g., '14'), or descriptive text like 'Endpoint accessible without authentication [Authentication Flows] • GET /store/inventory'";
10
+ };
11
+ };
12
+ readonly required: readonly ["issue_id"];
13
+ readonly additionalProperties: false;
14
+ };
15
+ };
16
+ export declare function handleAiFixQualityIssue(authManager: any, args: any): Promise<any>;
17
+ //# sourceMappingURL=aiFixQualityIssue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiFixQualityIssue.d.ts","sourceRoot":"","sources":["../../../src/tools/protected/aiFixQualityIssue.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;CAcxB,CAAC;AAEX,wBAAsB,uBAAuB,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CA8LvF"}
@@ -0,0 +1,188 @@
1
+ import axios from "axios";
2
+ import { API_ENDPOINTS } from "../../config.js";
3
+ import { buildAIFixQualityPrompt } from "../../utils/promptBuilder.js";
4
+ export const aiFixQualityIssueTool = {
5
+ name: "ai_fix_quality_issue",
6
+ description: "šŸ¤– Generate AI-powered fix prompt for a quality issue by sequence number or description (requires authentication)",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ issue_id: {
11
+ type: "string",
12
+ description: "The quality issue ID, sequence number (e.g., '14'), or descriptive text like 'Endpoint accessible without authentication [Authentication Flows] • GET /store/inventory'"
13
+ }
14
+ },
15
+ required: ["issue_id"],
16
+ additionalProperties: false,
17
+ },
18
+ };
19
+ export async function handleAiFixQualityIssue(authManager, args) {
20
+ try {
21
+ const issueIdOrDescription = args.issue_id;
22
+ const accessToken = authManager.getAccessToken();
23
+ const tokenType = authManager.getTokenType();
24
+ const orgId = authManager.getSelectedOrgId();
25
+ if (!accessToken) {
26
+ throw new Error('No access token available');
27
+ }
28
+ if (!orgId) {
29
+ throw new Error('No organization selected. Please select an organization first using manage_organizations tool.');
30
+ }
31
+ if (!issueIdOrDescription) {
32
+ throw new Error('Issue ID or description is required');
33
+ }
34
+ // Get the selected APP and quality app ID (same logic as show_quality_issues)
35
+ const selectedAppId = authManager.getSelectedApiId();
36
+ const selectedAppData = authManager.getSelectedApiData();
37
+ if (!selectedAppId) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `āŒ **No APP Selected**\n\nšŸŽÆ **Required**: You must select an APP first to fix its quality issues.\n\nšŸ“‹ **Steps**:\n1. Run \`list_apps\` to see available APPs\n2. Run \`select_app\` with an APP ID\n3. Then run this tool again`,
43
+ },
44
+ ],
45
+ };
46
+ }
47
+ // First, get the app details using the catalog ID to get the quality_test_appId
48
+ const catalogUrl = `${API_ENDPOINTS.API_CATALOG_SERVICE_IDS}/${selectedAppId}`;
49
+ let appDetails;
50
+ try {
51
+ const catalogResponse = await axios.get(catalogUrl, {
52
+ headers: {
53
+ 'Authorization': `${tokenType} ${accessToken}`,
54
+ 'Content-Type': 'application/json',
55
+ 'X-Org-ID': orgId
56
+ },
57
+ timeout: 30000
58
+ });
59
+ if (catalogResponse.status !== 200 || !catalogResponse.data) {
60
+ throw new Error(`Failed to fetch app details with status ${catalogResponse.status}`);
61
+ }
62
+ appDetails = catalogResponse.data;
63
+ if (!appDetails.quality_test_appId) {
64
+ throw new Error('No quality_test_appId found for this app');
65
+ }
66
+ }
67
+ catch (error) {
68
+ const errorMessage = error instanceof Error ? error.message : String(error);
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: `āŒ **Error fetching app details**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure the selected app has quality testing enabled.`,
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ // Use the quality_test_appId for fetching quality issues
79
+ const qualityAppId = appDetails.quality_test_appId;
80
+ // Fetch quality issues for the specific API (using same endpoint as show_quality_issues)
81
+ const url = `${API_ENDPOINTS.QUALITY_ISSUES_BY_APP}/${qualityAppId}?page=1&pageSize=100`;
82
+ const response = await axios.get(url, {
83
+ headers: {
84
+ 'Authorization': `${tokenType} ${accessToken}`,
85
+ 'Content-Type': 'application/json',
86
+ 'X-Org-ID': orgId
87
+ },
88
+ timeout: 30000
89
+ });
90
+ if (response.status !== 200 || !response.data) {
91
+ throw new Error(`Failed to fetch quality issues: ${response.status}`);
92
+ }
93
+ const issues = response.data.items || [];
94
+ let targetIssue = null;
95
+ let issueId = '';
96
+ // Check if input is a sequence number (numeric string)
97
+ const sequenceNumber = parseInt(issueIdOrDescription);
98
+ if (!isNaN(sequenceNumber) && sequenceNumber > 0) {
99
+ // Input is a sequence number, get the issue by index (1-based)
100
+ const issueIndex = sequenceNumber - 1;
101
+ if (issueIndex >= 0 && issueIndex < issues.length) {
102
+ targetIssue = issues[issueIndex];
103
+ issueId = targetIssue._id;
104
+ }
105
+ else {
106
+ return {
107
+ content: [
108
+ {
109
+ type: "text",
110
+ text: `āŒ **Invalid Sequence Number**\n\nšŸ”“ **Error**: Sequence number '${sequenceNumber}' is out of range\n\nšŸ“‹ **Available range**: 1 to ${issues.length}\n\nšŸ’” **Tip**: Use show_quality_issues to see the current list of issues with their sequence numbers.`,
111
+ },
112
+ ],
113
+ };
114
+ }
115
+ }
116
+ else {
117
+ // Try to find issue by exact ID first
118
+ targetIssue = issues.find((issue) => issue._id === issueIdOrDescription);
119
+ if (targetIssue) {
120
+ issueId = targetIssue._id;
121
+ }
122
+ else {
123
+ // Parse descriptive text to find matching issue
124
+ // Format: "Endpoint accessible without authentication [Authentication Flows] • GET /store/inventory"
125
+ const descriptionLower = issueIdOrDescription.toLowerCase();
126
+ for (const issue of issues) {
127
+ const bugTitle = (issue.bug_title || '').toLowerCase();
128
+ const tags = (issue.tags || []).join(' ').toLowerCase();
129
+ const method = (issue.method || 'multiple').toLowerCase();
130
+ const path = (issue.path || '').toLowerCase();
131
+ // Check if description matches this issue
132
+ const bugTitleMatch = bugTitle && descriptionLower.includes(bugTitle);
133
+ const tagsMatch = tags && descriptionLower.includes(tags);
134
+ const methodMatch = method && descriptionLower.includes(method);
135
+ const pathMatch = path && descriptionLower.includes(path);
136
+ // If any key parts match, consider it a match
137
+ if (bugTitleMatch || (tagsMatch && methodMatch) || (methodMatch && pathMatch)) {
138
+ targetIssue = issue;
139
+ issueId = issue._id;
140
+ break;
141
+ }
142
+ }
143
+ if (!targetIssue) {
144
+ return {
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: `āŒ **Issue Not Found**\n\nšŸ”“ **Error**: No quality issue found matching '${issueIdOrDescription}'\n\nšŸ’” **Tips**:\n• Use show_quality_issues to see available issues\n• Use sequence numbers (e.g., '1', '2', '3')\n• Use partial descriptions like 'authentication' or 'GET /store'`,
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ }
154
+ }
155
+ // Generate AI fix prompt using the quality issue
156
+ const prompt = buildAIFixQualityPrompt(targetIssue);
157
+ // Store the fixed issue in the session
158
+ const fixedIssue = {
159
+ issueId: issueId,
160
+ issue: targetIssue,
161
+ fixedAt: new Date(),
162
+ prompt: prompt,
163
+ status: "ai-fixed"
164
+ };
165
+ // Add to fixed quality issues
166
+ authManager.addFixedQualityIssue(fixedIssue);
167
+ // Return the AI fix prompt
168
+ return {
169
+ content: [
170
+ {
171
+ type: "text",
172
+ text: `šŸ¤– **AI Fix Generated for Quality Issue**\n\nšŸŽÆ **Issue**: ${targetIssue.bug_title || targetIssue.name}\nšŸ†” **ID**: ${issueId}\nšŸ“ **Endpoint**: ${targetIssue.method?.toUpperCase() || 'UNKNOWN'} ${targetIssue.path || '/unknown'}\nšŸ·ļø **Tags**: ${targetIssue.tags?.join(', ') || 'None'}\n\n---\n\n**AI Fix Prompt:**\n\n${prompt}\n\n---\n\nāœ… **Status**: Issue marked as AI-fixed and added to fixed issues list\n\nšŸ’” **Next Steps**:\n• Review the generated fix prompt\n• Implement the suggested changes in your code\n• Run \`show_fixed_quality_issues\` to see all fixed issues\n• Run \`check_quality_fixes\` after implementing to verify fixes`,
173
+ },
174
+ ],
175
+ };
176
+ }
177
+ catch (error) {
178
+ const errorMessage = error instanceof Error ? error.message : String(error);
179
+ return {
180
+ content: [
181
+ {
182
+ type: "text",
183
+ text: `āŒ **Error generating AI fix for quality issue**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure you're authenticated and have access to quality data.\n\nšŸ”„ **Try**: Re-running the 'login' tool if the error persists.`,
184
+ },
185
+ ],
186
+ };
187
+ }
188
+ }
@@ -0,0 +1,17 @@
1
+ export declare const aiFixSecurityIssueTool: {
2
+ readonly name: "ai_fix_security_issue";
3
+ readonly description: "šŸ¤– Generate AI-powered fix prompt for a security issue by sequence number or description (requires authentication)";
4
+ readonly inputSchema: {
5
+ readonly type: "object";
6
+ readonly properties: {
7
+ readonly issue_id: {
8
+ readonly type: "string";
9
+ readonly description: "The security issue ID, sequence number (e.g., '14'), or descriptive text like 'System Design Issues/Enumerable Resource ID • MULTIPLE /store'";
10
+ };
11
+ };
12
+ readonly required: readonly ["issue_id"];
13
+ readonly additionalProperties: false;
14
+ };
15
+ };
16
+ export declare function handleAiFixSecurityIssue(authManager: any, args: any): Promise<any>;
17
+ //# sourceMappingURL=aiFixSecurityIssue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiFixSecurityIssue.d.ts","sourceRoot":"","sources":["../../../src/tools/protected/aiFixSecurityIssue.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;CAczB,CAAC;AAEX,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAgNxF"}
@@ -0,0 +1,205 @@
1
+ import axios from "axios";
2
+ import { API_ENDPOINTS } from "../../config.js";
3
+ import { buildAIFixPrompt } from "../../utils/promptBuilder.js";
4
+ export const aiFixSecurityIssueTool = {
5
+ name: "ai_fix_security_issue",
6
+ description: "šŸ¤– Generate AI-powered fix prompt for a security issue by sequence number or description (requires authentication)",
7
+ inputSchema: {
8
+ type: "object",
9
+ properties: {
10
+ issue_id: {
11
+ type: "string",
12
+ description: "The security issue ID, sequence number (e.g., '14'), or descriptive text like 'System Design Issues/Enumerable Resource ID • MULTIPLE /store'"
13
+ }
14
+ },
15
+ required: ["issue_id"],
16
+ additionalProperties: false,
17
+ },
18
+ };
19
+ export async function handleAiFixSecurityIssue(authManager, args) {
20
+ try {
21
+ const issueIdOrDescription = args.issue_id;
22
+ const accessToken = authManager.getAccessToken();
23
+ const tokenType = authManager.getTokenType();
24
+ const orgId = authManager.getSelectedOrgId();
25
+ if (!accessToken) {
26
+ throw new Error('No access token available');
27
+ }
28
+ if (!orgId) {
29
+ throw new Error('No organization selected. Please select an organization first using manage_organizations tool.');
30
+ }
31
+ if (!issueIdOrDescription) {
32
+ throw new Error('Issue ID or description is required');
33
+ }
34
+ // Get the selected APP and security app ID (same logic as show_security_issues)
35
+ const selectedAppId = authManager.getSelectedApiId();
36
+ const selectedAppData = authManager.getSelectedApiData();
37
+ if (!selectedAppId) {
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text: `āŒ **No APP Selected**\n\nšŸŽÆ **Required**: You must select an APP first to fix its security issues.\n\nšŸ“‹ **Steps**:\n1. Run \`list_apps\` to see available APPs\n2. Run \`select_app\` with an APP ID\n3. Then run this tool again`,
43
+ },
44
+ ],
45
+ };
46
+ }
47
+ // First, get the app details using the catalog ID to get the security_privacy_test_appId
48
+ const catalogUrl = `${API_ENDPOINTS.API_CATALOG_SERVICE_IDS}/${selectedAppId}`;
49
+ let appDetails;
50
+ try {
51
+ const catalogResponse = await axios.get(catalogUrl, {
52
+ headers: {
53
+ 'Authorization': `${tokenType} ${accessToken}`,
54
+ 'Content-Type': 'application/json',
55
+ 'X-Org-ID': orgId
56
+ },
57
+ timeout: 30000
58
+ });
59
+ if (catalogResponse.status !== 200 || !catalogResponse.data) {
60
+ throw new Error(`Failed to fetch app details with status ${catalogResponse.status}`);
61
+ }
62
+ appDetails = catalogResponse.data;
63
+ if (!appDetails.security_privacy_test_appId) {
64
+ throw new Error('No security_privacy_test_appId found for this app');
65
+ }
66
+ }
67
+ catch (error) {
68
+ const errorMessage = error instanceof Error ? error.message : String(error);
69
+ return {
70
+ content: [
71
+ {
72
+ type: "text",
73
+ text: `āŒ **Error fetching app details**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure the selected app has security testing enabled.`,
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ // Use the security_privacy_test_appId for fetching security issues
79
+ const securityAppId = appDetails.security_privacy_test_appId;
80
+ // Fetch security issues for the specific API (using same endpoint as show_security_issues)
81
+ const url = `${API_ENDPOINTS.SECURITY_ISSUES_BY_APP}?app_id=${encodeURIComponent(securityAppId)}&limit=100`;
82
+ const response = await axios.get(url, {
83
+ headers: {
84
+ 'Authorization': `${tokenType} ${accessToken}`,
85
+ 'Content-Type': 'application/json',
86
+ 'X-Org-ID': orgId
87
+ },
88
+ timeout: 30000
89
+ });
90
+ if (response.status !== 200 || !response.data) {
91
+ throw new Error(`Failed to fetch security issues: ${response.status}`);
92
+ }
93
+ const issues = response.data.data || [];
94
+ let targetIssue = null;
95
+ let issueId = '';
96
+ // Check if input is a sequence number (numeric string)
97
+ const sequenceNumber = parseInt(issueIdOrDescription);
98
+ if (!isNaN(sequenceNumber) && sequenceNumber > 0) {
99
+ // Input is a sequence number, get the issue by index (1-based)
100
+ const issueIndex = sequenceNumber - 1;
101
+ if (issueIndex >= 0 && issueIndex < issues.length) {
102
+ targetIssue = issues[issueIndex];
103
+ issueId = targetIssue._id;
104
+ }
105
+ else {
106
+ return {
107
+ content: [
108
+ {
109
+ type: "text",
110
+ text: `āŒ **Invalid Sequence Number**\n\nšŸ”“ **Error**: Sequence number '${sequenceNumber}' is out of range\n\nšŸ“‹ **Available range**: 1 to ${issues.length}\n\nšŸ’” **Tip**: Use show_security_issues to see the current list of issues with their sequence numbers.`,
111
+ },
112
+ ],
113
+ };
114
+ }
115
+ }
116
+ else {
117
+ // Try to find issue by exact ID first
118
+ targetIssue = issues.find((issue) => issue._id === issueIdOrDescription);
119
+ if (targetIssue) {
120
+ issueId = targetIssue._id;
121
+ }
122
+ else {
123
+ // Parse descriptive text to find matching issue
124
+ // Format: "System Design Issues/Enumerable Resource ID • MULTIPLE /store"
125
+ const descriptionLower = issueIdOrDescription.toLowerCase();
126
+ for (const issue of issues) {
127
+ const label = (issue.label || '').toLowerCase();
128
+ const method = (issue.method || 'multiple').toLowerCase();
129
+ const path = (issue.path || '').toLowerCase();
130
+ // Check if description matches this issue
131
+ const labelMatch = label && descriptionLower.includes(label);
132
+ const methodMatch = method && descriptionLower.includes(method);
133
+ const pathMatch = path && descriptionLower.includes(path);
134
+ // Additional fuzzy matching for common patterns
135
+ const isSystemDesign = descriptionLower.includes('system design');
136
+ const isEnumerable = descriptionLower.includes('enumerable');
137
+ const isResourceId = descriptionLower.includes('resource id');
138
+ if ((labelMatch && (methodMatch || pathMatch)) ||
139
+ (isSystemDesign && isEnumerable && isResourceId && pathMatch)) {
140
+ targetIssue = issue;
141
+ issueId = issue._id;
142
+ break;
143
+ }
144
+ }
145
+ }
146
+ }
147
+ if (!targetIssue) {
148
+ // Try partial matching as last resort
149
+ const firstIssueOfType = issues.find((issue) => {
150
+ const label = (issue.label || '').toLowerCase();
151
+ return issueIdOrDescription.toLowerCase().includes(label) ||
152
+ label.includes(issueIdOrDescription.toLowerCase().split('•')[0].trim());
153
+ });
154
+ if (firstIssueOfType) {
155
+ targetIssue = firstIssueOfType;
156
+ issueId = firstIssueOfType._id;
157
+ }
158
+ else {
159
+ const availableIssues = issues.slice(0, 3).map((issue) => {
160
+ const method = issue.method || 'MULTIPLE';
161
+ const path = issue.path || '/unknown';
162
+ return `${issue.label} • ${method} ${path}`;
163
+ });
164
+ return {
165
+ content: [
166
+ {
167
+ type: "text",
168
+ text: `āŒ **Issue Not Found**\n\nšŸ”“ **Error**: Could not find security issue matching: "${issueIdOrDescription}"\n\nšŸ“‹ **Available Issues** (first 3):\n${availableIssues.map((issue) => `• ${issue}`).join('\n')}\n\nšŸ’” **Tip**: Use show_security_issues tool to see all issues, or try a more specific description.`,
169
+ },
170
+ ],
171
+ };
172
+ }
173
+ }
174
+ // Check if issue is already fixed and show previous fix info, but allow re-fixing
175
+ const isRefix = authManager.isIssueFixed(issueId);
176
+ if (isRefix) {
177
+ const fixedIssue = authManager.getFixedIssues().find((fi) => fi.issueId === issueId);
178
+ console.error(`šŸ”„ Re-fixing issue: ${issueId} (previously fixed at ${fixedIssue?.fixedAt.toLocaleString()})`);
179
+ }
180
+ // Generate AI fix prompt (matching extension logic)
181
+ const prompt = buildAIFixPrompt(targetIssue, isRefix);
182
+ // Mark issue as fixed in session (like the extension does)
183
+ const fixedIssue = authManager.markIssueAsFixed(issueId, targetIssue, prompt);
184
+ // Return the prompt directly for MCP to execute
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: prompt,
190
+ },
191
+ ],
192
+ };
193
+ }
194
+ catch (error) {
195
+ const errorMessage = error instanceof Error ? error.message : String(error);
196
+ return {
197
+ content: [
198
+ {
199
+ type: "text",
200
+ text: `āŒ **Error generating AI fix**\n\nšŸ”“ **Error**: ${errorMessage}\n\nšŸ’” **Tip**: Make sure you're authenticated, have an organization selected, and the issue ID is valid.\n\nšŸ”„ **Try**: Using show_security_issues tool first to see available issues.`,
201
+ },
202
+ ],
203
+ };
204
+ }
205
+ }
@@ -0,0 +1,17 @@
1
+ export declare const checkDesignFixesTool: {
2
+ readonly name: "check_design_fixes";
3
+ readonly description: "šŸ” Check which previously fixed design issues were actually resolved (auto-triggered after run_design_test)";
4
+ readonly inputSchema: {
5
+ readonly type: "object";
6
+ readonly properties: {
7
+ readonly wait_seconds: {
8
+ readonly type: "number";
9
+ readonly description: "Wait time before checking issues (default: 15 seconds)";
10
+ readonly default: 15;
11
+ };
12
+ };
13
+ readonly additionalProperties: false;
14
+ };
15
+ };
16
+ export declare function handleCheckDesignFixes(authManager: any, args: any): Promise<any>;
17
+ //# sourceMappingURL=checkDesignFixes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkDesignFixes.d.ts","sourceRoot":"","sources":["../../../src/tools/protected/checkDesignFixes.ts"],"names":[],"mappings":"AAkDA,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;CAcvB,CAAC;AAEX,wBAAsB,sBAAsB,CAAC,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CA8KtF"}