agent-ready-mcp 0.5.4 → 0.6.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/dist/mcp-server.mjs +78 -4
- package/package.json +1 -1
package/dist/mcp-server.mjs
CHANGED
|
@@ -23093,6 +23093,50 @@ async function call(config2, opts) {
|
|
|
23093
23093
|
}
|
|
23094
23094
|
return payload;
|
|
23095
23095
|
}
|
|
23096
|
+
async function postAnonScan(config2, url2) {
|
|
23097
|
+
const path = "/api/scan";
|
|
23098
|
+
let res;
|
|
23099
|
+
try {
|
|
23100
|
+
res = await fetch(`${config2.baseUrl}${path}`, {
|
|
23101
|
+
method: "POST",
|
|
23102
|
+
headers: {
|
|
23103
|
+
"Content-Type": "application/json",
|
|
23104
|
+
Accept: "application/json"
|
|
23105
|
+
},
|
|
23106
|
+
body: JSON.stringify({ url: url2 }),
|
|
23107
|
+
signal: AbortSignal.timeout(config2.scanTimeoutMs)
|
|
23108
|
+
});
|
|
23109
|
+
} catch (err) {
|
|
23110
|
+
if (err instanceof Error && err.name === "TimeoutError") {
|
|
23111
|
+
throw new ApiError(
|
|
23112
|
+
"timeout",
|
|
23113
|
+
`Request to ${path} timed out after ${config2.scanTimeoutMs}ms.`
|
|
23114
|
+
);
|
|
23115
|
+
}
|
|
23116
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
23117
|
+
throw new ApiError("network_error", `Network error calling ${path}: ${message}`);
|
|
23118
|
+
}
|
|
23119
|
+
const text = await res.text();
|
|
23120
|
+
let payload = null;
|
|
23121
|
+
if (text.length > 0) {
|
|
23122
|
+
try {
|
|
23123
|
+
payload = JSON.parse(text);
|
|
23124
|
+
} catch {
|
|
23125
|
+
}
|
|
23126
|
+
}
|
|
23127
|
+
if (!res.ok) {
|
|
23128
|
+
const body = payload && typeof payload === "object" ? payload : null;
|
|
23129
|
+
let message = typeof body?.error === "string" && body.error ? body.error : text || `HTTP ${res.status} from ${path}`;
|
|
23130
|
+
if (res.status === 429) {
|
|
23131
|
+
if (typeof body?.resetAt === "string") {
|
|
23132
|
+
message += ` Quota resets ${body.resetAt.slice(0, 10)}.`;
|
|
23133
|
+
}
|
|
23134
|
+
throw new ApiError("quota_exhausted", message, res.status);
|
|
23135
|
+
}
|
|
23136
|
+
throw new ApiError(`http_${res.status}`, message, res.status);
|
|
23137
|
+
}
|
|
23138
|
+
return payload;
|
|
23139
|
+
}
|
|
23096
23140
|
async function postScan(config2, body) {
|
|
23097
23141
|
return call(config2, {
|
|
23098
23142
|
method: "POST",
|
|
@@ -31531,7 +31575,31 @@ var POLL_INTERVAL_MS = 2e3;
|
|
|
31531
31575
|
async function sleep(ms) {
|
|
31532
31576
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31533
31577
|
}
|
|
31578
|
+
var ANON_TIER_NOTE = "Scanned on the anonymous free tier (3 scans per 30 days per IP, 25-page depth). A Pro API key (AGENT_READY_API_KEY) unlocks 50 scans/month, 250-page depth, scan history via get_scan, and weekly monitoring \u2014 https://agent-ready.dev/pricing";
|
|
31534
31579
|
async function scanSite(config2, input) {
|
|
31580
|
+
if (!config2.apiKey) {
|
|
31581
|
+
let res;
|
|
31582
|
+
try {
|
|
31583
|
+
res = await postAnonScan(config2, input.url);
|
|
31584
|
+
} catch (err) {
|
|
31585
|
+
if (err instanceof ApiError) {
|
|
31586
|
+
const hint = err.status === 429 ? " Set a Pro API key (AGENT_READY_API_KEY, from https://agent-ready.dev/dashboard/api-keys) to remove the anonymous cap." : "";
|
|
31587
|
+
throw new ToolError(err.code, err.message + hint);
|
|
31588
|
+
}
|
|
31589
|
+
throw err;
|
|
31590
|
+
}
|
|
31591
|
+
if (!res || typeof res !== "object" || !res.scan) {
|
|
31592
|
+
throw new ToolError(
|
|
31593
|
+
"invalid_response",
|
|
31594
|
+
"Anonymous scan returned no scan payload from /api/scan."
|
|
31595
|
+
);
|
|
31596
|
+
}
|
|
31597
|
+
const payload = { ...res.scan, message: ANON_TIER_NOTE };
|
|
31598
|
+
return {
|
|
31599
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
31600
|
+
structuredContent: payload
|
|
31601
|
+
};
|
|
31602
|
+
}
|
|
31535
31603
|
let placeholder;
|
|
31536
31604
|
try {
|
|
31537
31605
|
placeholder = await postScan(config2, {
|
|
@@ -31605,6 +31673,12 @@ async function getScanById(config2, input) {
|
|
|
31605
31673
|
if (err.status === 404) {
|
|
31606
31674
|
throw new ToolError("not_found", `Scan ${input.id} not found.`);
|
|
31607
31675
|
}
|
|
31676
|
+
if (err.code === "missing_api_key") {
|
|
31677
|
+
throw new ToolError(
|
|
31678
|
+
"missing_api_key",
|
|
31679
|
+
"get_scan needs a Pro API key (scan history is account-scoped). scan_site works without one on the anonymous tier and returns its result inline. Keys: https://agent-ready.dev/dashboard/api-keys"
|
|
31680
|
+
);
|
|
31681
|
+
}
|
|
31608
31682
|
throw new ToolError(err.code, err.message);
|
|
31609
31683
|
}
|
|
31610
31684
|
throw err;
|
|
@@ -31754,7 +31828,7 @@ var validateStructuredDataInputShape = {
|
|
|
31754
31828
|
// src/server.ts
|
|
31755
31829
|
var SERVER_INFO = {
|
|
31756
31830
|
name: "agent-ready",
|
|
31757
|
-
version: "0.
|
|
31831
|
+
version: "0.6.0"
|
|
31758
31832
|
};
|
|
31759
31833
|
function createMcpServer(config2) {
|
|
31760
31834
|
const server = new McpServer(SERVER_INFO);
|
|
@@ -31768,7 +31842,7 @@ function createMcpServer(config2) {
|
|
|
31768
31842
|
"scan_site",
|
|
31769
31843
|
{
|
|
31770
31844
|
title: "Scan a site for AI agent readability",
|
|
31771
|
-
description: "Runs the agent-ready.dev scanner against a URL and returns structured results: Vercel score, llmstxt.org score, and per-check findings with remediation hints.
|
|
31845
|
+
description: "Runs the agent-ready.dev scanner against a URL and returns structured results: Vercel score, llmstxt.org score, and per-check findings with remediation hints. Works without an API key on the anonymous free tier (3 scans/30 days per IP, 25-page depth, synchronous). With a Pro AGENT_READY_API_KEY it scans deeper (up to 250 pages) and may take up to ~60s; if the local poll deadline elapses, the tool returns the scan id and asks you to poll with get_scan.",
|
|
31772
31846
|
inputSchema: scanSiteInputShape,
|
|
31773
31847
|
outputSchema: scanOutputShape,
|
|
31774
31848
|
annotations: READ_ONLY_OPEN_WORLD
|
|
@@ -31785,7 +31859,7 @@ function createMcpServer(config2) {
|
|
|
31785
31859
|
"get_scan",
|
|
31786
31860
|
{
|
|
31787
31861
|
title: "Get a previous scan by id",
|
|
31788
|
-
description: "Fetches a completed or in-progress scan by its id.
|
|
31862
|
+
description: "Fetches a completed or in-progress scan by its id. Requires a Pro API key \u2014 scan history is account-scoped. (Anonymous scan_site calls return their result inline, so keyless use never needs this tool.)",
|
|
31789
31863
|
inputSchema: getScanInputShape,
|
|
31790
31864
|
outputSchema: scanOutputShape,
|
|
31791
31865
|
annotations: READ_ONLY_OPEN_WORLD
|
|
@@ -31853,7 +31927,7 @@ async function main() {
|
|
|
31853
31927
|
const config2 = createConfig();
|
|
31854
31928
|
if (!config2.apiKey) {
|
|
31855
31929
|
process.stderr.write(
|
|
31856
|
-
"agent-ready-mcp started without AGENT_READY_API_KEY \u2014
|
|
31930
|
+
"agent-ready-mcp started without AGENT_READY_API_KEY \u2014 scan_site runs on the anonymous free tier (3 scans per 30 days per IP, 25-page depth); get_scan needs a Pro key. Issue one at https://agent-ready.dev/dashboard/api-keys for deeper scans, history, and monitoring.\n"
|
|
31857
31931
|
);
|
|
31858
31932
|
}
|
|
31859
31933
|
const server = createMcpServer(config2);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-ready-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"mcpName": "io.github.mlava/agent-ready-mcp",
|
|
5
5
|
"description": "MCP server for Agent Ready — scan any URL for AI-readability against the Vercel Agent Readability Spec, the llmstxt.org standard, and agent-protocol manifests (MCP server cards, A2A, agents.json, agent-permissions.json, UCP, x402, NLWeb). 69 checks with per-check fix guidance.",
|
|
6
6
|
"license": "MIT",
|