# Proadcast for AI chats: find a product for what someone needs > Ask Proadcast for products in one sentence; it answers with listed products and links the person opens. No token, no sign-in for the search. Connect: `claude mcp add --transport http proadcast https://proadcast.ing/api/mcp`, then ask, e.g. "find a product that summarizes my meeting notes". Tool `find_products` {need: one sentence, at most 300 characters} returns `{products: [{name, description, open_url}], note?}`: up to 5, best match first, the same ranking as https://proadcast.ing/results. Show the `open_url` links; the person signs in once and Proadcast hands their need to the product. Up to 30 searches a minute. # Proadcast for makers: register a product with an agent > Proadcast lists products that open over MCP. A seeker describes a need, sees listed products, and "Open" sends them to your open URL with their need. This page is all an agent needs; it is also the MCP resource `proadcast://guides/provider`. ## Auth The owner signs in at https://proadcast.ing/settings, creates an agent token with **provider:write** ticked, and hands you the `pdc_…` token. Send `Authorization: Bearer pdc_…` to the MCP endpoint. Without that scope the provider tools are not listed; with only that scope, only they are. One product per account. ## Endpoint and tools MCP over streamable HTTP: `https://proadcast.ing/api/mcp`. Results are compact JSON; errors are JSON with `isError`. Every product response carries its `id`. A failed check carries `reason`, `status` when one came back, and a one-line `fix`. Claude Code: `claude mcp add --transport http proadcast https://proadcast.ing/api/mcp --header "Authorization: Bearer pdc_…"`. Without an MCP client, POST one JSON-RPC call (stateless, no session needed): `curl -sS https://proadcast.ing/api/mcp -H "Authorization: Bearer pdc_…" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_my_product","arguments":{}}}'` | Tool | Input | Returns | | --- | --- | --- | | check_connection | mcp_url, open_url, health_url? | {checks}: dry run, saves nothing | | register_product | name, mcp_url, open_url, health_url?, description?, categories?, replace? | {id, status, checks, on_air, tools_read (count), next} | | get_my_product | none | {id, name, mcp_url, open_url, health_url, description, categories, tools, status, checks, liveness, last_checked_at, last_failure} | | update_my_product | any register field | {saved, checks?, product}; only fields you pass change | | refresh_tools | none | {read (true if tools/list answered), tools} | | list_categories | query? | no query: {groups, hint}; query: [{slug, name, group}], at most 30 | | delete_my_product | confirm: true | {deleted: true} | ## Flow 1. `check_connection`; fix every check with `ok: false` (reasons below). 2. `register_product`; read `status` and `checks`. A product is saved even when checks fail (`status: "failed"`, not listed). 3. Fix, then `update_my_product` with the new URLs. New URLs are saved only if every check passes (`saved: false` otherwise); a description or categories sent with them are saved either way. `replace: true` without categories keeps the old ones. 4. Add a description (at most 500 characters) and up to 3 category slugs from `list_categories`. 5. Implement the handoff below. `status: "held"`: saved, not listed until an admin approves (wording the screen is unsure of, reports, or an earlier product of the account that was held or reported); nothing to do, and it can't be deleted meanwhile. `status: "blocked"`: removed by Proadcast (`block_reason`); it can't be changed. `status: "passed"` means listed. It does not mean on air: `on_air` (register_product) is true only while it is listed and `liveness` (get_my_product) is `on_air`, i.e. the health check passes now. Proadcast checks every 30 minutes; with no check for 2 hours liveness is `unknown`. ## Checks - `mcp_handshake`: POST a JSON-RPC `initialize` to mcp_url; 2xx JSON or SSE holding a `result`, within 5 s, no redirect. - `open_url`: GET open_url; 2xx or 3xx within 5 s, up to 3 redirects. - `health`: GET health_url, or open_url when blank; 2xx within 5 s, redirects must stay on the open URL's site. Reported only for a health_url, or when it fails while `open_url` passed. - `tools_list`: one `tools/list` read (never `tools/call`); best effort, never blocks. Every URL: https, a host name (no IP), no user:password, resolving to public addresses only. health_url must share open_url's registrable domain. `check_connection`, `register_product`, URL changes and `refresh_tools` share a limit of 10 an hour. ## Reason codes | reason | Fix | | --- | --- | | not_https, invalid_url | Use a full https:// URL with a host name and no credentials. | | dns | The host name does not resolve publicly. | | blocked_address | The host resolves to a private or reserved address; serve it publicly. | | timeout, network | Nothing answered within 5 s, or the connection failed. | | http_3xx, http_4xx, http_5xx | Wrong status (`status` has it). The MCP endpoint must not redirect or require auth for initialize. | | redirect_limit, redirect_other_site | Too many redirects, or one left the open URL's site. | | not_json, no_result, rpc_error | initialize must answer JSON-RPC (JSON or SSE) with a `result`, not an `error`. | ## Errors `{"error":"validation","field","code","fix"}`; a prohibited-content refusal adds `reasons:[{field,code,match}]`, codes `kw_adult|kw_gambling|kw_drugs|kw_weapons|kw_scam|kw_illegal_service|domain_tld|domain_keyword` · `{"error":"forbidden","code":"removed","reason"}` · `{"error":"forbidden","code":"under_review","fix"}` (delete of a held product) · `{"error":"conflict","code":"already_registered","id"}` (pass `replace: true` to replace it) · `{"error":"rate_limited","retry_after_s"}` · `{"error":"not_found","fix"}` (no product yet: call `register_product`) · `{"error":"unauthenticated"}`. ## Handoff: read the seeker's need A seeker who opens your product lands on `?need=&proadcast_token=`. From your server (never the browser), read the need: `curl -sS "https://proadcast.ing/api/handoff/need?token=$PROADCAST_TOKEN"` - 200: `{"need":{"id","feature","content"},"providerId","expiresAt"}`. Check `providerId` is your product's `id`. - 401 `invalid_token`: bad or expired (24 h); don't retry. 404 `not_found`: the need is gone or you are no longer listed. 503 `unavailable`: handoff reads are not switched on yet; retry later (the `need` id still arrives). Keep the token out of logs and out of the `Referer` your page sends. The owner's https://proadcast.ing/provide page shows the last 30 days: times shown and opened, the needs that opened the product, and the keywords that matched the rest. ## Rules One product per account. No adult content, gambling, drugs, weapons, scams or illegal services: names, descriptions, tools and URLs are screened on every change, and such products are refused or removed. Describe the product truthfully. ## Q&A: answer what users ask Each product gets about 100 questions users ask (a question bank picked by its categories). Answered ones become a public page, `https://proadcast.ing/product///qa`, indexed once 10 or more are answered. The rest tell the maker what to improve. | Tool | Input | Returns | | --- | --- | --- | | get_qa_questions | status? (default pending), limit? (≤25), cursor? | {questions:[{id,q}], left, next_cursor?, rule?} | | answer_qa | answers:[{id, status, answer?, evidence_url?}] (≤25) | {saved, pending, rejected:[{id,reason,fix}], held?} | | add_qa_question | q (5-200 chars; 20 at most) | {id} | | get_qa_gaps | none | {unknown:[{id,q}], not_supported:[{id,q,a?}]} | Flow, after `register_product`: call `get_qa_questions`, answer the batch with `answer_qa`, repeat until `questions` is empty; then `get_qa_gaps` and report the gaps to the maker as improvement ideas. - Answer only from the product's code, docs and site; never invent. `answered` needs an answer (≤1200 chars, plain text or light markdown: paragraphs, `- ` lists, **bold**, `code`). Not sure: `unknown`. The product can't: `not_supported`. - Answers are screened like listings: a prohibited question or evidence URL is rejected (`reason: "prohibited"`); an answer that matches the screen (even "we don't allow gambling") is saved `held`, not public until an admin approves. The maker can hide, edit or send back any item at /provide; an item the maker edited rejects your answer (`maker_edited`) until they ask for a re-answer. `answer_qa` and `add_qa_question` share 60 calls an hour.