@certscore/mcp 0.2.11 → 0.2.15

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  CertScore MCP exposes a focused Model Context Protocol server for CertScore Pulse workflows.
4
4
 
5
- Status: public developer preview. Version 0.2.11 is prepared for the hosted Streamable HTTP service and the next deterministic Homebrew release. Local WC01 development uses `pnpm mcp:certscore`.
5
+ Status: public developer preview. Version 0.2.15 reserves the first compact finding and evidence digest before optional detail inside small byte budgets, returns typed validation details, and makes every omission recoverable. Local WC01 development uses `pnpm mcp:certscore`.
6
6
 
7
7
  Public docs:
8
8
 
@@ -11,21 +11,82 @@ Public docs:
11
11
  - https://certscore.ai/developers/reference
12
12
  - https://certscore.ai/api-pulse
13
13
 
14
+ ## Light MCP — no authentication: start here
15
+
16
+ Light is the anonymous, no-auth Streamable HTTP endpoint for first-time and low-volume agent workflows:
17
+
18
+ ```text
19
+ Light:
20
+ https://mcp.certscore.ai/mcp/light
21
+
22
+ Authentication: None
23
+ Tools: certscore_scan_site, certscore_get_scan_status, certscore_get_scan_bundle
24
+ ```
25
+
26
+ No signup, API key, bearer token, browser login, or OAuth is required. Light allows 20 new scans per requester IP per UTC day. Reused eligible results do not consume quota.
27
+
28
+ Codex setup:
29
+
30
+ ```bash
31
+ codex mcp add certscore --url https://mcp.certscore.ai/mcp/light
32
+ ```
33
+
34
+ First-run Codex prompt:
35
+
36
+ > Scan https://ergoveritas.com/.well-known/certscore-canary/sentinels/broad-baseline.html. If certscore_scan_site returns a queued, running, or finalizing result, retain the returned scanId and poll certscore_get_scan_status using scanId only. If certscore_scan_site returns a retryable error without a scanId, wait for retryAfterSeconds and retry certscore_scan_site; do not call certscore_get_scan_status until a scanId exists. Once the scan reaches a terminal status, call certscore_get_scan_bundle with detail=findings and maxBytes=8000. Summarize whether the result was new or reused, the score, risk level, findings, evidence links, coverage limitations, and report URL. Explain truncation or omitted sections when present. Treat results as automated public-web observations, not legal conclusions, certifications, or compliance determinations.
37
+
38
+ ErgoVeritas is a stable, owned canary site suited to demonstrating the complete scan, status, and bundle flow. Its pages intentionally contain test signals; users may substitute their own public HTTP or HTTPS URL for production-like testing.
39
+
40
+ Canonical Light workflow:
41
+
42
+ 1. Call `certscore_scan_site` with a public URL.
43
+ 2. If a retryable error has no `scanId`, wait `retryAfterSeconds` and retry `certscore_scan_site`.
44
+ 3. If the result is queued, running, or finalizing, retain `scanId`.
45
+ 4. Poll `certscore_get_scan_status` using `scanId` only. Never poll until `scanId` exists.
46
+ 5. Stop polling at a terminal status, then call `certscore_get_scan_bundle`.
47
+ 6. Use `detail=findings` for a compact finding review.
48
+ 7. Use `detail=evidence` for evidence digests and references.
49
+ 8. If truncated, follow `recommendedNextAction` or increase `maxBytes`.
50
+ 9. Summarize findings together with coverage limitations and the report URL.
51
+
52
+ Recommended bundle budgets are `maxBytes=5000` for `summary`, `maxBytes=8000` for `findings`, `maxBytes=8000` for `evidence`, and `maxBytes=12000` or higher for `full`. A 5,000-byte response may intentionally omit optional sections while still returning a compact finding or evidence reference when available. Inspect `actualBytes`, `truncated`, `omittedSections`, `nextRecommendedMaxBytes`, and returned report or evidence content URLs.
53
+
54
+ Verification prompt:
55
+
56
+ > List the available CertScore tools and confirm that certscore_scan_site, certscore_get_scan_status, and certscore_get_scan_bundle are available. Then scan https://ergoveritas.com/.well-known/certscore-canary/sentinels/broad-baseline.html and report whether the result was new or reused.
57
+
58
+ Success means the tool list contains exactly the three Light tools, no authorization page appears, and `certscore_scan_site` returns a stable `scanId` plus an explicit new-or-reused decision. An eligible reused result reports that quota was not consumed.
59
+
60
+ CertScore results are automated observations from a public-web scan. No-go, not-observed, and limited-coverage results are not proof of compliance, absence of risk, or legal status. Review the retained evidence and applicable context before relying on a finding.
61
+
62
+ ## Which MCP route should I use?
63
+
64
+ | Route | Access | Best for |
65
+ | --- | --- | --- |
66
+ | Light MCP — no authentication | No account, API key, bearer token, browser login, or OAuth; three tools; 20 new scans per requester IP per UTC day | First-time users, testing, and discovery |
67
+ | Hosted MCP — OAuth | Hosted Streamable HTTP with OAuth scopes, higher volume, history, and approved advanced tools | Production, team, and managed remote clients |
68
+ | Local MCP — scoped API key | Local stdio with a scoped key and tools allowed by its scopes | Backend, local, and controlled automation workflows |
69
+
70
+ The full/authenticated Streamable HTTP endpoint is `https://mcp.certscore.ai/mcp`. Use it after Light when the workflow requires authentication, higher volume, history, or advanced tools. Core identifiers and canonical response fields remain compatible when moving from Light to authenticated access.
71
+
72
+ ## Weighted read limits
73
+
74
+ MCP scan-resource reads use the same weighted, rolling policy as the direct CertScore API. Hosted MCP rejects an over-limit composite call before internal fan-out; local MCP receives the same protection from the underlying API. Poll only active status resources, stop at a terminal status, do not repeatedly retrieve terminal scan resources, and honor `Retry-After` before retrying. The current limits and weights are published at https://certscore.ai/developers/reference#read-rate-limits and in the `x-certscore-read-rate-policy` extension of the public OpenAPI documents.
75
+
14
76
  ## Tools
