x402-surface-check 0.2.39 → 0.2.40
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 +1 -1
- package/bin/x402-surface-check.mjs +54 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ npx --yes x402-surface-check --strict-proof https://api.example.com/openapi.json
|
|
|
20
20
|
|
|
21
21
|
## What It Checks
|
|
22
22
|
|
|
23
|
-
- Manifest endpoint discovery from `items[]`, `endpoints[]`, marketplace `skills[]` / `catalog.skills[]`, object-valued `endpoints`, string-valued endpoint maps, `tools` maps, `resources[]`, `x402Endpoints`, category arrays, raw resource URL strings, method-prefixed resource strings, and OpenAPI paths
|
|
23
|
+
- Manifest endpoint discovery from `items[]`, `endpoints[]`, marketplace `skills[]` / `catalog.skills[]`, `agents[].tools[]` resource URLs, object-valued `endpoints`, string-valued endpoint maps, `tools` maps, `resources[]`, `x402Endpoints`, category arrays, raw resource URL strings, method-prefixed resource strings, and OpenAPI paths
|
|
24
24
|
- Streamable HTTP MCP tool catalogs via safe JSON-RPC `tools/list` probes with `Accept: application/json, text/event-stream`
|
|
25
25
|
- Object-valued manifest endpoint query examples, public catalog/discovery GETs, and payment-bearing two-phase operations without treating expected public catalog reads as failed payment gates
|
|
26
26
|
- Linked discovery documents via `discovery_url`, `discoveryUrl`, `resources_url`, `resourcesUrl`, string `discovery` links, nested `discovery.x402_json` / OpenAPI links, or manifest-level OpenAPI links
|
|
@@ -376,6 +376,22 @@ function marketplaceSkillPriceUsd(skill) {
|
|
|
376
376
|
return numberFromDecimal(value)
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
+
function endpointRawPath(endpoint) {
|
|
380
|
+
if (!endpoint || typeof endpoint !== 'object') return undefined
|
|
381
|
+
const values = [
|
|
382
|
+
endpoint.url,
|
|
383
|
+
endpoint.endpoint,
|
|
384
|
+
endpoint.resourceUrl,
|
|
385
|
+
endpoint.resourceURL,
|
|
386
|
+
endpoint.resource_url,
|
|
387
|
+
endpoint.resource?.url,
|
|
388
|
+
endpoint.resource?.uri,
|
|
389
|
+
endpoint.resource,
|
|
390
|
+
endpoint.path,
|
|
391
|
+
]
|
|
392
|
+
return values.find(value => typeof value === 'string' && value.trim())
|
|
393
|
+
}
|
|
394
|
+
|
|
379
395
|
function manifestEndpointUrl(rawPath, endpoint, baseUrl, sourceUrl) {
|
|
380
396
|
const url = new URL(endpointUrl(rawPath, baseUrl, sourceUrl))
|
|
381
397
|
const parameters = endpoint?.parameters
|
|
@@ -432,7 +448,7 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
432
448
|
for (const skillList of marketplaceSkillLists) {
|
|
433
449
|
for (const skill of skillList) {
|
|
434
450
|
if (!skill || typeof skill !== 'object') continue
|
|
435
|
-
const rawPath = skill
|
|
451
|
+
const rawPath = endpointRawPath(skill)
|
|
436
452
|
if (!rawPath) continue
|
|
437
453
|
if (redactedCredentialUrl(rawPath)) continue
|
|
438
454
|
entries.push({
|
|
@@ -445,9 +461,41 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
445
461
|
}
|
|
446
462
|
}
|
|
447
463
|
|
|
464
|
+
const agentCatalogLists = [
|
|
465
|
+
document.agents,
|
|
466
|
+
document.catalog?.agents,
|
|
467
|
+
document.marketplace?.agents,
|
|
468
|
+
].filter(Array.isArray)
|
|
469
|
+
|
|
470
|
+
for (const agentList of agentCatalogLists) {
|
|
471
|
+
for (const agent of agentList) {
|
|
472
|
+
if (!agent || typeof agent !== 'object' || !Array.isArray(agent.tools)) continue
|
|
473
|
+
const agentName = agent.agentId ?? agent.agent_id ?? agent.slug ?? agent.id ?? agent.name
|
|
474
|
+
for (const tool of agent.tools) {
|
|
475
|
+
if (!tool || typeof tool !== 'object') continue
|
|
476
|
+
const rawPath = endpointRawPath(tool)
|
|
477
|
+
if (!rawPath) continue
|
|
478
|
+
if (redactedCredentialUrl(rawPath)) continue
|
|
479
|
+
const method = String(tool.method ?? 'POST').toUpperCase()
|
|
480
|
+
const paymentSignal = Math.max(manifestEndpointPaymentSignal(agent), manifestEndpointPaymentSignal(tool))
|
|
481
|
+
const hasPathParameters = /\{[^}]+\}/.test(String(rawPath))
|
|
482
|
+
if (paymentSignal === 0 && (method !== 'GET' || hasPathParameters)) continue
|
|
483
|
+
const toolName = tool.slug ?? tool.id ?? tool.name ?? String(rawPath).split('/').filter(Boolean).at(-1)
|
|
484
|
+
entries.push({
|
|
485
|
+
name: agentName && toolName ? `${agentName}/${toolName}` : toolName ?? agentName ?? String(rawPath),
|
|
486
|
+
url: manifestEndpointUrl(rawPath, tool, baseUrl, sourceUrl),
|
|
487
|
+
method,
|
|
488
|
+
expectedPriceUsd: marketplaceSkillPriceUsd(tool) ?? marketplaceSkillPriceUsd(agent),
|
|
489
|
+
requestBody: marketplaceSkillBody(tool) ?? marketplaceSkillBody(agent),
|
|
490
|
+
publicDiscovery: paymentSignal === 0,
|
|
491
|
+
})
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
448
496
|
if (Array.isArray(document.endpoints)) {
|
|
449
497
|
for (const endpoint of document.endpoints) {
|
|
450
|
-
const rawPath = endpoint
|
|
498
|
+
const rawPath = endpointRawPath(endpoint)
|
|
451
499
|
if (!rawPath) continue
|
|
452
500
|
entries.push({
|
|
453
501
|
name: endpoint.id ?? endpoint.name ?? String(rawPath).split('/').filter(Boolean).at(-1) ?? String(rawPath),
|
|
@@ -487,7 +535,7 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
487
535
|
if (Array.isArray(document.tools)) {
|
|
488
536
|
for (const tool of document.tools) {
|
|
489
537
|
if (!tool || typeof tool !== 'object') continue
|
|
490
|
-
const rawPath = tool
|
|
538
|
+
const rawPath = endpointRawPath(tool)
|
|
491
539
|
if (!rawPath) continue
|
|
492
540
|
const method = String(tool.method ?? 'POST').toUpperCase()
|
|
493
541
|
const paymentSignal = manifestEndpointPaymentSignal(tool)
|
|
@@ -516,7 +564,7 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
516
564
|
}
|
|
517
565
|
if (!endpoint || typeof endpoint !== 'object') continue
|
|
518
566
|
const keyPath = key.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)/i)?.[2] ?? key
|
|
519
|
-
const rawPath = endpoint
|
|
567
|
+
const rawPath = endpointRawPath(endpoint) ?? keyPath
|
|
520
568
|
if (!rawPath) continue
|
|
521
569
|
const method = String(endpoint.method ?? 'POST').toUpperCase()
|
|
522
570
|
const paymentSignal = manifestEndpointPaymentSignal(endpoint)
|
|
@@ -535,7 +583,7 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
535
583
|
if (Array.isArray(document.items)) {
|
|
536
584
|
for (const item of document.items) {
|
|
537
585
|
if (item?.type && item.type !== 'http') continue
|
|
538
|
-
const rawPath = item
|
|
586
|
+
const rawPath = endpointRawPath(item)
|
|
539
587
|
if (!rawPath) continue
|
|
540
588
|
entries.push({
|
|
541
589
|
name: item.metadata?.name ?? item.id ?? item.name ?? String(rawPath).split('/').filter(Boolean).at(-1) ?? String(rawPath),
|
|
@@ -588,7 +636,7 @@ function endpointEntries(document, sourceUrl, limit) {
|
|
|
588
636
|
}
|
|
589
637
|
|
|
590
638
|
if (!resource || typeof resource !== 'object') continue
|
|
591
|
-
const rawPath = resource
|
|
639
|
+
const rawPath = endpointRawPath(resource)
|
|
592
640
|
if (!rawPath) continue
|
|
593
641
|
entries.push({
|
|
594
642
|
name: resource.id
|