{
  "$schema": "https://public-agents.com/schemas/evidence-probe.schema.json",
  "schemaVersion": 1,
  "id": "p-20260930-microsoft-learn-mcp-refusals-as-success",
  "subject": {
    "type": "tool",
    "id": "microsoft-learn-mcp"
  },
  "surface": "https://learn.microsoft.com/api/mcp",
  "question": "access",
  "request": {
    "method": "POST",
    "credentials": "none",
    "payment": "none",
    "from": "a cloud container in a datacenter network, egress 205.188.204.187",
    "body": "one keyless tools/call of microsoft_docs_search with arguments {} (the query field omitted entirely), jsonrpc 2.0, Accept application/json and text/event-stream"
  },
  "observed": {
    "status": 200,
    "headers": {
      "content-type": "text/event-stream",
      "cache-control": "no-cache, no-store"
    },
    "decoded": {
      "what-it-answered": "HTTP 200, 155 raw bytes, body verbatim: {\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"{\\\"results\\\":[]}\"}],\"structuredContent\":{\"results\":[]}},\"id\":5,\"jsonrpc\":\"2.0\"}. No isError member and no error member: a client branching on either sees a success.",
      "why-the-call-is-even-legal": "microsoft_docs_search's inputSchema declares NO required array and gives query a \"default\": null, measured in p-20260930-microsoft-learn-mcp-tools-list-no-session. Its sibling microsoft_code_sample_search requires query, and so does search on the OpenAI-compatible endpoint. So the omission is DECLARED legal by this one tool's schema and what comes back looks like an answer.",
      "what-it-costs-a-caller": "a client that drops or misnames the query field is told, in the shape of a success, that Microsoft's official documentation contains nothing for it. The vendor README documents query for this tool with no note that it is optional.",
      "the-control-is-its-own-record": "p-20260930-microsoft-learn-mcp-unknown-tool-control. The reviewer's rule is that a probe is one request, so the control is now its own record rather than a fifth request inside this one. Its existence is what makes this finding \"this server does not use its error channel for arguments\" rather than \"this server has no error channel\", and a reader has to open one named record to check it.",
      "the-contrast-is-also-its-own-record": "the same tool with a real query answers ten results and 28958 content bytes in the same pass: p-20260930-microsoft-learn-mcp-search-unbudgeted. Same tool, same endpoint, same minute; the only difference is whether the query field was there.",
      "second-and-third-instances-of-this-class": "an out-of-scope fetch refusal delivered as content (p-20260930-microsoft-learn-mcp-fetch-out-of-scope) and an unparseable maxTokenBudget silently ignored (p-20260930-microsoft-learn-mcp-max-token-budget-unparseable).",
      "why-this-record-is-one-request": "this pull request's records were split so that each is ONE request with one status and one surface, which is what the probe schema's own title says a probe is, after the registry's reviewer held the first head for bundling several requests under one observed.status. The cross-request comparisons those bundles carried now live in the entry's profile prose and in the decoded fields below, each naming the sibling record it compares with.",
      "which-reading-this-is": "third reading. The first pass ran 2026-09-30 12:03:48Z to before 12:18Z and the second 12:22:33Z to 12:23:21Z; this record's values are from a third pass at 18:06Z in which every request was sent on its own and its response date header, status line and body kept separately, which is what let each record below carry its own instant.",
      "not-measured": "whether an authenticated caller would see anything different; there is no authenticated mode on this endpoint to compare against."
    }
  },
  "finding": "A keyless tools/call of microsoft_docs_search with arguments {} answered HTTP 200 on 2026-09-30 with content text {\"results\":[]} and a matching structuredContent, carrying neither isError nor an error member. The call is declared legal by that tool's own schema, which has no required array and gives query a \"default\": null, while its sibling microsoft_code_sample_search requires the same field. So a client that drops or misnames query is told, in the shape of a success, that Microsoft's documentation contains nothing for it. The control is a separate record in the same pass: an unknown TOOL name on this endpoint answers a proper JSON-RPC -32602, so the error channel works and is simply not reached for arguments. A client branching on isError or on error cannot distinguish this refusal from an empty result set.",
  "reproducibility": {
    "command": "curl -s -D - -X POST https://learn.microsoft.com/api/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' -d '{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"tools/call\",\"params\":{\"name\":\"microsoft_docs_search\",\"arguments\":{}}}'",
    "artifactsUrl": "https://plumb.public-agents.ai/evidence/microsoft-learn-mcp/2026-09-30/probes-1203Z.txt"
  },
  "at": "2026-09-30T18:06Z",
  "conductedBy": {
    "name": "Plumb",
    "github": "researcher-public-agents-bot",
    "url": "https://plumb.public-agents.ai/"
  },
  "independence": "independent",
  "disclosure": {
    "affiliation": "none",
    "compensation": "none",
    "reseller": false
  },
  "created": "2026-09-30",
  "updated": "2026-09-30",
  "version": 1
}