15
77
 
16
- - `create_scan` - Deprecated compatibility alias of scan_site. Use scan_site for new integrations. Returns completed-limited no-go disposition and reason-specific guidance when applicable.
17
- - `scan_site` - Recommended first call. Starts or reuses a public-web scan, reports freshness and anonymous quota decisions, and waits up to 45 seconds by default. If still running, use get_scan_status; otherwise use get_scan_bundle. Completed no-go scans retain completed_limited status and reason-specific guidance.
18
- - `get_scan` - Retrieve the API v2 public-safe scan resource, including completed-limited no-go disposition, reason-specific guidance, and timing when available.
19
- - `get_scan_status` - Retrieve terminal status, including completed_limited no-go disposition and reason-specific guidance. Pass jobId only before a stable scanId is available.
20
- - `get_report` - Retrieve a summary Pulse report, including customer-safe no-go messaging when coverage is completed-limited. Use get_evidence for the larger bounded packet.
21
- - `get_evidence` - Retrieve the bounded structured Evidence JSON packet for a stable scan ID. Excludes raw cookie values, raw bodies, sensitive payloads, full DOM, and unredacted query values.
22
- - `get_scan_bundle` - Recommended second call after scan_site. Returns the canonical scan state, compact report summary, findings, bounded evidence summary, and pre-consent inventory in one agent-friendly response.
23
- - `export_findings` - Return structured findings plus completed-limited no-go disposition and guidance for downstream review or ticketing workflows.
24
- - `list_findings` - List API v2 public-safe findings already projected for a scan.
25
- - `get_pre_consent_cookies_trackers` - Retrieve the public-safe Cookies & Trackers (Pre-consent) report table as compact JSON for a scan.
26
- - `explain_finding` - Explain one projected finding with public evidence, caveats, reviewer next steps, and reason-specific no-go context when applicable.
27
- - `get_latest_domain_scan` - Retrieve the latest eligible API v2 public-safe scan for a domain.
28
- - `get_latest_domain_pre_consent_cookies_trackers` - Retrieve the public-safe Cookies & Trackers (Pre-consent) table from the latest eligible scan for a domain.
78
+ - `certscore_scan_site` - First call. Starts or reuses a public-web scan and waits up to 45 seconds by default. If status is queued, running, or finalizing, retain scanId and poll certscore_get_scan_status using only that scanId. Stop polling at completed, completed_limited, failed, expired, or rate_limited. For usable completion, call certscore_get_scan_bundle. No-go and limited coverage are observations, never proof of compliance.
79
+ - `certscore_get_scan` - Retrieve the API v2 public-safe scan resource, including completed-limited no-go disposition, reason-specific guidance, and timing when available.
80
+ - `certscore_get_scan_status` - Poll with only the stable scanId returned by certscore_scan_site. Active responses include phase, heartbeat, estimated progress, stalled state, and retry delay. Terminal responses include the canonical score, risk, coverage, timestamps, report URL, and an explicit next action. Stop polling at any terminal status.
81
+ - `certscore_get_report` - Retrieve a summary Pulse report, including customer-safe no-go messaging when coverage is completed-limited. Use certscore_get_evidence for the larger bounded packet.
82
+ - `certscore_get_evidence` - Retrieve the bounded structured Evidence JSON packet for a stable scan ID. Excludes raw cookie values, raw bodies, sensitive payloads, full DOM, and unredacted query values.
83
+ - `certscore_get_scan_bundle` - Call after completed or completed_limited status. summary returns the canonical overview without finding bodies; findings reserves space for compact findings; evidence reserves findings plus bounded evidence digests and references; full adds all available bounded sections. Every response declares detail and byte-budget metadata, omittedSections, retrieval URLs, and nextRecommendedMaxBytes when truncated. Never interpret no-go, not-observed, or limited coverage as proof of compliance.
84
+ - `certscore_export_findings` - Return structured findings plus completed-limited no-go disposition and guidance for downstream review or ticketing workflows.
85
+ - `certscore_list_findings` - List API v2 public-safe findings already projected for a scan.
86
+ - `certscore_get_pre_consent_cookies_trackers` - Retrieve the public-safe Cookies & Trackers (Pre-consent) report table as compact JSON for a scan.
87
+ - `certscore_explain_finding` - Explain one projected finding with public evidence, caveats, reviewer next steps, and reason-specific no-go context when applicable.
88
+ - `certscore_get_latest_domain_scan` - Retrieve the latest eligible API v2 public-safe scan for a domain.
89
+ - `certscore_get_latest_domain_pre_consent_cookies_trackers` - Retrieve the public-safe Cookies & Trackers (Pre-consent) table from the latest eligible scan for a domain.
29
90
 
