Koskamo

Zovo Cap Table Calculator MCP

A cap table calculator for SAFEs, notes and priced rounds, with dilution math to the share. It returns the pro-forma cap table before and after, the price per share, each instrument's conversion price and shares, and each holder's dilution. The circular pool and SAFE math is solved with fraction math, and you get an Excel cap table and a PDF summary.

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.

Zovo Cap Table Calculator MCP logo, by ZovoCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-08Published by Zovo
MCP endpoint (Streamable HTTP)
https://cap-table.zovo.one/mcp
Vendor documentation

What its tools do

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

2 of 2 have a description · 2 of 2 declare behavior hints · 2 of 2 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Calculate pro-forma cap tables for post-money SAFEs, pre-money SAFEs, convertible notes, or priced rounds
  • Determine dilution for each holder based on current holdings and next funding event
  • Compute conversion prices for instruments using the lower of cap price and discount price
  • Generate Excel cap tables and PDF summaries with before/after ownership bars

Source and maintenance

Community listingRegistry 1.0.0

Protocol and capabilities

Server
cap-table 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
2 advertised
Resources
1 advertised
Resource templates
1 advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "resources": {
    "listChanged": true
  }
}

Server-provided instructions

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

Zovo Cap Table Calculator models startup dilution with exact math. Use calculate_cap_table for a pro-forma cap table before and after SAFEs, convertible notes and a priced round (pre-money valuation, new money, target option pool); use calculate_safe_ownership for a quick SAFE ownership check (investment / post-money cap). Pass every holder with shares, including the unallocated option pool. Results are illustrative, not legal or tax advice; the real documents govern.

Tools

2 advertised

calculate_cap_table — Calculate cap table
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use this when the user wants a cap table calculator or startup dilution calculator: a pro-forma cap table before and after post-money or pre-money SAFEs, convertible notes (principal plus simple interest, cap, discount) and/or a priced round (pre-money valuation, new money, target option pool topped up in the pre-money). Returns price per share, each instrument's cap price, discount price and conversion price (the lower), shares issued, each holder's fully diluted % before and after, an Excel cap table and a PDF summary. Solves the circular pool and conversion math with fractions, then rounds to whole shares. Illustrative only; does not model liquidation preferences, vesting, anti-dilution or more than one priced round, and is not legal or tax advice.

