mcp4openapi 0.2.3 → 0.2.4
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 +8 -2
- package/dist/src/http-transport.d.ts.map +1 -1
- package/dist/src/http-transport.js +32 -11
- package/dist/src/http-transport.js.map +1 -1
- package/dist/src/mcp-server.d.ts +1 -1
- package/dist/src/mcp-server.d.ts.map +1 -1
- package/dist/src/mcp-server.js +20 -2
- package/dist/src/mcp-server.js.map +1 -1
- package/dist/src/oauth-provider.d.ts.map +1 -1
- package/dist/src/oauth-provider.js +28 -1
- package/dist/src/oauth-provider.js.map +1 -1
- package/dist/src/schema-validator.d.ts.map +1 -1
- package/dist/src/schema-validator.js +14 -1
- package/dist/src/schema-validator.js.map +1 -1
- package/dist/src/testing/mock-gitlab-server.d.ts.map +1 -1
- package/dist/src/testing/mock-gitlab-server.js +86 -29
- package/dist/src/testing/mock-gitlab-server.js.map +1 -1
- package/dist/src/testing/mock-semgrep-server.d.ts +32 -0
- package/dist/src/testing/mock-semgrep-server.d.ts.map +1 -0
- package/dist/src/testing/mock-semgrep-server.js +213 -0
- package/dist/src/testing/mock-semgrep-server.js.map +1 -0
- package/dist/src/validation-utils.d.ts.map +1 -1
- package/dist/src/validation-utils.js +24 -2
- package/dist/src/validation-utils.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Semgrep API server for integration testing
|
|
3
|
+
*
|
|
4
|
+
* Why: Enables end-to-end testing without real Semgrep instance.
|
|
5
|
+
* Tests actual HTTP flow, parameter handling, error scenarios.
|
|
6
|
+
*/
|
|
7
|
+
import { http, HttpResponse } from 'msw';
|
|
8
|
+
import { setupServer } from 'msw/node';
|
|
9
|
+
/** Default BASE_URL for Semgrep API (used by MSW interceptor) */
|
|
10
|
+
export const DEFAULT_BASE_URL = 'https://semgrep.dev';
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
13
|
+
validToken: 'mock-semgrep-token-12345',
|
|
14
|
+
deploymentSlug: 'test-deployment',
|
|
15
|
+
deploymentId: 123,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Create Semgrep API handlers
|
|
19
|
+
*/
|
|
20
|
+
export function createSemgrepHandlers(config = {}) {
|
|
21
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
22
|
+
return [
|
|
23
|
+
// GET /api/v1/deployments - List deployments
|
|
24
|
+
http.get(`${cfg.baseUrl}/api/v1/deployments`, ({ request }) => {
|
|
25
|
+
const authHeader = request.headers.get('Authorization');
|
|
26
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
27
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
28
|
+
}
|
|
29
|
+
const token = authHeader.replace('Bearer ', '');
|
|
30
|
+
if (token !== cfg.validToken) {
|
|
31
|
+
return HttpResponse.json({ error: 'Invalid token' }, { status: 401 });
|
|
32
|
+
}
|
|
33
|
+
return HttpResponse.json({
|
|
34
|
+
deployments: [
|
|
35
|
+
{
|
|
36
|
+
id: cfg.deploymentId,
|
|
37
|
+
slug: cfg.deploymentSlug,
|
|
38
|
+
name: 'Test Deployment',
|
|
39
|
+
findings: {
|
|
40
|
+
url: `${cfg.baseUrl}/api/v1/deployments/${cfg.deploymentSlug}/findings`,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
}),
|
|
46
|
+
// POST /api/v1/deployments/{deploymentSlug}/triage - Bulk triage
|
|
47
|
+
http.post(`${cfg.baseUrl}/api/v1/deployments/:deploymentSlug/triage`, async ({ request, params }) => {
|
|
48
|
+
const authHeader = request.headers.get('Authorization');
|
|
49
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
50
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
51
|
+
}
|
|
52
|
+
const token = authHeader.replace('Bearer ', '');
|
|
53
|
+
if (token !== cfg.validToken) {
|
|
54
|
+
return HttpResponse.json({ error: 'Invalid token' }, { status: 401 });
|
|
55
|
+
}
|
|
56
|
+
const { deploymentSlug } = params;
|
|
57
|
+
if (deploymentSlug !== cfg.deploymentSlug) {
|
|
58
|
+
return HttpResponse.json({ error: 'Deployment not found' }, { status: 404 });
|
|
59
|
+
}
|
|
60
|
+
let body;
|
|
61
|
+
try {
|
|
62
|
+
body = await request.json();
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return HttpResponse.json({ error: 'Invalid JSON body' }, { status: 400 });
|
|
66
|
+
}
|
|
67
|
+
// Log the received request for debugging
|
|
68
|
+
console.log('[Mock Semgrep] Received triage request:', {
|
|
69
|
+
url: request.url,
|
|
70
|
+
params,
|
|
71
|
+
body,
|
|
72
|
+
headers: {
|
|
73
|
+
'Content-Type': request.headers.get('Content-Type'),
|
|
74
|
+
'Authorization': authHeader ? '***' : undefined,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
// Validate required fields according to OpenAPI spec
|
|
78
|
+
if (!body.issue_type) {
|
|
79
|
+
return HttpResponse.json({
|
|
80
|
+
error: 'Validation error',
|
|
81
|
+
details: 'issue_type is required',
|
|
82
|
+
}, { status: 400 });
|
|
83
|
+
}
|
|
84
|
+
if (!['sast', 'sca', 'secrets'].includes(body.issue_type)) {
|
|
85
|
+
return HttpResponse.json({
|
|
86
|
+
error: 'Validation error',
|
|
87
|
+
details: 'issue_type must be one of: sast, sca, secrets',
|
|
88
|
+
}, { status: 400 });
|
|
89
|
+
}
|
|
90
|
+
// Check deploymentSlug in body (as per OpenAPI spec)
|
|
91
|
+
if (!body.deploymentSlug) {
|
|
92
|
+
return HttpResponse.json({
|
|
93
|
+
error: 'Validation error',
|
|
94
|
+
details: 'deploymentSlug is required in request body',
|
|
95
|
+
}, { status: 400 });
|
|
96
|
+
}
|
|
97
|
+
if (body.deploymentSlug !== cfg.deploymentSlug) {
|
|
98
|
+
return HttpResponse.json({
|
|
99
|
+
error: 'Validation error',
|
|
100
|
+
details: 'deploymentSlug in body does not match URL parameter',
|
|
101
|
+
}, { status: 400 });
|
|
102
|
+
}
|
|
103
|
+
// Validate limit is integer if provided
|
|
104
|
+
if (body.limit !== undefined) {
|
|
105
|
+
if (!Number.isInteger(body.limit)) {
|
|
106
|
+
return HttpResponse.json({
|
|
107
|
+
error: 'Validation error',
|
|
108
|
+
details: 'limit must be an integer',
|
|
109
|
+
}, { status: 400 });
|
|
110
|
+
}
|
|
111
|
+
if (body.limit < 1 || body.limit > 3000) {
|
|
112
|
+
return HttpResponse.json({
|
|
113
|
+
error: 'Validation error',
|
|
114
|
+
details: 'limit must be between 1 and 3000',
|
|
115
|
+
}, { status: 400 });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Validate triage state and reason
|
|
119
|
+
if (body.new_triage_state) {
|
|
120
|
+
const validStates = ['ignored', 'reviewing', 'fixing', 'reopened'];
|
|
121
|
+
if (!validStates.includes(body.new_triage_state)) {
|
|
122
|
+
return HttpResponse.json({
|
|
123
|
+
error: 'Validation error',
|
|
124
|
+
details: `new_triage_state must be one of: ${validStates.join(', ')}`,
|
|
125
|
+
}, { status: 400 });
|
|
126
|
+
}
|
|
127
|
+
if (body.new_triage_state === 'ignored' && body.new_triage_reason) {
|
|
128
|
+
const validReasons = ['acceptable_risk', 'false_positive', 'no_time', 'no_triage_reason'];
|
|
129
|
+
if (!validReasons.includes(body.new_triage_reason)) {
|
|
130
|
+
return HttpResponse.json({
|
|
131
|
+
error: 'Validation error',
|
|
132
|
+
details: `new_triage_reason must be one of: ${validReasons.join(', ')}`,
|
|
133
|
+
}, { status: 400 });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Mock successful response
|
|
138
|
+
return HttpResponse.json({
|
|
139
|
+
num_triaged: 3,
|
|
140
|
+
triaged_issues: [123, 456, 789],
|
|
141
|
+
});
|
|
142
|
+
}),
|
|
143
|
+
// GET /api/v1/deployments/{deploymentSlug}/projects - List projects
|
|
144
|
+
http.get(`${cfg.baseUrl}/api/v1/deployments/:deploymentSlug/projects`, ({ request, params }) => {
|
|
145
|
+
const authHeader = request.headers.get('Authorization');
|
|
146
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
147
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
148
|
+
}
|
|
149
|
+
const { deploymentSlug } = params;
|
|
150
|
+
if (deploymentSlug !== cfg.deploymentSlug) {
|
|
151
|
+
return HttpResponse.json({ error: 'Deployment not found' }, { status: 404 });
|
|
152
|
+
}
|
|
153
|
+
// Mock projects response
|
|
154
|
+
return HttpResponse.json({
|
|
155
|
+
projects: [
|
|
156
|
+
{
|
|
157
|
+
id: 1,
|
|
158
|
+
name: 'test-org/test-repo',
|
|
159
|
+
url: 'https://github.com/test-org/test-repo',
|
|
160
|
+
default_branch: 'refs/heads/main',
|
|
161
|
+
tags: ['test'],
|
|
162
|
+
latest_scan_at: '2025-12-03T00:00:00Z',
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
});
|
|
166
|
+
}),
|
|
167
|
+
// GET /api/v1/deployments/{deploymentSlug}/findings - List findings
|
|
168
|
+
http.get(`${cfg.baseUrl}/api/v1/deployments/:deploymentSlug/findings`, ({ request, params }) => {
|
|
169
|
+
const authHeader = request.headers.get('Authorization');
|
|
170
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
171
|
+
return HttpResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
172
|
+
}
|
|
173
|
+
const { deploymentSlug } = params;
|
|
174
|
+
if (deploymentSlug !== cfg.deploymentSlug) {
|
|
175
|
+
return HttpResponse.json({ error: 'Deployment not found' }, { status: 404 });
|
|
176
|
+
}
|
|
177
|
+
const url = new URL(request.url);
|
|
178
|
+
const issueType = url.searchParams.get('issue_type') || 'sast';
|
|
179
|
+
const status = url.searchParams.get('status');
|
|
180
|
+
// Mock findings response
|
|
181
|
+
return HttpResponse.json({
|
|
182
|
+
sastFindings: {
|
|
183
|
+
findings: [
|
|
184
|
+
{
|
|
185
|
+
id: 123,
|
|
186
|
+
severity: 'high',
|
|
187
|
+
status: status || 'open',
|
|
188
|
+
rule: {
|
|
189
|
+
name: 'test.rule.1',
|
|
190
|
+
confidence: 'high',
|
|
191
|
+
},
|
|
192
|
+
repository: {
|
|
193
|
+
name: 'test/repo',
|
|
194
|
+
},
|
|
195
|
+
location: {
|
|
196
|
+
filePath: 'src/test.ts',
|
|
197
|
+
line: 10,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}),
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Create and start mock Semgrep server
|
|
208
|
+
*/
|
|
209
|
+
export function createMockSemgrepServer(config = {}) {
|
|
210
|
+
const handlers = createSemgrepHandlers(config);
|
|
211
|
+
return setupServer(...handlers);
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=mock-semgrep-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-semgrep-server.js","sourceRoot":"","sources":["../../../src/testing/mock-semgrep-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-utils.d.ts","sourceRoot":"","sources":["../../src/validation-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,SAAS,EAAE,MAAM,GAChB,MAAM,
|
|
1
|
+
{"version":3,"file":"validation-utils.d.ts","sourceRoot":"","sources":["../../src/validation-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,SAAS,EAAE,MAAM,GAChB,MAAM,CAiCR;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAGrE"}
|
|
@@ -55,6 +55,10 @@ export function redactHeader(headers, headerName) {
|
|
|
55
55
|
export function redactQueryParam(url, paramName) {
|
|
56
56
|
if (!url)
|
|
57
57
|
return '';
|
|
58
|
+
// Enforce safe paramName (alphanumeric, underscore, dash) length <= 64
|
|
59
|
+
if (!/^[A-Za-z0-9_-]{1,64}$/.test(paramName)) {
|
|
60
|
+
return url; // Unsafe param name; return original unmodified
|
|
61
|
+
}
|
|
58
62
|
try {
|
|
59
63
|
const urlObj = new URL(url);
|
|
60
64
|
if (urlObj.searchParams.has(paramName)) {
|
|
@@ -63,8 +67,26 @@ export function redactQueryParam(url, paramName) {
|
|
|
63
67
|
return urlObj.toString();
|
|
64
68
|
}
|
|
65
69
|
catch {
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
// Fallback: manual parsing without dynamic RegExp to avoid ReDoS concerns
|
|
71
|
+
// Split on '?' then process query string key-value pairs
|
|
72
|
+
const qIndex = url.indexOf('?');
|
|
73
|
+
if (qIndex === -1)
|
|
74
|
+
return url;
|
|
75
|
+
const base = url.substring(0, qIndex);
|
|
76
|
+
const query = url.substring(qIndex + 1);
|
|
77
|
+
const parts = query.split('&');
|
|
78
|
+
const redactedParts = parts.map(part => {
|
|
79
|
+
const eqIndex = part.indexOf('=');
|
|
80
|
+
if (eqIndex === -1)
|
|
81
|
+
return part; // skip malformed segment
|
|
82
|
+
const key = part.substring(0, eqIndex);
|
|
83
|
+
if (key === paramName) {
|
|
84
|
+
// Encode [REDACTED] for consistency with URLSearchParams behavior
|
|
85
|
+
return key + '=%5BREDACTED%5D';
|
|
86
|
+
}
|
|
87
|
+
return part;
|
|
88
|
+
});
|
|
89
|
+
return base + '?' + redactedParts.join('&');
|
|
68
90
|
}
|
|
69
91
|
}
|
|
70
92
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation-utils.js","sourceRoot":"","sources":["../../src/validation-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,UAAU,MAAM,aAAa,CAAC;AAErC,oEAAoE;AACpE,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACvC,WAAW;IACX,aAAa;IACb,WAAW;IACX,kBAAkB;IAClB,kBAAkB;IAClB,kBAAkB;IAClB,kBAAkB;IAClB,gBAAgB;IAChB,eAAe;IACf,sBAAsB;IACtB,gBAAgB;IAChB,UAAU;IACV,SAAS;CACV,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,CAAC,wBAAwB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAgB,EAChB,UAAkB;IAElB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEvD,MAAM,QAAQ,GAAG,EAAE,GAAI,OAAmC,EAAE,CAAC;IAE7D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;YACnD,QAAQ,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAuB,EACvB,SAAiB;IAEjB,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"validation-utils.js","sourceRoot":"","sources":["../../src/validation-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp4openapi",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Universal MCP server that generates tools from any OpenAPI specification",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -56,10 +56,10 @@
|
|
|
56
56
|
"url": "https://github.com/davidruzicka/mcp4openapi/issues"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@modelcontextprotocol/sdk": "^1.0
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.24.0",
|
|
60
60
|
"dotenv": "^17.2.3",
|
|
61
61
|
"escape-html": "^1.0.3",
|
|
62
|
-
"express": "^5.1
|
|
62
|
+
"express": "^5.2.1",
|
|
63
63
|
"express-rate-limit": "^8.2.1",
|
|
64
64
|
"openapi-types": "^12.1.3",
|
|
65
65
|
"prom-client": "^15.1.3",
|