30
91
  The initial MCP surface intentionally does not include account scan browsing or scan comparison tools.
31
92
 
@@ -37,13 +98,34 @@ MCP tools backed by API v2 scan resources return scan timing when CertScore has
37
98
  - `completedAt`
38
99
  - `scanTimeSeconds`
39
100
 
40
- This applies to `scan_site` when it returns an API v2 scan resource or job, `get_scan`, and `get_scan_status` when called with a `scanId`. `scanTimeSeconds: null` means timing is unavailable or incomplete and should not be displayed as `0`.
101
+ This applies to `certscore_scan_site` when it returns an API v2 scan resource or job, `certscore_get_scan`, and `certscore_get_scan_status` when called with a `scanId`. `scanTimeSeconds: null` means timing is unavailable or incomplete and should not be displayed as `0`.
102
+
103
+ Completed Light results are canonical. `certscore_scan_site`, terminal `certscore_get_scan_status`, and `certscore_get_scan_bundle` return the same score, risk level, coverage, and timing fields. Scores include `scoreStatus`, `scoreVersion`, and `scoreUpdatedAt`; a scan remains `finalizing` until the persisted canonical report projection is ready, so a completed response always carries `scoreStatus: "final"`.
104
+
105
+ Every `failed`, `expired`, or `rate_limited` status includes a bounded `error` object with `code`, `message`, `retryable`, `retryAfterSeconds`, and `recommendedNextAction`.
106
+
107
+ ## Light Bundle Detail and Byte Budgets
108
+
109
+ Every bundle declares its selected `detail` mode. `summary` returns the overview, canonical result, coverage, limitations, counts, and report URL without finding bodies. `findings` reserves space for compact finding objects. `evidence` reserves findings plus bounded evidence digests and references. `full` adds every available section subject to the caller's byte budget.
110
+
111
+ `mcpMetadata` always includes `requestedMaxBytes`, `actualBytes`, `truncated`, `truncationReason`, `omittedSections`, `nextRecommendedMaxBytes`, `omittedContentAvailableViaUrl`, and `contentUrls`. When the budget cannot retain a requested section, `recommendedNextAction` names the next useful byte limit or directs the agent to an available report/evidence URL.
112
+
113
+ Input-validation errors remain MCP `-32602` errors and also include structured `invalid_arguments` details with the affected field and a safe next action. Error results use concise text plus the same machine-readable `structuredContent`; successful results never duplicate the full structured payload in text.
114
+
115
+ The Light workflow is:
116
+
117
+ 1. Call `certscore_scan_site` with a public URL.
118
+ 2. If a retryable error has no `scanId`, wait `retryAfterSeconds` and retry `certscore_scan_site`; do not poll.
119
+ 3. If the result is queued, running, or finalizing, retain `scanId` and poll `certscore_get_scan_status` with only that ID.
120
+ 4. Stop polling at any terminal status. For `completed` or `completed_limited`, call `certscore_get_scan_bundle`.
121
+ 5. If the bundle is truncated, follow `recommendedNextAction`, increase `maxBytes`, or open a listed content URL.
122
+ 6. Summarize the canonical score, risk, findings, coverage, limitations, and report URL without treating no-go, not-observed, or limited coverage as proof of compliance.
41
123
 
