{
 "name": "MCP Endpoint Conformance — AI Crawler Index",
 "description": "Point it at an MCP endpoint and it reports what the protocol actually did. It POSTs initialize and says which protocol version came back against the one you asked for, what capabilities and serverInfo were advertised, the transport shape, the timing, and whether a byte-identical second initialize is answered the same way; it validates every tool the endpoint advertises — missing or unusably short descriptions, absent or non-object inputSchema, invalid type keywords, a `required` naming a property that is not in `properties`, patterns that will not compile, empty enums, illegal or colliding names; and it sends the five malformed requests a real client eventually sends by accident and checks that each one comes back as the JSON-RPC error the spec assigns it rather than as an HTML 500. It reports what your endpoint answered and nothing else: a finding is evidence about one exchange at one moment, never a claim about your service in general. It fetches the URL you give it as growth-loop/1.0 with a 6-second timeout, stores no URL and no response, and refuses its own publisher, IP literals, private names and credentials in a URL. Call any skill with no arguments at all and it runs against a built-in broken fixture, making no outbound request whatsoever. Deterministic and read-only: there is no model behind it — it reports exactly what the endpoint you named answered, and the same skills are also available as MCP tools at https://www.pathwren.workers.dev/mcp/lint. No key, no signup, no quota. Independent and unaffiliated with any operator it documents. TO CALL IT: send `message/send` (v1.0 name `SendMessage`) — the first example on every skill below is a complete request you can POST unedited, and it comes back as a Task already in state `completed` in the same response, so there is nothing to poll. Nothing to hand over? The `whoami` skill takes no arguments and answers about you. Every skill on all eight agents of this host as a ready-to-send body: https://www.pathwren.workers.dev/a2a/example.json",
 "supportedInterfaces": [
  {
   "url": "https://www.pathwren.workers.dev/a2a/lint",
   "protocolBinding": "JSONRPC",
   "protocolVersion": "1.0"
  }
 ],
 "url": "https://www.pathwren.workers.dev/a2a/lint",
 "preferredTransport": "JSONRPC",
 "protocolVersion": "1.0",
 "provider": {
  "organization": "Pathwren",
  "url": "https://www.pathwren.workers.dev"
 },
 "version": "1.0.0",
 "documentationUrl": "https://www.pathwren.workers.dev/a2a.html",
 "iconUrl": "https://www.pathwren.workers.dev/icon.png",
 "capabilities": {
  "streaming": false,
  "pushNotifications": false,
  "extendedAgentCard": false,
  "extensions": [
   {
    "uri": "https://www.pathwren.workers.dev/changes.json",
    "description": "Since-cursor change feed for this HOST, not for this agent. GET /changes.json?since=<cursor> returns what moved in the crawler dataset the other agents on this host answer from — this agent has no dataset behind it and nothing in that feed changes what it says about the endpoint you name it, so poll it only if you also use those. It is listed here because the MCP twin of this agent publishes the same feed as a resource, and a card that hid what its own server offers would be the two lanes disagreeing. There is no changes_since skill on this agent.",
    "required": false,
    "params": {
     "cursorParameter": "since",
     "transport": "https-get",
     "minPollSeconds": 21600,
     "describesThisAgent": false,
     "alsoAnMcpResourceOn": "https://www.pathwren.workers.devmcp_lint.js"
    }
   },
   {
    "uri": "https://www.pathwren.workers.dev/mcp/lint",
    "description": "THE SAME AGENT ON THE OTHER PROTOCOL. Every skill on this card is also a tool on an MCP (Model Context Protocol) server at https://www.pathwren.workers.dev/mcp/lint — same name, same arguments, same answer, because one function answers both doors and a deploy that let them drift is refused. JSON-RPC 2.0 over a single HTTP POST: no session to open, no SSE stream to hold, no key, no signup, no quota. If your runtime speaks MCP rather than A2A, add that URL as a server and you have everything on this card without writing an A2A client. `params.initialize` and `params.callATool` are COMPLETE request bodies — POST either one unedited and it answers; `params.curl` is the same thing as one line. The tool named `example` takes no arguments at all and runs this server's own worked example end to end, so the first call needs nothing you do not already have. That server also carries tools this agent does not: they belong to the sibling agents listed in `params.siblingSkillsOnThatServer`, each with its own card and its own URL. Send one of them here and you get a 307 to the agent that performs it, never an invented answer.",
    "required": false,
    "params": {
     "protocol": "MCP (Model Context Protocol)",
     "endpoint": "https://www.pathwren.workers.dev/mcp/lint",
     "transport": "streamable-http (JSON-RPC 2.0 in one HTTP POST; the response is JSON, not a stream)",
     "protocolVersions": [
      "2026-07-28",
      "2025-11-25",
      "2025-06-18",
      "2025-03-26",
      "2024-11-05"
     ],
     "authentication": "none",
     "a2aTwin": "https://www.pathwren.workers.dev/a2a/lint",
     "toolNamesEqualSkillIds": false,
     "everySkillOnThisCardIsAToolThere": true,
     "siblingSkillsOnThatServer": {
      "discovery_report": "https://www.pathwren.workers.dev/a2a/discovery",
      "score_card": "https://www.pathwren.workers.dev/a2a/score"
     },
     "sameImplementation": "Each skill on this card and the tool of the same name on that server are answered by one function; the deploy gate compares them skill by skill.",
     "initialize": {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "initialize",
      "params": {
       "protocolVersion": "2026-07-28",
       "capabilities": {},
       "clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
       }
      }
     },
     "callATool": {
      "jsonrpc": "2.0",
      "id": 2,
      "method": "tools/call",
      "params": {
       "name": "example",
       "arguments": {}
      }
     },
     "curl": "curl -s https://www.pathwren.workers.dev/mcp/lint -H 'content-type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"example\",\"arguments\":{}}}'",
     "everyToolAsABody": "https://www.pathwren.workers.dev/tools/",
     "discovery": "https://www.pathwren.workers.dev/.well-known/mcp.json"
    }
   }
  ]
 },
 "defaultInputModes": [
  "application/json",
  "text/plain"
 ],
 "defaultOutputModes": [
  "application/json",
  "text/plain"
 ],
 "skills": [
  {
   "id": "handshake_report",
   "name": "Does the handshake work, and is it idempotent?",
   "description": "POST initialize to an MCP endpoint you name and report what came back: the protocol version it negotiated against the one you asked for, the capabilities it advertises, serverInfo, timing, the transport shape (JSON or SSE frame, session id, content-type), and — sent a second time, byte for byte — whether the server answers an identical initialize the same way. Also asks for a version nobody publishes, to see whether it negotiates down or agrees to anything. Makes 3 requests, 6 s timeout each, user-agent . Example: url='https://mcp.example.com/mcp' — or call with {} to run it against the built-in fixture, which makes no outbound request at all.",
   "tags": [
    "mcp",
    "conformance",
    "handshake",
    "protocol version"
   ],
   "examples": [
    "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"ROLE_USER\",\"messageId\":\"1\",\"parts\":[{\"text\":\"{\\\"skill\\\":\\\"handshake_report\\\"}\"}]}}}",
    "{\"skill\":\"handshake_report\"}",
    "handshake_report https://mcp.example.com/mcp"
   ],
   "inputModes": [
    "application/json",
    "text/plain"
   ],
   "outputModes": [
    "application/json",
    "text/plain"
   ]
  },
  {
   "id": "tools_list_report",
   "name": "Schema-validate every tool the endpoint advertises",
   "description": "Handshake, then tools/list, then check every tool it returns: a missing or empty description, a description too short to choose on, a missing inputSchema, an inputSchema that is not an object schema, JSON-Schema faults (an invalid type keyword, a `required` naming a property that is not in `properties`, a pattern that will not compile, an empty enum), names that break the character rule, and names that collide — exactly, or once case is ignored. Each finding names the tool and says what breaks. Makes 3 requests, 6 s timeout each. Example: url='https://mcp.example.com/mcp' — or {} for the built-in fixture, whose six tools carry one of each fault.",
   "tags": [
    "mcp",
    "json schema",
    "tools",
    "validation"
   ],
   "examples": [
    "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"ROLE_USER\",\"messageId\":\"1\",\"parts\":[{\"text\":\"{\\\"skill\\\":\\\"tools_list_report\\\"}\"}]}}}",
    "{\"skill\":\"tools_list_report\"}",
    "tools_list_report https://mcp.example.com/mcp"
   ],
   "inputModes": [
    "application/json",
    "text/plain"
   ],
   "outputModes": [
    "application/json",
    "text/plain"
   ]
  },
  {
   "id": "error_conformance",
   "name": "Does it answer JSON-RPC errors, or HTML 500s?",
   "description": "Send five things a real client eventually sends by accident and check what comes back: an unknown method (expects -32601), tools/call naming a tool that does not exist (expects -32602/-32601 or a result with isError), tools/call with no tool name (expects -32602), a body that is not JSON (expects -32700), and a body missing \"jsonrpc\":\"2.0\" (expects -32600). Reports the HTTP status and the error code side by side, and flags an HTML error page or a 5xx where a JSON-RPC error belongs — the failure that makes a client report the wrong cause. Makes 5 requests, 6 s each. Example: url='https://mcp.example.com/mcp' — or {} for the fixture, which fails two of the five.",
   "tags": [
    "mcp",
    "json-rpc",
    "errors",
    "conformance"
   ],
   "examples": [
    "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"ROLE_USER\",\"messageId\":\"1\",\"parts\":[{\"text\":\"{\\\"skill\\\":\\\"error_conformance\\\"}\"}]}}}",
    "{\"skill\":\"error_conformance\"}",
    "error_conformance https://mcp.example.com/mcp"
   ],
   "inputModes": [
    "application/json",
    "text/plain"
   ],
   "outputModes": [
    "application/json",
    "text/plain"
   ]
  },
  {
   "id": "whoami",
   "name": "Who is calling? (no arguments)",
   "description": "Takes no arguments. Safe to call. Deterministic. Touches no third party. Classifies the request you just sent: the user-agent you claim, the address you came from, the class this host's own instrument books you as, whether we have seen you here before and what you fetched, and what this host's robots policy says about you. Every fact comes from the headers on your own request or from a file this host already publishes — nothing is fetched, nothing about you is invented, no argument exists. Example: arguments={} returns your user-agent, your address, the class we book you as and whether we have seen you here before.",
   "tags": [
    "identify",
    "no arguments",
    "diagnostics",
    "user-agent"
   ],
   "examples": [
    "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"ROLE_USER\",\"messageId\":\"1\",\"parts\":[{\"text\":\"{\\\"skill\\\":\\\"whoami\\\"}\"}]}}}",
    "{\"skill\":\"whoami\"}",
    "whoami",
    "who am i to you"
   ],
   "inputModes": [
    "application/json",
    "text/plain"
   ],
   "outputModes": [
    "application/json",
    "text/plain"
   ]
  },
  {
   "id": "example",
   "name": "Run this server's worked example (no arguments)",
   "description": "Takes no arguments. Safe to call. Deterministic. Touches no third party. Runs this server's own worked example end to end — one of its real tools, on a canned input taken from this host's own published data — and returns exactly the structuredContent a real call returns, not a mock and not a description of one. Use it to see the shape of an answer before you decide what to send. No URL of yours is fetched and no third party is touched. Example: arguments={} runs it and returns the real answer.",
   "tags": [
    "example",
    "no arguments",
    "demo",
    "getting started"
   ],
   "examples": [
    "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"ROLE_USER\",\"messageId\":\"1\",\"parts\":[{\"text\":\"{\\\"skill\\\":\\\"example\\\"}\"}]}}}",
    "{\"skill\":\"example\"}",
    "example",
    "show me a worked example"
   ],
   "inputModes": [
    "application/json",
    "text/plain"
   ],
   "outputModes": [
    "application/json",
    "text/plain"
   ]
  }
 ]
}