← WebMCP Directory

Tool tree

tv.fangorn.network

Media & PersonalTools verified
Website
SOND3R
Explore capabilities
    search-catalogAnswer

    Semantically search this storefront — titles, descriptions and subtitle lines across every publisher in the current view. Also shows the results on the page.

    View tool JSON
    {
      "name": "search-catalog",
      "kind": "answer",
      "impl": "imperative",
      "description": "Semantically search this storefront — titles, descriptions and subtitle lines across every publisher in the current view. Also shows the results on the page.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "What to look for, in natural language"
          },
          "limit": {
            "type": "number",
            "description": "Max files to return (default 10)"
          }
        },
        "required": [
          "query"
        ]
      }
    }
    find-lineAnswer

    Find where words are actually SPOKEN, across every subtitle in this view — the exact-phrase counterpart to search-catalog, which ranks whole files by topic and therefore cannot find a phrase said once. Give it phrases; it returns the lines containing them, with the timestamps to cut. Use it to build a supercut that says something the corpus never meant to say.

    View tool JSON
    {
      "name": "find-line",
      "kind": "answer",
      "impl": "imperative",
      "description": "Find where words are actually SPOKEN, across every subtitle in this view — the exact-phrase counterpart to search-catalog, which ranks whole files by topic and therefore cannot find a phrase said once. Give it phrases; it returns the lines containing them, with the timestamps to cut. Use it to build a supercut that says something the corpus never meant to say.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "phrases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The words to find, each matched intact and on word boundaries"
          },
          "per": {
            "type": "number",
            "description": "Best matches per phrase, 1–10, default 4"
          }
        },
        "required": [
          "phrases"
        ]
      }
    }
    browse-catalogAction

    List what this storefront holds, without searching. Filter by publisher address or media kind.

    View tool JSON
    {
      "name": "browse-catalog",
      "kind": "act",
      "impl": "imperative",
      "description": "List what this storefront holds, without searching. Filter by publisher address or media kind.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "publisher": {
            "type": "string",
            "description": "Only this publisher's wallet address"
          },
          "kind": {
            "type": "string",
            "description": "video, audio, image, text, software…"
          },
          "limit": {
            "type": "number",
            "description": "Max files to return (default 50)"
          }
        }
      }
    }
    open-itemAction

    Open one file's page in the storefront — its description, price and, for a paid file, the buy button the person presses themselves. Free files start playing.

    View tool JSON
    {
      "name": "open-item",
      "kind": "act",
      "impl": "imperative",
      "description": "Open one file's page in the storefront — its description, price and, for a paid file, the buy button the person presses themselves. Free files start playing.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "An id from search-catalog or browse-catalog"
          }
        },
        "required": [
          "id"
        ]
      }
    }
    list-channelsAnswer

    Every channel on this TV and what is playing on each right now, with what is up next. Channels marked `tuned:true` were generated from a natural-language query rather than grouped out of the catalog.

    View tool JSON
    {
      "name": "list-channels",
      "kind": "answer",
      "impl": "imperative",
      "description": "Every channel on this TV and what is playing on each right now, with what is up next. Channels marked `tuned:true` were generated from a natural-language query rather than grouped out of the catalog.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    tune-channelAction

    Make a brand-new television channel and turn the set to it. Three kinds of evidence, mixable: a mood in words ('rainy cyberpunk', 'slow nature documentary'), `blend` — how far to pull toward where THIS viewer's session is already heading, from read-taste — and specific items to move toward or away from. A channel built with blend or like/unlike is derived from behaviour that exists only in this browser, so it cannot be produced anywhere else. Returns a link that puts anyone else on the exact same frame.

    View tool JSON
    {
      "name": "tune-channel",
      "kind": "act",
      "impl": "imperative",
      "description": "Make a brand-new television channel and turn the set to it. Three kinds of evidence, mixable: a mood in words ('rainy cyberpunk', 'slow nature documentary'), `blend` — how far to pull toward where THIS viewer's session is already heading, from read-taste — and specific items to move toward or away from. A channel built with blend or like/unlike is derived from behaviour that exists only in this browser, so it cannot be produced anywhere else. Returns a link that puts anyone else on the exact same frame.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "prompt": {
            "type": "string",
            "description": "The mood or theme, in natural language"
          },
          "blend": {
            "type": "number",
            "description": "0–1: how much of the viewer's own heading (read-taste) to mix in. 0 = the words alone, 1 = purely where they are already going."
          },
          "like": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Item ids to pull the channel toward"
          },
          "unlike": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Item ids to push the channel away from"
          },
          "title": {
            "type": "string",
            "description": "What to call it, when the channel is not just a prompt"
          },
          "scenes": {
            "type": "boolean",
            "description": "Build the channel out of MOMENTS instead of whole files. A 'firetrucks' channel with scenes:false is every film that mentions one; with scenes:true it is the ~45 seconds in each film where one is actually on screen. Needs a corpus with subtitle, scene or summary rows — say so if the channel comes back empty."
          }
        }
      }
    }
    watch-channelAction

    Turn the TV to an existing channel, by number or by name.

    View tool JSON
    {
      "name": "watch-channel",
      "kind": "act",
      "impl": "imperative",
      "description": "Turn the TV to an existing channel, by number or by name.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "description": "A channel number or title from list-channels"
          }
        },
        "required": [
          "channel"
        ]
      }
    }
    channel-scheduleAnswer

    What is coming up on a channel — the running order for the next few hours, computed from the clock alone. Works for any channel, whether or not it is the one on screen.

    View tool JSON
    {
      "name": "channel-schedule",
      "kind": "answer",
      "impl": "imperative",
      "description": "What is coming up on a channel — the running order for the next few hours, computed from the clock alone. Works for any channel, whether or not it is the one on screen.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "description": "Channel number or title (default: what is on screen)"
          },
          "hours": {
            "type": "number",
            "description": "How far ahead to look (default 3)"
          }
        }
      }
    }
    share-channelAction

    Get the shareable link for any channel, and optionally keep a tuned one in this browser's channel list. Anyone who opens the link watches in sync — the schedule is a pure function of UTC, so there is nothing to synchronise.

    View tool JSON
    {
      "name": "share-channel",
      "kind": "act",
      "impl": "imperative",
      "description": "Get the shareable link for any channel, and optionally keep a tuned one in this browser's channel list. Anyone who opens the link watches in sync — the schedule is a pure function of UTC, so there is nothing to synchronise.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "description": "Channel number or title (default: what is on screen)"
          },
          "save": {
            "type": "boolean",
            "description": "Also keep it in this browser's channel list"
          }
        }
      }
    }
    read-tasteAnswer

    What this viewer is actually into, right now — derived in the browser from what they have opened, rated and sat through, and never sent anywhere. Returns their heading in words, how fast it is moving, what they have rejected, and the items nearest to where they are going next. This is the signal that makes a channel personal; feed it back through tune-channel's `blend`.

    View tool JSON
    {
      "name": "read-taste",
      "kind": "answer",
      "impl": "imperative",
      "description": "What this viewer is actually into, right now — derived in the browser from what they have opened, rated and sat through, and never sent anywhere. Returns their heading in words, how fast it is moving, what they have rejected, and the items nearest to where they are going next. This is the signal that makes a channel personal; feed it back through tune-channel's `blend`.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    await-viewer-signalAction

    Wait until the viewer DOES something, and return what it was. Blocks — this is a subscription, not a poll. Signals: `skip` (left a slot early — the strongest negative this surface produces), `finished` (sat through one), `like`/`dislike` (rated it), `channel`, `tuned`. Returns null if nothing happens before the timeout, which means they are still watching and is not an error. Call it again with `after` set to the last `seq` you saw to avoid missing anything in between.

    View tool JSON
    {
      "name": "await-viewer-signal",
      "kind": "act",
      "impl": "imperative",
      "description": "Wait until the viewer DOES something, and return what it was. Blocks — this is a subscription, not a poll. Signals: `skip` (left a slot early — the strongest negative this surface produces), `finished` (sat through one), `like`/`dislike` (rated it), `channel`, `tuned`. Returns null if nothing happens before the timeout, which means they are still watching and is not an error. Call it again with `after` set to the last `seq` you saw to avoid missing anything in between.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "seconds": {
            "type": "number",
            "description": "How long to wait before giving up (default 45, max 120)"
          },
          "after": {
            "type": "number",
            "description": "Only signals newer than this `seq`"
          }
        }
      }
    }
    proposeAction

    Ask the viewer something on the screen they are already looking at. A card appears over the TV with your question and your buttons. Use it before doing anything they did not ask for: retuning what they are watching, saving a channel, changing direction. This is the consent step WebMCP has no primitive for, and it only works because the tools are running in the page the person is looking at. Three outcomes, and they are NOT interchangeable: an `answer` is a decision; `answer: null` with `settled: true` means dismissed or expired, which is a NO; and `pending: true` means the card is still on screen and they have not answered yet — that is not a no, and acting on it as one discards a decision they are still making. When you get a `ticket`, call this tool again with it (and nothing else) to keep waiting. The card outlives any single call, so a slow yes is never lost.

    View tool JSON
    {
      "name": "propose",
      "kind": "act",
      "impl": "imperative",
      "description": "Ask the viewer something on the screen they are already looking at. A card appears over the TV with your question and your buttons. Use it before doing anything they did not ask for: retuning what they are watching, saving a channel, changing direction. This is the consent step WebMCP has no primitive for, and it only works because the tools are running in the page the person is looking at.\n\nThree outcomes, and they are NOT interchangeable: an `answer` is a decision; `answer: null` with `settled: true` means dismissed or expired, which is a NO; and `pending: true` means the card is still on screen and they have not answered yet — that is not a no, and acting on it as one discards a decision they are still making. When you get a `ticket`, call this tool again with it (and nothing else) to keep waiting. The card outlives any single call, so a slow yes is never lost.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "description": "Short, answerable by pressing a button. Say what you would do and why."
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The buttons (default Yes / No). Keep them to two or three."
          },
          "seconds": {
            "type": "number",
            "description": "How long the card STANDS on screen before it expires (default 60, max 300)"
          },
          "wait": {
            "type": "number",
            "description": "How long THIS call blocks before handing back a ticket (default 45, max 110). Keep it under your transport's timeout."
          },
          "ticket": {
            "type": "string",
            "description": "Resume waiting on a card you already posted, from a previous `pending` reply. Send this alone."
          }
        }
      }
    }
    player-stateAnswer

    What is playing in this tab right now, and where the playhead is.

    View tool JSON
    {
      "name": "player-state",
      "kind": "answer",
      "impl": "imperative",
      "description": "What is playing in this tab right now, and where the playhead is.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      }
    }
    control-playerAction

    Drive the open player: play, pause, or jump to a timestamp.

    View tool JSON
    {
      "name": "control-player",
      "kind": "act",
      "impl": "imperative",
      "description": "Drive the open player: play, pause, or jump to a timestamp.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "play",
              "pause",
              "seek"
            ]
          },
          "seconds": {
            "type": "number",
            "description": "Playhead position, for seek"
          }
        },
        "required": [
          "action"
        ]
      }
    }
    capture-frameAction

    Look at the video: the frame at a given timestamp (or the current one), returned as an image. Reads the exact frame — off the canvas where the file allows it, otherwise through the relay, which seeks the remote file by range request and so is not bound by the browser's cross-origin rules. Falls back to the archive's own coarse frame strip only where neither is available.

    View tool JSON
    {
      "name": "capture-frame",
      "kind": "act",
      "impl": "imperative",
      "description": "Look at the video: the frame at a given timestamp (or the current one), returned as an image. Reads the exact frame — off the canvas where the file allows it, otherwise through the relay, which seeks the remote file by range request and so is not bound by the browser's cross-origin rules. Falls back to the archive's own coarse frame strip only where neither is available.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "at": {
            "type": "number",
            "description": "Seconds to seek to first; omit for the current frame"
          },
          "width": {
            "type": "number",
            "description": "Downscale to this width, default 640"
          }
        }
      }
    }
    annotateAction

    Draw on the open player: bookmarks on its timeline (the person can click one to jump there) and boxes over the picture for a stretch of time. Replaces whatever was drawn before; call with nothing to clear.

    View tool JSON
    {
      "name": "annotate",
      "kind": "act",
      "impl": "imperative",
      "description": "Draw on the open player: bookmarks on its timeline (the person can click one to jump there) and boxes over the picture for a stretch of time. Replaces whatever was drawn before; call with nothing to clear.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "marks": {
            "type": "array",
            "description": "Bookmarks on the timeline",
            "items": {
              "type": "object",
              "properties": {
                "at": {
                  "type": "number",
                  "description": "Seconds"
                },
                "label": {
                  "type": "string"
                }
              },
              "required": [
                "at",
                "label"
              ]
            }
          },
          "boxes": {
            "type": "array",
            "description": "Boxes over the picture, in 0–1 fractions of the frame",
            "items": {
              "type": "object",
              "properties": {
                "at": {
                  "type": "number"
                },
                "until": {
                  "type": "number",
                  "description": "Seconds; defaults to at + 3"
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                },
                "w": {
                  "type": "number"
                },
                "h": {
                  "type": "number"
                },
                "label": {
                  "type": "string"
                }
              },
              "required": [
                "at",
                "x",
                "y",
                "w",
                "h"
              ]
            }
          }
        }
      }
    }
    scan-filmAction

    Flip through a film without watching it: frames spread across its running time (or across a range), in ONE call, as a single contact sheet with each tile stamped with its time. Costs a couple of kilobytes per frame — the way to check what a film actually contains before spending an hour on it. Frames are the exact ones at those timestamps where a relay can read them, so tightening `from`/`to` really does look closer; without one it falls back to the archive's published strip, whose cadence is fixed and sometimes only a frame or two per episode.

    View tool JSON
    {
      "name": "scan-film",
      "kind": "act",
      "impl": "imperative",
      "description": "Flip through a film without watching it: frames spread across its running time (or across a range), in ONE call, as a single contact sheet with each tile stamped with its time. Costs a couple of kilobytes per frame — the way to check what a film actually contains before spending an hour on it. Frames are the exact ones at those timestamps where a relay can read them, so tightening `from`/`to` really does look closer; without one it falls back to the archive's published strip, whose cadence is fixed and sometimes only a frame or two per episode.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "A file id; omit for whatever is open"
          },
          "from": {
            "type": "number",
            "description": "Start of the range in seconds, default 0"
          },
          "to": {
            "type": "number",
            "description": "End of the range in seconds, default the whole film"
          },
          "count": {
            "type": "number",
            "description": "How many frames, 2–12, default 8"
          }
        }
      }
    }
    describe-scenesAnswer

    Write down what happens in a film, at timestamps — the thing the catalog does not know. Scan it with scan-film or capture-frame first, then describe what you actually saw: subject, action, shot, setting. Each description becomes a searchable moment that lands the next person on that exact second, so write for a stranger's query ('a man lights a cigarette in the rain'), not as a caption. Stages a draft for the person to review and publish; call it again after a closer pass and the better description wins.

    View tool JSON
    {
      "name": "describe-scenes",
      "kind": "answer",
      "impl": "imperative",
      "description": "Write down what happens in a film, at timestamps — the thing the catalog does not know. Scan it with scan-film or capture-frame first, then describe what you actually saw: subject, action, shot, setting. Each description becomes a searchable moment that lands the next person on that exact second, so write for a stranger's query ('a man lights a cigarette in the rain'), not as a caption. Stages a draft for the person to review and publish; call it again after a closer pass and the better description wins.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "A file id; omit for whatever is open"
          },
          "scenes": {
            "type": "array",
            "description": "What happens, and when",
            "items": {
              "type": "object",
              "properties": {
                "start": {
                  "type": "number",
                  "description": "Seconds into the film"
                },
                "end": {
                  "type": "number",
                  "description": "Seconds; defaults to start"
                },
                "text": {
                  "type": "string",
                  "description": "What is on screen, in a sentence or two"
                }
              },
              "required": [
                "start",
                "text"
              ]
            }
          },
          "summary": {
            "type": "string",
            "description": "One line about the film as a whole, if you have one"
          }
        },
        "required": [
          "scenes"
        ]
      }
    }
    program-channelAction

    Put an ORDERED run of clips on the television, as a channel. Takes the same `shots` as montage — but instead of rendering a file, it becomes a channel the set turns to, each slot a window the player seeks into. Use it when the order is the point: a channel where clip two answers clip one is a programme, while the same clips shuffled are only a subject. The ring is data, so it keeps playing on the clock for a viewer with no agent, long after this conversation ends.

    View tool JSON
    {
      "name": "program-channel",
      "kind": "act",
      "impl": "imperative",
      "description": "Put an ORDERED run of clips on the television, as a channel. Takes the same `shots` as montage — but instead of rendering a file, it becomes a channel the set turns to, each slot a window the player seeks into. Use it when the order is the point: a channel where clip two answers clip one is a programme, while the same clips shuffled are only a subject. The ring is data, so it keeps playing on the clock for a viewer with no agent, long after this conversation ends.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "shots": {
            "type": "array",
            "description": "The clips, in the order they should play",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "A file id; omit for whatever is open"
                },
                "start": {
                  "type": "number",
                  "description": "Seconds into the film"
                },
                "dur": {
                  "type": "number",
                  "description": "Seconds to take, default 5"
                },
                "note": {
                  "type": "string",
                  "description": "What this clip is — printed on its cell in the guide"
                }
              },
              "required": [
                "start"
              ]
            }
          },
          "title": {
            "type": "string",
            "description": "What to call the channel"
          }
        },
        "required": [
          "shots"
        ]
      }
    }
    montageAction

    Turn shots you picked into an edit list — to render here, or to hand to software off this machine. Resolves each file to the URL its bytes actually live at and checks the numbers, so a bad supercut fails here, in one call, instead of after three features have been fetched. `format` decides who the list is for: `json` for `node scripts/cut.mjs <list>.json out.mp4`, `edl` or `otio` for an editor — Blender, Resolve, Premiere and Nuke all import one of those, and an OTIO clip carries the source URL, so the timeline resolves with nothing downloaded. Hand the text straight to whatever desktop tool you also have open. Marks the open film's shots on its timeline so the person can see the cut before it is rendered.

    View tool JSON
    {
      "name": "montage",
      "kind": "act",
      "impl": "imperative",
      "description": "Turn shots you picked into an edit list — to render here, or to hand to software off this machine. Resolves each file to the URL its bytes actually live at and checks the numbers, so a bad supercut fails here, in one call, instead of after three features have been fetched. `format` decides who the list is for: `json` for `node scripts/cut.mjs <list>.json out.mp4`, `edl` or `otio` for an editor — Blender, Resolve, Premiere and Nuke all import one of those, and an OTIO clip carries the source URL, so the timeline resolves with nothing downloaded. Hand the text straight to whatever desktop tool you also have open. Marks the open film's shots on its timeline so the person can see the cut before it is rendered.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "shots": {
            "type": "array",
            "description": "The cuts, in the order they should play",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "A file id; omit for whatever is open"
                },
                "start": {
                  "type": "number",
                  "description": "Seconds into the film"
                },
                "dur": {
                  "type": "number",
                  "description": "Seconds to take, default 5"
                },
                "note": {
                  "type": "string",
                  "description": "What this shot is, for the person reviewing it"
                }
              },
              "required": [
                "start"
              ]
            }
          },
          "format": {
            "type": "string",
            "enum": [
              "json",
              "edl",
              "otio"
            ],
            "description": "Who the list is for. `json` (default) renders with scripts/cut.mjs. `edl` is CMX3600, which every NLE imports. `otio` is OpenTimelineIO — JSON, and each clip carries its source URL, so it is the one to hand another tool or an agent."
          },
          "title": {
            "type": "string",
            "description": "What to call the timeline, for edl/otio"
          }
        },
        "required": [
          "shots"
        ]
      }
    }