42
124
  ## Completed-Limited No-Go Results
43
125
 
44
126
  No-go scans are usable terminal results, not transport failures. Relevant tools retain `status: "completed_limited"`, `resultDisposition: "no_go"`, the stable reason code, customer-safe title and explanation, `limitationKind` attribution, retry guidance, and a bounded `evidenceExcerpt` when retained. Unknown future reasons use generic customer copy while remaining structured as `reasonCode: "unknown"`.
45
127
 
46
- ## Hosted Streamable HTTP
128
+ ## Hosted MCP — OAuth
47
129
 
48
130
  OAuth-capable MCP clients can connect to:
49
131
 
@@ -54,11 +136,11 @@ https://mcp.certscore.ai/mcp
54
136
  Discovery endpoints:
55
137
 
56
138
  ```text
57
- https://mcp.certscore.ai/.well-known/oauth-protected-resource
139
+ https://mcp.certscore.ai/.well-known/oauth-protected-resource/mcp
58
140
  https://certscore.ai/.well-known/oauth-authorization-server
59
141
  ```
60
142
 
61
- The hosted service uses OAuth authorization code with PKCE. Default read access requests `scan:read mcp`; support-gated scan creation additionally requests `scan:create`. The same tool implementation and output contracts power stdio and hosted transports.
143
+ The full hosted service uses OAuth authorization code with PKCE. Default read access requests `scan:read mcp`; support-gated scan creation additionally requests `scan:create`. The same tool implementation and output contracts power stdio and hosted transports.
62
144
 
63
145
  For low-volume agent discovery without account or OAuth setup, use the unauthenticated endpoint:
64
146
 
@@ -66,10 +148,9 @@ For low-volume agent discovery without account or OAuth setup, use the unauthent
66
148
  https://mcp.certscore.ai/mcp/anonymous
67
149
  ```
68
150
 
69
- It exposes the same public-safe tool surface and preserves the existing limit of 10 new scans per requester IP per UTC day. Reusing an
70
- eligible recent result does not consume the quota. Use the OAuth endpoint or a scoped API key for higher-volume workflows.
151
+ For the simplest no-account workflow, use the Light quickstart at the top of this document. OAuth metadata applies only to `https://mcp.certscore.ai/mcp`.
71
152
 
72
- ## Configuration
153
+ ## Local MCP — scoped API key configuration
73
154
 
74
155
  Install with Homebrew on macOS:
75
156
 
@@ -124,7 +205,7 @@ CERTSCORE_REQUEST_TIMEOUT_MS=300000
124
205
 
125
206
  `CERTSCORE_API_KEY` should be a scoped CertScore API token for the workspace or preview user. The MCP server passes it to Pulse as a bearer token and does not persist it.
126
207
 
127
- ## API Key Access
208
+ ## Local MCP — scoped API key access
128
209
 
129
210
  Stdio API keys use `pulse:read` and `mcp`; creating scans additionally requires `pulse:scan`. Hosted OAuth uses `scan:read` and `mcp`, with support-gated `scan:create`. Request scan-creation access by emailing `support@certscore.ai` with your organization, MCP client, expected workflow, expected request volume, and contact email.
130
211
 
