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.
@@ -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.5.4"
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. Scans 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.",
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. Only scans owned by the authenticated API key's user are returned.",
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 tools will return a configuration message until a key is set. Issue a Pro API key at https://agent-ready.dev/dashboard/api-keys.\n"
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.5.4",
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",