Koskamo

Hacker Bob MCP

A hosted Model Context Protocol server providing read-only access to public Common Vulnerabilities and Exposures (CVE) records, capability metadata, and agent instructions for authorized offensive-security testing.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Hacker Bob MCP logo, by Hacker BobCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-07Published by Hacker Bob
MCP endpoint (Streamable HTTP)
https://hackerbob.ai/mcp
Vendor documentation

What its tools do

22 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

22 of 22 have a description · 22 of 22 declare behavior hints · 7 of 19 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Warning Advertises resources/templates/list but does not implement it
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Retrieve public CVE records
  • Access capability metadata
  • View agent instructions
  • Discover cleared public data

Source and maintenance

Community listingRegistry 1.0.0
Maintenance checked

Protocol and capabilities

Server
hacker-bob 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
22 advertised
Resources
3 advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  },
  "resources": {
    "subscribe": false,
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Public tools read cleared CVE records. Authenticated workspace tools require OAuth or device authorization. Assessment launch always requires human approval of the exact prepared run.

Tools

22 advertised

list_public_cve_records — List public CVE records
Advertised by the server during the last successful anonymous check.
Advertised read-only

List cleared public Hacker Bob Common Vulnerabilities and Exposures records with cursor pagination and optional project or publication-status filters.

list_public_cve_records input schema
{
  "type": "object",
  "required": [],
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 100,
      "minimum": 1,
      "description": "Maximum records to return. Defaults to 20."
    },
    "cursor": {
      "type": "string",
      "description": "Opaque cursor returned by a previous list call."
    },
    "status": {
      "enum": [
        "public",
        "assigned-no-public-record"
      ],
      "type": "string",
      "description": "Publication status to include."
    },
    "project": {
      "type": "string",
      "description": "Exact open-source project name to include."
    }
  },
  "additionalProperties": false
}
list_public_cve_records annotations
{
  "title": "List public CVE records",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_public_cve_record — Get one public CVE record
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return one cleared Hacker Bob CVE record by identifier, including its open-source project, publication status, and upstream public record URL when available.

get_public_cve_record input schema
{
  "type": "object",
  "required": [
    "recordId"
  ],
  "properties": {
    "recordId": {
      "type": "string",
      "pattern": "^CVE-[0-9]{4}-[0-9]+$",
      "description": "CVE identifier such as CVE-2026-47747."
    }
  },
  "additionalProperties": false
}
get_public_cve_record annotations
{
  "title": "Get one public CVE record",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
search_public_cve_records — Search public CVE records
Advertised by the server during the last successful anonymous check.
Advertised read-only

Search cleared public Hacker Bob CVE records by CVE identifier, open-source project name, or publication status without contacting any assessment target.

search_public_cve_records input schema
{
  "type": "object",
  "required": [
    "query"
  ],
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 50,
      "minimum": 1,
      "description": "Maximum matching records to return. Defaults to 20."
    },
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Text to match against CVE identifiers, project names, and publication status."
    }
  },
  "additionalProperties": false
}
search_public_cve_records annotations
{
  "title": "Search public CVE records",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_capabilities — Get Hacker Bob capabilities
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return current public boundaries and, when authenticated, workspace-specific tool reachability, scopes, and role requirements.

get_capabilities input schema
{
  "type": "object",
  "required": [],
  "properties": {},
  "additionalProperties": false
}
get_capabilities annotations
{
  "title": "Get Hacker Bob capabilities",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_my_account — Get my Hacker Bob account
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return the authenticated account and the workspace bound to this agent connection.

get_my_account input schema
{
  "type": "object",
  "required": [],
  "properties": {},
  "additionalProperties": false
}
get_my_account annotations
{
  "title": "Get my Hacker Bob account",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
list_workspaces — List my workspaces
Advertised by the server during the last successful anonymous check.
Advertised read-only

List active Hacker Bob workspaces available to the authenticated account. The connection remains bound to its approved workspace.

list_workspaces input schema
{
  "type": "object",
  "required": [],
  "properties": {},
  "additionalProperties": false
}
list_workspaces annotations
{
  "title": "List my workspaces",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_workspace — Get workspace
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return the approved workspace and current membership role.

get_workspace input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_workspace annotations
{
  "title": "Get workspace",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
list_assets — List authorized assets
Advertised by the server during the last successful anonymous check.
Advertised read-only

List workspace assets and current ownership-authorization state without contacting a target.

list_assets input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "includeArchived": {
      "type": "boolean",
      "description": "Include archived assets. Defaults to false."
    }
  },
  "additionalProperties": false
}
list_assets annotations
{
  "title": "List authorized assets",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_asset — Get authorized asset
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return one workspace asset and its current authorization state.

get_asset input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "assetId"
  ],
  "properties": {
    "assetId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_asset annotations
{
  "title": "Get authorized asset",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
begin_domain_authorization — Begin domain authorization
Advertised by the server during the last successful anonymous check.

Create a DNS TXT or HTTPS-file challenge proving control of a domain. This does not run an assessment.

begin_domain_authorization input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "domain",
    "method",
    "idempotencyKey"
  ],
  "properties": {
    "label": {
      "type": "string",
      "maxLength": 120,
      "minLength": 1
    },
    "domain": {
      "type": "string",
      "maxLength": 253,
      "minLength": 1,
      "description": "Domain name only; no scheme, path, port, credentials, or wildcard."
    },
    "method": {
      "enum": [
        "dns_txt",
        "http_file"
      ],
      "type": "string"
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "idempotencyKey": {
      "type": "string",
      "maxLength": 128,
      "minLength": 8
    }
  },
  "additionalProperties": false
}
begin_domain_authorization annotations
{
  "title": "Begin domain authorization",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
check_domain_authorization — Check domain authorization
Advertised by the server during the last successful anonymous check.
Open-world

Check the previously issued DNS or HTTPS proof and update the asset authorization state.

check_domain_authorization input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "authorizationId",
    "idempotencyKey"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "idempotencyKey": {
      "type": "string",
      "maxLength": 128,
      "minLength": 8
    },
    "authorizationId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    }
  },
  "additionalProperties": false
}
check_domain_authorization annotations
{
  "title": "Check domain authorization",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": false
}
list_assessments — List assessments
Advertised by the server during the last successful anonymous check.
Advertised read-only

List assessments and current run states in the approved workspace.

list_assessments input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "includeArchived": {
      "type": "boolean"
    }
  },
  "additionalProperties": false
}
list_assessments annotations
{
  "title": "List assessments",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_assessment — Get assessment
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return one assessment, its verified asset, current run state, and any pending human approval.

get_assessment input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "assessmentId"
  ],
  "properties": {
    "assessmentId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_assessment annotations
{
  "title": "Get assessment",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
prepare_assessment — Prepare assessment
Advertised by the server during the last successful anonymous check.

Create an immutable assessment for a verified stored asset and return a browser approval URL. This never contacts the target.

prepare_assessment input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "assetId",
    "depth",
    "coverage",
    "interactionPolicy",
    "idempotencyKey"
  ],
  "properties": {
    "depth": {
      "enum": [
        "standard",
        "deep"
      ],
      "type": "string"
    },
    "assetId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "coverage": {
      "type": "object",
      "required": [
        "mode",
        "rules"
      ],
      "properties": {
        "mode": {
          "enum": [
            "all",
            "exclude",
            "include"
          ],
          "type": "string"
        },
        "rules": {
          "type": "array",
          "items": {
            "type": "string",
            "maxLength": 240,
            "minLength": 1
          },
          "maxItems": 100
        }
      },
      "additionalProperties": false
    },
    "boundaries": {
      "type": "string",
      "maxLength": 1000
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "idempotencyKey": {
      "type": "string",
      "maxLength": 128,
      "minLength": 8
    },
    "interactionPolicy": {
      "enum": [
        "safe",
        "stateful"
      ],
      "type": "string"
    }
  },
  "additionalProperties": false
}
prepare_assessment annotations
{
  "title": "Prepare assessment",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
launch_assessment — Submit approved assessment
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Consume a recent human approval and submit the immutable assessment to Hacker Bob's managed queue. The target is resolved only from the stored verified asset.

launch_assessment input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "assessmentId",
    "idempotencyKey"
  ],
  "properties": {
    "assessmentId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "idempotencyKey": {
      "type": "string",
      "maxLength": 128,
      "minLength": 8
    }
  },
  "additionalProperties": false
}
launch_assessment annotations
{
  "title": "Submit approved assessment",
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": true,
  "destructiveHint": true
}
cancel_assessment — Cancel assessment
Advertised by the server during the last successful anonymous check.
Advertised destructive