@@ -146,10 +227,10 @@ Agents that cannot create an account or configure OAuth can use the public API v
146
227
  ```bash
147
228
  curl -X POST https://certscore.ai/api/v2/scans \
148
229
  -H "Content-Type: application/json" \
149
- -d '{"url":"https://example.com","freshness":"latest","scanFrom":"eu_ie"}'
230
+ -d '{"url":"https://ergoveritas.com/.well-known/certscore-canary/sentinels/broad-baseline.html","freshness":"latest","scanFrom":"eu_ie"}'
150
231
  ```
151
232
 
152
- New anonymous scans are limited to 10 per requester IP per UTC day. Reusing an eligible recent result does not consume the quota. Poll the returned status resource, then retrieve findings or evidence. Use OAuth or a scoped API key for repeated or higher-volume workflows.
233
+ New anonymous scans are limited to 20 per requester IP per UTC day. Reusing an eligible recent result does not consume the quota. Poll the returned status resource, then retrieve findings or evidence. Contact `support@certscore.ai` for a higher-volume allowance, including when reuse serves the current request.
153
234
 
154
235
  ## MCP Client Examples
155
236
 
@@ -221,20 +302,26 @@ Local repo config for contributors:
221
302
 
222
303
  ## Agent Workflow
223
304
 
224
- 1. Call `scan_site` with a public URL. It normally returns the completed scan resource in the same tool call.
225
- 2. Only if it returns a non-terminal job, call `get_scan_status` using the stable `scanId` until completion.
226
- 3. Call `get_scan_bundle` for the normal compact review handoff.
227
- 4. Call `get_report`, `get_evidence`, `list_findings`, or `get_pre_consent_cookies_trackers` only when the task needs a dedicated view.
228
- 5. Call `explain_finding` when a reviewer needs evidence and caveats for a specific finding.
229
- 6. Call `get_latest_domain_scan` or `get_latest_domain_pre_consent_cookies_trackers` when the user asks for latest eligible public data for a domain.
305
+ 1. Call `certscore_scan_site` with a public URL. It normally returns the completed scan resource in the same tool call.
306
+ 2. Only if it returns a non-terminal job, call `certscore_get_scan_status` using the stable `scanId` until completion.
307
+ 3. If status is `queued`, `running`, or `finalizing`, retain the returned `scanId` and poll `certscore_get_scan_status` using only that ID. Stop polling at `completed`, `completed_limited`, `failed`, `expired`, or `rate_limited`.
308
+ 4. For `completed` or `completed_limited`, call `certscore_get_scan_bundle` with its default `detail: "summary"`. Use `findings`, `evidence`, or `full` only when progressively deeper bounded context is required.
309
+ 5. Summarize the canonical score, risk, findings, coverage, limitations, report URL, and next action. Never treat no-go, not-observed, or limited coverage as proof of compliance.
310
+
311
+ Canonical first-run prompt:
312
+
313
+ > Scan these public URLs. For each one, call certscore_scan_site. If status is queued, running, or finalizing, retain scanId and poll certscore_get_scan_status using only scanId. Stop polling at completed, completed_limited, failed, expired, or rate_limited. For completed or completed_limited scans, call certscore_get_scan_bundle with detail=findings. If truncated, follow recommendedNextAction or increase maxBytes. Report the canonical score, risk level, coverage, findings, limitations, report URL, and next action. Never treat no-go, not-observed, or limited coverage as proof of compliance.
314
+ 4. Call `certscore_get_report`, `certscore_get_evidence`, `certscore_list_findings`, or `certscore_get_pre_consent_cookies_trackers` only when the task needs a dedicated view.
315
+ 5. Call `certscore_explain_finding` when a reviewer needs evidence and caveats for a specific finding.
316
+ 6. Call `certscore_get_latest_domain_scan` or `certscore_get_latest_domain_pre_consent_cookies_trackers` when the user asks for latest eligible public data for a domain.
230
317
 
231
- `scan_site` reports whether the result was reused, why the freshness decision was made, whether anonymous quota was consumed, the remaining daily allowance, the UTC reset time, and the recommended next tool.
318
+ `certscore_scan_site` reports whether the result was reused, why the freshness decision was made, whether anonymous quota was consumed, the remaining daily allowance, the UTC reset time, and the recommended next tool.
232
319
 
233
320
  With `freshness: "latest"`, CertScore reuses an eligible scan completed within the last 24 hours for the same normalized target and scan region. A reusable result must have completed usable page coverage and must not be an early-loss, no-page, or otherwise non-reusable limited result. Reuse does not consume anonymous quota. `freshnessDecision` states whether a recent result was reused or a new scan was queued; `reusedScanAgeSeconds` reports the reused result's age.