calculate_cap_table input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "holders"
  ],
  "properties": {
    "notes": {
      "anyOf": [
        {
          "anyOf": [
            {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "name": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 80
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Note label, e.g. \"Bridge note\"."
                  },
                  "discount": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Discount in percent, e.g. 20."
                  },
                  "principal": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Principal, e.g. 250000 or \"$250k\"."
                  },
                  "issue_date": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 30
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Date the note was issued, e.g. 2025-03-01. Interest accrues from here to conversion_date (actual days / 365)."
                  },
                  "interest_rate": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Simple annual interest in percent, e.g. 6 for 6%."
                  },
                  "valuation_cap": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Valuation cap, e.g. 6000000. Cap price = cap / fully diluted shares before the round (excluding converting securities and the new pool)."
                  },
                  "conversion_date": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 30
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Conversion date, e.g. 2026-06-30. Default: the round date, else today (America/New_York)."
                  }
                },
                "additionalProperties": {}
              }
            },
            {
              "type": "string"
            }
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "Convertible notes, e.g. [{\"principal\":250000,\"interest_rate\":6,\"issue_date\":\"2025-03-01\",\"valuation_cap\":6000000,\"discount\":20}]."
    },
    "round": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "date": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 30
                },
                {
                  "type": "null"
                }
              ],
              "description": "Closing date, used as the note conversion date, e.g. 2026-06-30."
            },
            "name": {
              "anyOf": [
                {
                  "type": "string",
                  "maxLength": 40
                },
                {
                  "type": "null"
                }
              ],
              "description": "Round name, e.g. \"Series A\" (default \"Priced round\")."
            },
            "investors": {
              "anyOf": [
                {
                  "anyOf": [
                    {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 80
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "New investor name, e.g. \"Lead VC\"."
                          },
                          "amount": {
                            "type": [
                              "number",
                              "string",
                              "null"
                            ],
                            "description": "Amount invested in the round, e.g. 3000000."
                          }
                        },
                        "additionalProperties": {}
                      }
                    },
                    {
                      "type": "string"
                    }
                  ]
                },
                {
                  "type": "null"
                }
              ],
              "description": "Optional split of new money by investor, e.g. [{\"name\":\"Lead\",\"amount\":4000000},{\"name\":\"Angels\",\"amount\":1000000}]."
            },
            "new_money": {
              "type": [
                "number",
                "string",
                "null"
              ],
              "description": "New cash invested in the round, e.g. 5000000 or \"$5M\". Not counting SAFEs or notes converting."
            },
            "pre_money_valuation": {
              "type": [
                "number",
                "string",
                "null"
              ],
              "description": "Pre-money valuation of the priced round, e.g. 20000000 or \"$20M\". Includes the pool top-up and the conversions (standard term sheet convention)."
            },
            "target_pool_percent": {
              "type": [
                "number",
                "string",
                "null"
              ],
              "description": "Unallocated option pool target after the round, in percent of post-money fully diluted shares, e.g. 10. The top-up is in the pre-money (the pool shuffle)."
            },
            "post_money_valuation": {
              "type": [
                "number",
                "string",
                "null"
              ],
              "description": "Instead of pre_money_valuation: post-money valuation, e.g. 25000000 (pre = post - new money)."
            }
          },
          "additionalProperties": {}
        },
        {
          "type": "null"
        }
      ],
      "description": "The priced round. Leave out to see ownership with SAFEs converted at their caps only."
    },
    "safes": {
      "anyOf": [
        {
          "anyOf": [
            {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "mfn": {
                    "type": [
                      "boolean",
                      "string",
                      "null"
                    ],
                    "description": "true for an MFN SAFE: it takes the lowest cap and highest discount of SAFEs listed after it."
                  },
                  "name": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 80
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Investor or SAFE label, e.g. \"Angel SAFE\"."
                  },
                  "type": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 20
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "post (YC post-money SAFE, default) or pre (pre-money SAFE)."
                  },
                  "amount": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Investment (purchase amount), e.g. 500000 or \"$500k\"."
                  },
                  "discount": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Discount in percent, e.g. 20 for 20% (a YC \"discount rate\" of 80% is read as a 20% discount)."
                  },
                  "valuation_cap": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Valuation cap, e.g. 8000000 or \"$8M\". Post-money cap unless type is pre."
                  }
                },
                "additionalProperties": {}
              }
            },
            {
              "type": "string"
            }
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "SAFEs to convert, e.g. [{\"name\":\"Angels\",\"amount\":500000,\"valuation_cap\":8000000,\"discount\":20}] or text \"$500k at $8M post cap 20% discount; $250k MFN\"."
    },
    "holders": {
      "anyOf": [
        {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "kind": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 40
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "common (founders, employees; default), options (granted options), pool (unallocated option pool), preferred (prior priced rounds) or warrant. Guessed from the name when left out: a name with \"pool\" is the unallocated pool."
              },
              "name": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 80
                  },
                  {
                    "type": "null"
                  }
                ],
                "description": "Holder name, e.g. \"Alice (founder)\", \"Option pool\" or \"Seed investors\"."
              },
              "shares": {
                "type": [
                  "number",
                  "string",
                  "null"
                ],
                "description": "Shares or options held, fully diluted, e.g. 4000000 or \"4M\"."
              }
            },
            "additionalProperties": {}
          }
        },
        {
          "type": "string"
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {
            "type": [
              "number",
              "string"
            ]
          }
        }
      ],
      "description": "Current holders with shares, fully diluted, including granted options and the unallocated pool. Array, e.g. [{\"name\":\"Alice\",\"shares\":4500000},{\"name\":\"Bob\",\"shares\":4500000},{\"name\":\"Option pool\",\"shares\":1000000,\"kind\":\"pool\"}], or text \"Alice 4.5M; Bob 4.5M; Option pool 1M\"."
    },
    "currency": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 3
        },
        {
          "type": "null"
        }
      ],
      "description": "ISO currency code for labels, default USD, e.g. EUR."
    },
    "new_money": {
      "type": [
        "number",
        "string",
        "null"
      ],
      "description": "Shortcut for round.new_money, e.g. 5000000."
    },
    "company_name": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 80
        },
        {
          "type": "null"
        }
      ],
      "description": "Company name for the files, e.g. \"Acme Robotics\"."
    },
    "pre_money_valuation": {
      "type": [
        "number",
        "string",
        "null"
      ],
      "description": "Shortcut for round.pre_money_valuation, e.g. \"$20M\"."
    },
    "target_pool_percent": {
      "type": [
        "number",
        "string",
        "null"
      ],
      "description": "Shortcut for round.target_pool_percent, e.g. 10."
    }
  }
}
calculate_cap_table output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "summary",
    "price_per_share",
    "pre_money_valuation",
    "new_money",
    "post_money_valuation",
    "fully_diluted_before",
    "pre_money_fully_diluted",
    "fully_diluted_after",
    "option_pool_increase",
    "unallocated_pool_after_pct",
    "rows",
    "rows_total",
    "conversions",
    "conversions_total",
    "warnings",
    "assumptions",
    "disclaimer",
    "downloads"
  ],
  "properties": {
    "rows": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "kind",
          "shares_before",
          "pct_before",
          "shares_after",
          "pct_after",
          "change_pts"
        ],
        "properties": {
          "kind": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "pct_after": {
            "type": "number"
          },
          "change_pts": {
            "type": [
              "number",
              "null"
            ]
          },
          "pct_before": {
            "type": [
              "number",
              "null"
            ]
          },
          "shares_after": {
            "type": "number"
          },
          "shares_before": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "summary": {
      "type": "string"
    },
    "warnings": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "downloads": {
      "type": "object",
      "required": [
        "xlsx",
        "pdf"
      ],
      "properties": {
        "pdf": {
          "type": "string"
        },
        "xlsx": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "new_money": {
      "type": [
        "number",
        "null"
      ]
    },
    "disclaimer": {
      "type": "string"
    },
    "rows_total": {
      "type": "number"
    },
    "assumptions": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "conversions": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "type",
          "amount",
          "valuation_cap",
          "discount_pct",
          "cap_price",
          "discount_price",
          "conversion_price",
          "price_basis",
          "shares",
          "interest"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "shares": {
            "type": "number"
          },
          "interest": {
            "type": [
              "number",
              "null"
            ]
          },
          "cap_price": {
            "type": [
              "number",
              "null"
            ]
          },
          "price_basis": {
            "type": "string"
          },
          "discount_pct": {
            "type": [
              "number",
              "null"
            ]
          },
          "valuation_cap": {
            "type": [
              "number",
              "null"
            ]
          },
          "discount_price": {
            "type": [
              "number",
              "null"
            ]
          },
          "conversion_price": {
            "type": [
              "number",
              "null"
            ]
          }
        },
        "additionalProperties": false
      }
    },
    "price_per_share": {
      "type": [
        "number",
        "null"
      ]
    },
    "conversions_total": {
      "type": "number"
    },
    "fully_diluted_after": {
      "type": "number"
    },
    "pre_money_valuation": {
      "type": [
        "number",
        "null"
      ]
    },
    "fully_diluted_before": {
      "type": "number"
    },
    "option_pool_increase": {
      "type": "number"
    },
    "post_money_valuation": {
      "type": [
        "number",
        "null"
      ]
    },
    "pre_money_fully_diluted": {
      "type": [
        "number",
        "null"
      ]
    },
    "unallocated_pool_after_pct": {
      "type": [
        "number",
        "null"
      ]
    }
  },
  "additionalProperties": false
}
calculate_cap_table annotations
{
  "title": "Calculate cap table",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
calculate_safe_ownership — Calculate SAFE ownership
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use this when the user asks a SAFE calculator question such as how much of the company a SAFE buys: ownership = investment / post-money valuation cap for a YC post-money SAFE (or the pre-money SAFE equivalent), plus combined ownership with other SAFEs, the SAFE price and share count. Ownership is as converted at the caps, before any priced round. Does not model a priced round, notes or option pool top-ups; use calculate_cap_table for those. Not legal or tax advice.

calculate_safe_ownership input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "investment",
    "valuation_cap"
  ],
  "properties": {
    "safe_type": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 20
        },
        {
          "type": "null"
        }
      ],
      "description": "post (YC post-money SAFE, default) or pre (pre-money SAFE)."
    },
    "investment": {
      "type": [
        "number",
        "string"
      ],
      "description": "SAFE investment, e.g. 500000 or \"$500k\"."
    },
    "other_safes": {
      "anyOf": [
        {
          "anyOf": [
            {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "mfn": {
                    "type": [
                      "boolean",
                      "string",
                      "null"
                    ],
                    "description": "true for an MFN SAFE: it takes the lowest cap and highest discount of SAFEs listed after it."
                  },
                  "name": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 80
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Investor or SAFE label, e.g. \"Angel SAFE\"."
                  },
                  "type": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 20
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "post (YC post-money SAFE, default) or pre (pre-money SAFE)."
                  },
                  "amount": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Investment (purchase amount), e.g. 500000 or \"$500k\"."
                  },
                  "discount": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Discount in percent, e.g. 20 for 20% (a YC \"discount rate\" of 80% is read as a 20% discount)."
                  },
                  "valuation_cap": {
                    "type": [
                      "number",
                      "string",
                      "null"
                    ],
                    "description": "Valuation cap, e.g. 8000000 or \"$8M\". Post-money cap unless type is pre."
                  }
                },
                "additionalProperties": {}
              }
            },
            {
              "type": "string"
            }
          ]
        },
        {
          "type": "null"
        }
      ],
      "description": "Other SAFEs converting alongside it, e.g. [{\"amount\":250000,\"valuation_cap\":6000000}] or \"$250k at $6M cap\". Combined SAFE ownership is shown."
    },
    "valuation_cap": {
      "type": [
        "number",
        "string"
      ],
      "description": "Valuation cap, e.g. 10000000 or \"$10M\" (post-money cap unless safe_type is pre)."
    },
    "company_shares": {
      "type": [
        "number",
        "string",
        "null"
      ],
      "description": "Fully diluted shares before the SAFEs convert (founders, options, pool), e.g. 10000000. Used for share counts and the SAFE price; default 10,000,000."
    }
  }
}
calculate_safe_ownership output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "summary",
    "ownership_pct",
    "combined_safe_ownership_pct",
    "safe_price",
    "shares",
    "company_shares_before",
    "company_shares_after",
    "safes",
    "assumptions",
    "disclaimer"
  ],
  "properties": {
    "safes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "amount",
          "valuation_cap",
          "type",
          "ownership_pct",
          "safe_price",
          "shares"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "shares": {
            "type": "number"
          },
          "safe_price": {
            "type": "number"
          },
          "ownership_pct": {
            "type": "number"
          },
          "valuation_cap": {
            "type": "number"
          }
        },
        "additionalProperties": false
      }
    },
    "shares": {
      "type": "number"
    },
    "summary": {
      "type": "string"
    },
    "disclaimer": {
      "type": "string"
    },
    "safe_price": {
      "type": "number"
    },
    "assumptions": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "ownership_pct": {
      "type": "number"
    },
    "company_shares_after": {
      "type": "number"
    },
    "company_shares_before": {
      "type": "number"
    },
    "combined_safe_ownership_pct": {
      "type": "number"
    }
  },
  "additionalProperties": false
}
calculate_safe_ownership annotations
{
  "title": "Calculate SAFE ownership",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

1 advertised

cap-table-widget — Zovo Cap Table Calculator view

Advertised by the server during the last successful anonymous check.

Interactive view for Zovo Cap Table Calculator.

cap-table-widget URI
ui://widget/cap-table-v1-1.0.0-24e61d34b6f9195c860f578115ea449abe8591b5a22e6c13618d8619c4efa111.html

MIME type: text/html;profile=mcp-app

cap-table-widget-legacy — Zovo Cap Table Calculator view (previous versions)

Advertised by the server during the last successful anonymous check.

cap-table-widget-legacy URI template
ui://widget/cap-table-{version}.html

MIME type: text/html;profile=mcp-app

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
1212 ms
95th percentile latency
1212 ms

Maintenance history

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

  • · probe · passed · 1212 ms · metadata changed · 2 tool(s), 1 resource(s), 1 resource template(s)

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 zovo-cap-table-calculator-mcp https://cap-table.zovo.one/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 zovo-cap-table-calculator-mcp --url https://cap-table.zovo.one/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable zovo-cap-table-calculator-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "zovo-cap-table-calculator-mcp": {
      "url": "https://cap-table.zovo.one/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "zovo-cap-table-calculator-mcp": {
      "type": "streamableHttp",
      "url": "https://cap-table.zovo.one/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start zovo-cap-table-calculator-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "zovo-cap-table-calculator-mcp": {
      "type": "http",
      "url": "https://cap-table.zovo.one/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 zovo-cap-table-calculator-mcp https://cap-table.zovo.one/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://cap-table.zovo.one/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": {
    "zovo-cap-table-calculator-mcp": {
      "serverUrl": "https://cap-table.zovo.one/mcp"
    }
  }
}

Let your agent find its tools

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