Cancel an eligible queued or running assessment and reconcile any refundable reserved credit.

cancel_assessment input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "assessmentId",
    "idempotencyKey"
  ],
  "properties": {
    "assessmentId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    },
    "idempotencyKey": {
      "type": "string",
      "maxLength": 128,
      "minLength": 8
    }
  },
  "additionalProperties": false
}
cancel_assessment annotations
{
  "title": "Cancel assessment",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
list_findings — List findings
Advertised by the server during the last successful anonymous check.
Advertised read-only

List workspace findings with optional lifecycle and severity filters.

list_findings input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "status": {
      "type": "string",
      "maxLength": 40
    },
    "assetId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "severity": {
      "enum": [
        "critical",
        "high",
        "medium",
        "low"
      ],
      "type": "string"
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
list_findings annotations
{
  "title": "List findings",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_finding — Get finding
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return one finding with evidence-safe lifecycle history and related asset metadata.

get_finding input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "findingId"
  ],
  "properties": {
    "findingId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_finding annotations
{
  "title": "Get finding",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
list_reports — List released reports
Advertised by the server during the last successful anonymous check.
Advertised read-only

List non-revoked reports released to the approved workspace.

list_reports input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
list_reports annotations
{
  "title": "List released reports",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_report — Get released report
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return one released, non-revoked workspace report. Pending review material and access credentials are never returned.

get_report input schema
{
  "type": "object",
  "required": [
    "workspaceSlug",
    "reportId"
  ],
  "properties": {
    "reportId": {
      "type": "string",
      "maxLength": 128,
      "minLength": 1
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_report annotations
{
  "title": "Get released report",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_credit_summary — Get credit summary
Advertised by the server during the last successful anonymous check.
Advertised read-only

Return available, reserved, and used assessment credits for the approved workspace.

get_credit_summary input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
get_credit_summary annotations
{
  "title": "Get credit summary",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
list_audit_events — List audit events
Advertised by the server during the last successful anonymous check.
Advertised read-only

List recent workspace audit events with optional actor, action, and time filters.

list_audit_events input schema
{
  "type": "object",
  "required": [
    "workspaceSlug"
  ],
  "properties": {
    "toAt": {
      "type": "number",
      "minimum": 0
    },
    "actor": {
      "type": "string",
      "maxLength": 254
    },
    "action": {
      "type": "string",
      "maxLength": 80
    },
    "fromAt": {
      "type": "number",
      "minimum": 0
    },
    "workspaceSlug": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
      "maxLength": 80,
      "minLength": 1,
      "description": "Workspace slug selected during agent authorization."
    }
  },
  "additionalProperties": false
}
list_audit_events annotations
{
  "title": "List audit events",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

3 advertised

public-cve-records — Hacker Bob public CVE records

Advertised by the server during the last successful anonymous check.

Complete machine-readable index of cleared public CVE records and assigned IDs without public records.

public-cve-records URI
hackerbob://public/cve-records

MIME type: application/json

public-capabilities — Hacker Bob public capabilities

Advertised by the server during the last successful anonymous check.

Read-only public API and MCP capabilities plus the explicit no-assessment-execution boundary.

public-capabilities URI
hackerbob://public/capabilities

MIME type: application/json

agent-instructions — Hacker Bob agent instructions

Advertised by the server during the last successful anonymous check.

When-to-use instructions and authorization boundaries for public records and the local runtime.

agent-instructions URI
hackerbob://docs/agent-instructions

MIME type: text/markdown

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
504 ms
95th percentile latency
504 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 504 ms · metadata changed · 22 tool(s), 3 resource(s); warnings: Advertises resources/templates/list but does not implement it

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http hacker-bob-mcp https://hackerbob.ai/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add hacker-bob-mcp --url https://hackerbob.ai/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable hacker-bob-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "hacker-bob-mcp": {
      "url": "https://hackerbob.ai/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "hacker-bob-mcp": {
      "type": "streamableHttp",
      "url": "https://hackerbob.ai/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start hacker-bob-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "hacker-bob-mcp": {
      "type": "http",
      "url": "https://hackerbob.ai/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http hacker-bob-mcp https://hackerbob.ai/mcp

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://hackerbob.ai/mcp

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "hacker-bob-mcp": {
      "serverUrl": "https://hackerbob.ai/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Hacker Bob MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.