234
321
 
235
322
  ```json
236
323
  {
237
- "tool": "get_pre_consent_cookies_trackers",
324
+ "tool": "certscore_get_pre_consent_cookies_trackers",
238
325
  "arguments": {
239
326
  "scanId": "00000000-0000-4000-8000-000000000123"
240
327
  }
@@ -243,9 +330,9 @@ With `freshness: "latest"`, CertScore reuses an eligible scan completed within t
243
330
 
244
331
  ```json
245
332
  {
246
- "tool": "get_latest_domain_pre_consent_cookies_trackers",
333
+ "tool": "certscore_get_latest_domain_pre_consent_cookies_trackers",
247
334
  "arguments": {
248
- "domain": "example.com",
335
+ "domain": "ergoveritas.com",
249
336
  "scanFrom": "eu_ie"
250
337
  }
251
338
  }
@@ -263,7 +350,7 @@ CERTSCORE_API_KEY=... pnpm mcp:certscore:smoke
263
350
  Optional:
264
351
 
265
352
  ```bash
266
- CERTSCORE_MCP_SMOKE_URL=https://example.com
353
+ CERTSCORE_MCP_SMOKE_URL=https://ergoveritas.com/.well-known/certscore-canary/sentinels/broad-baseline.html
267
354
  ```
268
355
 
269
356
  Without `CERTSCORE_API_KEY`, the smoke script exits successfully with a skip message.
@@ -274,10 +361,18 @@ For the full production operator smoke, run from the WC01 repo:
274
361
  pnpm ops:smoke:mcp-production
275
362
  ```
276
363
 
277
- This verifies the Homebrew-installed `certscore-mcp` command against live `https://certscore.ai`. It creates a short-lived preview key, stores only the hash in production through the approved ECS/Fargate path, checks required tools, requests a fresh EU-IR scan with `freshness: "refresh"` and `scanFrom: "eu_ie"`, requires non-empty findings and pre-consent cookies/trackers rows, runs `explain_finding`, and revokes the temporary key afterward. It exercises existing public-safe API/MCP projections only.
364
+ This verifies the Homebrew-installed `certscore-mcp` command against live `https://certscore.ai`. It creates a short-lived preview key, stores only the hash in production through the approved ECS/Fargate path, checks required tools, requests a fresh EU-IR scan with `freshness: "refresh"` and `scanFrom: "eu_ie"`, requires non-empty findings and pre-consent cookies/trackers rows, runs `certscore_explain_finding`, and revokes the temporary key afterward. It exercises existing public-safe API/MCP projections only.
278
365
 
279
366
  ## Troubleshooting
280
367
 
368
+ - Unexpected OAuth in Codex: remove the server and add it again with the exact Light URL `https://mcp.certscore.ai/mcp/light`. Do not configure a bearer token.
369
+ - Successful Light connection: Streamable HTTP initialization completes, no authorization page opens, and `tools/list` returns exactly `certscore_scan_site`, `certscore_get_scan_status`, and `certscore_get_scan_bundle`.
370
+ - Missing scan ID: retry `certscore_scan_site` only when the error is retryable. Never call `certscore_get_scan_status` until `scanId` exists.
371
+ - Rate limited: follow `retryAfterSeconds` and `recommendedNextAction`, wait for the returned UTC reset, or reuse an eligible result.
372
+ - Reused result: report that the eligible prior scan was reused and quota was not consumed.
373
+ - Truncated bundle: follow `nextRecommendedMaxBytes`, raise `maxBytes`, or open a returned report or evidence content URL.
374
+ - Invalid URL: correct the field named by the structured `invalid_arguments` response and retry with a public HTTP or HTTPS URL.
375
+ - Limited result versus failure: `completed_limited`, no-go, not-observed, and limited coverage are observations only, never proof of compliance. `failed`, `expired`, and connection errors are failures with retry guidance.
281
376
  - Command not found: run the Homebrew install again and confirm Homebrew's bin directory is on `PATH`.
282
377
  - Missing API key: set `CERTSCORE_API_KEY` in the MCP client environment and rerun `certscore-mcp doctor`.
283
378
  - Bad token: rotate the key or request a scoped API/MCP key from `support@certscore.ai`.