@certscore/mcp 0.2.0
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/LICENSE +5 -0
- package/README.md +261 -0
- package/dist/certscore-mcp.mjs +23023 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +148 -0
- package/dist/tools.d.ts +77 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +329 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/package.json +65 -0
- package/server.json +37 -0
package/dist/tools.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { CertScoreError } from "@certscore/sdk";
|
|
2
|
+
const MAX_ERROR_RESPONSE_BODY_CHARS = 2_000;
|
|
3
|
+
export const MAX_EVIDENCE_PACKET_CHARS = 250_000;
|
|
4
|
+
const EVIDENCE_STRING_CHARS = 4_000;
|
|
5
|
+
const EVIDENCE_ARRAY_ITEMS = 40;
|
|
6
|
+
const EVIDENCE_OBJECT_KEYS = 80;
|
|
7
|
+
export function toToolResult(payload) {
|
|
8
|
+
const structuredContent = payload !== null && typeof payload === "object" && !Array.isArray(payload)
|
|
9
|
+
? payload
|
|
10
|
+
: { value: payload };
|
|
11
|
+
return {
|
|
12
|
+
structuredContent,
|
|
13
|
+
content: [
|
|
14
|
+
{
|
|
15
|
+
type: "text",
|
|
16
|
+
text: JSON.stringify(payload)
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function toToolError(error) {
|
|
22
|
+
if (error instanceof CertScoreError) {
|
|
23
|
+
return {
|
|
24
|
+
...toToolResult({
|
|
25
|
+
error: {
|
|
26
|
+
name: error.name,
|
|
27
|
+
message: error.message,
|
|
28
|
+
status: error.status,
|
|
29
|
+
code: error.code,
|
|
30
|
+
retryAfterSeconds: "retryAfterSeconds" in error ? error.retryAfterSeconds : undefined,
|
|
31
|
+
responseBody: truncateErrorResponseBody(error.responseBody)
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
isError: true
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...toToolResult({
|
|
39
|
+
error: {
|
|
40
|
+
name: error instanceof Error ? error.name : "Error",
|
|
41
|
+
message: error instanceof Error ? error.message : "Unknown CertScore MCP error."
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
isError: true
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function boundEvidencePacket(payload, maxSerializedChars = MAX_EVIDENCE_PACKET_CHARS) {
|
|
48
|
+
const originalSerializedChars = measureSerializedChars(payload);
|
|
49
|
+
if (originalSerializedChars <= maxSerializedChars) {
|
|
50
|
+
return payload;
|
|
51
|
+
}
|
|
52
|
+
const compacted = withMcpMetadata(compactEvidenceValue(payload, {
|
|
53
|
+
arrayItems: EVIDENCE_ARRAY_ITEMS,
|
|
54
|
+
depth: 8,
|
|
55
|
+
objectKeys: EVIDENCE_OBJECT_KEYS,
|
|
56
|
+
stringChars: EVIDENCE_STRING_CHARS
|
|
57
|
+
}), {
|
|
58
|
+
maxSerializedChars,
|
|
59
|
+
originalSerializedChars,
|
|
60
|
+
strategy: "compact_nested_values",
|
|
61
|
+
truncated: true
|
|
62
|
+
});
|
|
63
|
+
if (measureSerializedChars(compacted) <= maxSerializedChars) {
|
|
64
|
+
return compacted;
|
|
65
|
+
}
|
|
66
|
+
const minimal = withMcpMetadata(minimalEvidencePacket(payload), {
|
|
67
|
+
maxSerializedChars,
|
|
68
|
+
originalSerializedChars,
|
|
69
|
+
strategy: "minimal_safe_summary",
|
|
70
|
+
truncated: true
|
|
71
|
+
});
|
|
72
|
+
if (measureSerializedChars(minimal) <= maxSerializedChars) {
|
|
73
|
+
return minimal;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
type: "certscore_mcp_evidence_packet",
|
|
77
|
+
scanId: extractScanId(payload),
|
|
78
|
+
summary: "Evidence packet was too large for MCP transport and was reduced to metadata. Fetch API v2 directly for the full public-safe artifact.",
|
|
79
|
+
mcpMetadata: {
|
|
80
|
+
maxSerializedChars,
|
|
81
|
+
originalSerializedChars,
|
|
82
|
+
strategy: "metadata_only",
|
|
83
|
+
truncated: true
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function measureSerializedChars(value) {
|
|
88
|
+
return JSON.stringify(value)?.length ?? 0;
|
|
89
|
+
}
|
|
90
|
+
function compactEvidenceValue(value, options) {
|
|
91
|
+
if (value === null || value === undefined) {
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
if (typeof value === "string") {
|
|
95
|
+
return value.length > options.stringChars ? `${value.slice(0, options.stringChars)}…[truncated]` : value;
|
|
96
|
+
}
|
|
97
|
+
if (typeof value !== "object") {
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
if (options.depth <= 0) {
|
|
101
|
+
return "[truncated: depth limit]";
|
|
102
|
+
}
|
|
103
|
+
if (Array.isArray(value)) {
|
|
104
|
+
const items = value.slice(0, options.arrayItems).map((item) => compactEvidenceValue(item, {
|
|
105
|
+
...options,
|
|
106
|
+
depth: options.depth - 1
|
|
107
|
+
}));
|
|
108
|
+
if (value.length > options.arrayItems) {
|
|
109
|
+
items.push({
|
|
110
|
+
omittedItems: value.length - options.arrayItems,
|
|
111
|
+
truncated: true
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return items;
|
|
115
|
+
}
|
|
116
|
+
const entries = Object.entries(value);
|
|
117
|
+
const next = {};
|
|
118
|
+
for (const [key, nested] of entries.slice(0, options.objectKeys)) {
|
|
119
|
+
next[key] = compactEvidenceValue(nested, {
|
|
120
|
+
...options,
|
|
121
|
+
depth: options.depth - 1
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (entries.length > options.objectKeys) {
|
|
125
|
+
next.__truncatedKeys = entries.length - options.objectKeys;
|
|
126
|
+
}
|
|
127
|
+
return next;
|
|
128
|
+
}
|
|
129
|
+
function withMcpMetadata(value, metadata) {
|
|
130
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
131
|
+
const record = value;
|
|
132
|
+
const existing = record.mcpMetadata !== null && typeof record.mcpMetadata === "object" && !Array.isArray(record.mcpMetadata)
|
|
133
|
+
? record.mcpMetadata
|
|
134
|
+
: {};
|
|
135
|
+
return {
|
|
136
|
+
...record,
|
|
137
|
+
mcpMetadata: {
|
|
138
|
+
...existing,
|
|
139
|
+
...metadata
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
type: "certscore_mcp_evidence_packet",
|
|
145
|
+
value,
|
|
146
|
+
mcpMetadata: metadata
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function minimalEvidencePacket(payload) {
|
|
150
|
+
const record = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
151
|
+
return {
|
|
152
|
+
type: typeof record.type === "string" ? record.type : "certscore_mcp_evidence_packet",
|
|
153
|
+
scanId: extractScanId(record),
|
|
154
|
+
scan_id: typeof record.scan_id === "string" ? record.scan_id : undefined,
|
|
155
|
+
domain: typeof record.domain === "string" ? record.domain : null,
|
|
156
|
+
summary: compactEvidenceValue(record.summary ?? null, {
|
|
157
|
+
arrayItems: 20,
|
|
158
|
+
depth: 4,
|
|
159
|
+
objectKeys: 30,
|
|
160
|
+
stringChars: 1_000
|
|
161
|
+
}),
|
|
162
|
+
findings: compactEvidenceValue(record.findings ?? record.topFindings ?? [], {
|
|
163
|
+
arrayItems: 20,
|
|
164
|
+
depth: 5,
|
|
165
|
+
objectKeys: 40,
|
|
166
|
+
stringChars: 1_000
|
|
167
|
+
}),
|
|
168
|
+
evidenceHighlights: compactEvidenceValue(record.evidenceHighlights ?? null, {
|
|
169
|
+
arrayItems: 20,
|
|
170
|
+
depth: 5,
|
|
171
|
+
objectKeys: 40,
|
|
172
|
+
stringChars: 1_000
|
|
173
|
+
}),
|
|
174
|
+
coverage: compactEvidenceValue(record.coverage ?? null, {
|
|
175
|
+
arrayItems: 20,
|
|
176
|
+
depth: 4,
|
|
177
|
+
objectKeys: 30,
|
|
178
|
+
stringChars: 1_000
|
|
179
|
+
}),
|
|
180
|
+
disclaimer: typeof record.disclaimer === "string" ? record.disclaimer : null
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function extractScanId(payload) {
|
|
184
|
+
if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const record = payload;
|
|
188
|
+
if (typeof record.scanId === "string") {
|
|
189
|
+
return record.scanId;
|
|
190
|
+
}
|
|
191
|
+
if (typeof record.scan_id === "string") {
|
|
192
|
+
return record.scan_id;
|
|
193
|
+
}
|
|
194
|
+
const scan = record.scan;
|
|
195
|
+
const nestedScanId = scan !== null && typeof scan === "object" && !Array.isArray(scan)
|
|
196
|
+
? scan.scanId
|
|
197
|
+
: null;
|
|
198
|
+
if (typeof nestedScanId === "string") {
|
|
199
|
+
return nestedScanId;
|
|
200
|
+
}
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
function truncateErrorResponseBody(value) {
|
|
204
|
+
if (typeof value !== "string") {
|
|
205
|
+
const serialized = JSON.stringify(value);
|
|
206
|
+
if (serialized === undefined || serialized.length <= MAX_ERROR_RESPONSE_BODY_CHARS) {
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
return `${serialized.slice(0, MAX_ERROR_RESPONSE_BODY_CHARS)}…[truncated]`;
|
|
210
|
+
}
|
|
211
|
+
if (value.length <= MAX_ERROR_RESPONSE_BODY_CHARS) {
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
return `${value.slice(0, MAX_ERROR_RESPONSE_BODY_CHARS)}…[truncated]`;
|
|
215
|
+
}
|
|
216
|
+
export function normalizeDetail(detail) {
|
|
217
|
+
return detail ?? "summary";
|
|
218
|
+
}
|
|
219
|
+
export function normalizeFormat(format) {
|
|
220
|
+
return format ?? "json";
|
|
221
|
+
}
|
|
222
|
+
export function scanIdFromStatus(status) {
|
|
223
|
+
return status.scanId ?? status.scan_id ?? null;
|
|
224
|
+
}
|
|
225
|
+
export function scanIdFromPulse(report) {
|
|
226
|
+
const nestedScan = "scan" in report && report.scan && typeof report.scan === "object" ? report.scan : undefined;
|
|
227
|
+
return report.scanId ?? report.scan_id ?? nestedScan?.scanId ?? null;
|
|
228
|
+
}
|
|
229
|
+
export function findingsFromReport(report) {
|
|
230
|
+
const findings = Array.isArray(report.findings) ? report.findings : [];
|
|
231
|
+
const topFindings = Array.isArray(report.topFindings) ? report.topFindings : [];
|
|
232
|
+
const byId = new Map();
|
|
233
|
+
for (const finding of [...findings, ...topFindings]) {
|
|
234
|
+
byId.set(finding.id, finding);
|
|
235
|
+
}
|
|
236
|
+
return [...byId.values()];
|
|
237
|
+
}
|
|
238
|
+
export function exportFindings(report) {
|
|
239
|
+
return {
|
|
240
|
+
type: "certscore_mcp_findings_export",
|
|
241
|
+
scanId: scanIdFromPulse(report),
|
|
242
|
+
domain: report.domain ?? report.request?.domain ?? null,
|
|
243
|
+
summary: report.summary ?? null,
|
|
244
|
+
findings: findingsFromReport(report).map((finding) => ({
|
|
245
|
+
id: finding.id,
|
|
246
|
+
label: finding.label ?? null,
|
|
247
|
+
criticality: finding.criticality ?? null,
|
|
248
|
+
confidence: finding.confidence ?? null,
|
|
249
|
+
plainEnglish: finding.plainEnglish ?? null,
|
|
250
|
+
evidenceDigest: finding.evidenceDigest ?? null,
|
|
251
|
+
evidenceSummary: finding.evidence?.summary ?? null,
|
|
252
|
+
reviewLenses: finding.reviewLenses ?? [],
|
|
253
|
+
anchorUrl: finding.anchorUrl ?? finding.evidence?.fullEvidenceUrl ?? null,
|
|
254
|
+
nextStep: finding.nextStep ?? null
|
|
255
|
+
})),
|
|
256
|
+
disclaimer: report.disclaimer ?? null
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
export function paginateFindingList(payload, options = {}) {
|
|
260
|
+
const findings = Array.isArray(payload.findings) ? payload.findings : null;
|
|
261
|
+
if (!findings) {
|
|
262
|
+
return payload;
|
|
263
|
+
}
|
|
264
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
265
|
+
const limit = Math.min(200, Math.max(1, options.limit ?? 50));
|
|
266
|
+
const paginatedFindings = findings.slice(offset, offset + limit);
|
|
267
|
+
const next = {
|
|
268
|
+
...payload,
|
|
269
|
+
findings: paginatedFindings,
|
|
270
|
+
pagination: {
|
|
271
|
+
limit,
|
|
272
|
+
offset,
|
|
273
|
+
returned: paginatedFindings.length,
|
|
274
|
+
total: findings.length,
|
|
275
|
+
truncated: offset + limit < findings.length
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
return next;
|
|
279
|
+
}
|
|
280
|
+
export function limitPreConsentRows(payload, options = {}) {
|
|
281
|
+
const rows = Array.isArray(payload.rows) ? payload.rows : null;
|
|
282
|
+
if (!rows) {
|
|
283
|
+
return payload;
|
|
284
|
+
}
|
|
285
|
+
const maxRows = Math.min(200, Math.max(1, options.maxRows ?? 200));
|
|
286
|
+
const total = rows.length;
|
|
287
|
+
const truncated = total > maxRows;
|
|
288
|
+
return {
|
|
289
|
+
...payload,
|
|
290
|
+
rows: rows.slice(0, maxRows),
|
|
291
|
+
summary: {
|
|
292
|
+
...(payload.summary && typeof payload.summary === "object" && !Array.isArray(payload.summary) ? payload.summary : {}),
|
|
293
|
+
totalRowCount: total,
|
|
294
|
+
truncated
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
export function explainFinding(report, findingId) {
|
|
299
|
+
const finding = findingsFromReport(report).find((candidate) => candidate.id === findingId);
|
|
300
|
+
if (!finding) {
|
|
301
|
+
return {
|
|
302
|
+
type: "certscore_mcp_finding_explanation",
|
|
303
|
+
scanId: scanIdFromPulse(report),
|
|
304
|
+
findingId,
|
|
305
|
+
found: false,
|
|
306
|
+
message: "Finding was not present in this Pulse report.",
|
|
307
|
+
availableFindingIds: findingsFromReport(report).map((candidate) => candidate.id),
|
|
308
|
+
disclaimer: report.disclaimer ?? null
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
type: "certscore_mcp_finding_explanation",
|
|
313
|
+
scanId: scanIdFromPulse(report),
|
|
314
|
+
findingId,
|
|
315
|
+
found: true,
|
|
316
|
+
label: finding.label ?? finding.id,
|
|
317
|
+
criticality: finding.criticality ?? null,
|
|
318
|
+
confidence: finding.confidence ?? null,
|
|
319
|
+
plainEnglish: finding.plainEnglish ?? null,
|
|
320
|
+
evidenceSummary: finding.evidence?.summary ?? null,
|
|
321
|
+
evidenceDigest: finding.evidenceDigest ?? null,
|
|
322
|
+
exampleEvents: finding.evidence?.exampleEvents ?? [],
|
|
323
|
+
reviewLenses: finding.reviewLenses ?? [],
|
|
324
|
+
anchorUrl: finding.anchorUrl ?? finding.evidence?.fullEvidenceUrl ?? null,
|
|
325
|
+
nextStep: finding.nextStep ?? null,
|
|
326
|
+
caveats: report.coverage?.limitations ?? [],
|
|
327
|
+
disclaimer: report.disclaimer ?? null
|
|
328
|
+
};
|
|
329
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,QAAsB,CAAC"}
|
package/dist/version.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@certscore/mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"mcpName": "ai.certscore/mcp",
|
|
5
|
+
"private": false,
|
|
6
|
+
"description": "MCP server for CertScore public website risk-signal workflows.",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/certscore-mcp.mjs",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"bin": {
|
|
11
|
+
"certscore-mcp": "dist/certscore-mcp.mjs"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/certscore-mcp.mjs"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"server.json"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/ergoveritas1-alt/certscore.ai.git",
|
|
34
|
+
"directory": "packages/certscore-mcp"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://certscore.ai/developers/mcp",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://certscore.ai/contact",
|
|
39
|
+
"email": "support@certscore.ai"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -p tsconfig.json && esbuild src/index.ts --bundle --platform=node --format=esm --target=node20 --banner:js='#!/usr/bin/env node' --outfile=dist/certscore-mcp.mjs",
|
|
43
|
+
"bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node20 --banner:js='#!/usr/bin/env node' --outfile=dist/certscore-mcp.mjs",
|
|
44
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
45
|
+
"test": "node --import tsx --test src/*.test.ts",
|
|
46
|
+
"prepack": "pnpm run build",
|
|
47
|
+
"clean": "rm -rf dist"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"certscore",
|
|
51
|
+
"pulse",
|
|
52
|
+
"mcp",
|
|
53
|
+
"modelcontextprotocol",
|
|
54
|
+
"model-context-protocol"
|
|
55
|
+
],
|
|
56
|
+
"license": "proprietary",
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
59
|
+
"zod": "^3.25.76"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@certscore/api-contracts": "workspace:*",
|
|
63
|
+
"@certscore/sdk": "workspace:*"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/server.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "ai.certscore/mcp",
|
|
4
|
+
"title": "CertScore MCP",
|
|
5
|
+
"description": "MCP server for CertScore public website risk-signal workflows, including scan creation, status checks, findings, bounded evidence, and latest-domain lookups. CertScore outputs are automated public-web observations for review, not legal advice, certification, or a compliance determination.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/ergoveritas1-alt/certscore.ai",
|
|
8
|
+
"source": "github"
|
|
9
|
+
},
|
|
10
|
+
"version": "0.2.0",
|
|
11
|
+
"packages": [
|
|
12
|
+
{
|
|
13
|
+
"registryType": "npm",
|
|
14
|
+
"identifier": "@certscore/mcp",
|
|
15
|
+
"version": "0.2.0",
|
|
16
|
+
"transport": {
|
|
17
|
+
"type": "stdio"
|
|
18
|
+
},
|
|
19
|
+
"environmentVariables": [
|
|
20
|
+
{
|
|
21
|
+
"name": "CERTSCORE_API_KEY",
|
|
22
|
+
"description": "CertScore API key with scan:read, scan:create, and mcp scopes.",
|
|
23
|
+
"isRequired": true,
|
|
24
|
+
"format": "string",
|
|
25
|
+
"isSecret": true
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "CERTSCORE_BASE_URL",
|
|
29
|
+
"description": "Optional CertScore API base URL. Defaults to https://certscore.ai.",
|
|
30
|
+
"isRequired": false,
|
|
31
|
+
"format": "uri",
|
|
32
|
+
"isSecret": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|