Skip to content

plug v0.9.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 18:30
· 104 commits to main since this release
e80cde5

Added

  • Activity rows open. Click a call to see the tool, the server, the client,
    when it ran, how long it took, and whether it worked. A failed call says
    why, in the error's own words, and what to do next. The reason is kept for
    calls made after this update, cut to 240 characters.

  • Add Server starts from a list. Pick Notion, Linear, Atlassian, Asana,
    Sentry, Stripe, Vercel, Cloudflare, Canva, Intercom, or Context7 and Plug
    fills in the rest and asks you to sign in; a server Plug already has is not
    offered again. Pasting a setup block, a command, or an address still works,
    one step below the list.

  • A server's key can live in the Keychain instead of in config.toml.
    plug secret set <name> asks for the value without showing it, or takes it
    from a pipe, and stores it; the server then says keychain:<name> where the
    key used to be, as its bearer token or as the value of one of its env
    entries. Only the service reads the value, when it starts that server. A
    server whose secret is missing says so in plug status and the others start
    as usual. plug secret rm <name> removes one.

  • A server's key can also come from 1Password, from Plug's .env file, or
    from any other password manager. op://vault/item/field asks the 1Password
    command-line tool; file:<name> reads the .env file, and
    plug secret set --store file <name> writes it. Any other tool is three
    lines under [secrets.stores.<id>]: a command with {name} where the
    secret's name goes, and <id>:<name> runs it. A store that locks after a
    server started does not stop that server: Plug keeps the value it read, in
    memory only, and uses it until the store answers again.

  • Skills served over MCP keep their server's name. A skill:// resource
    from a server reaches every client as skill://<server>/…, in the
    resource list, in reads, in update notices, and in tool results, so two
    servers with a skill of the same name no longer collide and a client can
    tell where a skill came from. A skill file that is not listed is read
    through its server's name, and a URI written without the name still works
    when one server serves it.

  • A key typed into Plug goes to the Keychain on its own. Adding or editing a
    server in the app or with plug server add stores its token, and any env
    entry whose name says it is a credential, in the Keychain and writes
    keychain:<server>.<field> to config.toml. Removing the server, or the
    token, removes the stored value. A machine with no credential store keeps
    the key in the file as before.

  • plug doctor and the app's checkup name the keys still written in
    config.toml, and plug secret move moves them all to the Keychain.

  • Plug can watch a tool and tell a client when its result changes. Add an
    [[events.watch]] entry naming a server, a tool, and how often to check, and
    the event <server>.<name> appears to remote clients that support MCP
    Events. Plug only watches tools their server marks read-only unless the
    watch says allow_writes = true, sends nothing for the first result, and
    keeps a client away from the events of a server it is kept from. See
    docs/events.md.

  • plug events lists every watch with when it was last checked, when it last
    changed, and how many clients listen. plug events watch <server> <tool>
    adds one and says at once when the tool does not exist or is not read-only;
    plug events unwatch <event> removes it.

  • The app has an Events tab. It lists every event with how it is doing in one
    sentence and how many clients listen. Watch a Tool asks for a server, a
    tool, and how often to check; it offers only the tools the server marks
    read-only unless you ask for the rest, and Stop Watching removes a watch.

  • The app has a first-run guide. On a Mac with no servers it opens by itself
    once; after that the question mark in the toolbar opens it. It shows Plug's
    two sides in one picture and walks three steps, add a server, connect a
    client, use a tool, each with the button that does it and a tick when it is
    done. Copy Setup Prompt puts instructions on the clipboard that an agent can
    follow to set Plug up; the same text is docs/guides/agent-setup.md.

  • A server can have a second account. plug server add-account <server> <account> and Add Another Account in a server's menu add the same server
    again as <server>-<account>, with the same settings. An OAuth server's
    copy starts signed out and signs in with the other account; any other copy
    keeps the same credentials until you edit it. Tool groups carry the account
    in their name, so Gmail and GmailPersonal sit side by side.

  • The Clients tab chooses which servers each client can use. Every client that
    uses Plug has a button that opens its servers with a switch each, and a
    client kept from something says so in its row. The popover says plainly that
    for a client on this Mac this keeps the list short and is not a lock, while a
    remote client is held to it.

  • A client kept from a server stops hearing that server's resource updates,
    even for a subscription it made before the block. Lifting the block brings
    them back.

  • A client kept from a server is kept from all of it. Its resources, resource
    templates, and prompts leave that client's lists, and reading one, getting
    one, completing against one, or subscribing to one answers as if it did not
    exist. Before, a block covered the server's tools only.

  • Pi, Warp, and Kiro are clients. plug link pi, plug link warp, and
    plug link kiro write each one's own MCP file, the Clients tab lists them,
    and plug import reads servers from them.

  • GitHub Copilot CLI is a client. plug link copilot-cli and the Clients tab
    write ~/.copilot/mcp-config.json with the type and tools fields Copilot
    CLI requires, and plug import copilot-cli reads servers from it.

  • Every request knows which client sent it. plug connect --client <target>
    says which link started the connector, so a client is placed by how it was
    linked rather than by the name it reports; a remote request is placed by its
    grant, and requests on the shared token share one key. Nothing acts on the
    key yet: it is the ground per-client access stands on.

  • plug link and the Clients tab write connect --client <target> into a
    local link, so a client whose own name Plug does not recognise (Pi, Warp,
    Kiro, Kilo Code) shows under its real name and icon. Links written before
    this keep working unchanged; link the client again to pick it up.

  • A client can be kept from a server or from single tools. Under
    [clients."<key>"] in the config, blocked_servers = ["slack"] and
    blocked_tools = ["github__delete_*"] take those tools out of that client's
    list and make a call to one answer as an unknown tool, by any route: a
    direct call, a task, tool search, or the invoke wrapper. The key is the one
    plug clients -v shows. A change applies on config reload, and connected
    clients are told their tool list changed. For a local client this keeps a
    tidy tool list, it is not a security boundary: any program running as you
    can link itself under another name. For a remote client the key is its
    verified grant.

  • plug clients block <client> --server <name> and --tool <name> keep a
    client from a server or a tool, and plug clients unblock lets it back in.
    The client is picked as in plug clients rename: by the name it shows
    under, or by its key. It applies at once, without a reload, and
    plug clients lists who is kept from what.

  • An unknown local client started by an interpreter is told apart by the script
    it runs. Two tools that both run under python3 or node are now two
    clients, each with its own name. A name given to such a client before this
    change no longer applies; rename it once more.

  • A remote session knows the grant it came in on. Clients names a remote
    client Plug does not recognise after that grant, shows the matching app's
    icon when the Mac has one, and lets it be renamed from its own row; the name
    is stored under the grant, so it follows the client across sessions.
    plug clients -v lists the session's key as oauth:<client id>.

  • A client can be renamed. Clients has a pencil on every remote client and on
    every local client Plug can tell apart, and plug clients rename <client> "<name>" does the same; an empty name goes back to the one Plug works out.
    The name is kept in [clients."<key>"] in the config, under the client's
    target, the program that started it, or its grant, never under the name it
    reports. plug clients -v lists each key.

  • A local client Plug does not recognise is named after the program that
    started it. plug connect reads its parent from the process table, looking
    past shells and launchers, and reports it when it registers; Clients shows
    that app's name and icon in place of "Unidentified local client", and
    plug clients lists it under that name. A client cannot choose this name,
    unlike the one it sends in initialize.

  • Opt-in Slack event delivery. With [http.slack_events] configured, Plug
    receives Slack's Events API at /events/slack, keeps coworker mentions of one
    Slack user and replies in those threads across public channels, and delivers
    each as slack.ditto_message to one chosen downstream OAuth client through
    modern MCP Events (events/list, events/subscribe, events/unsubscribe,
    scope events:subscribe). Callbacks are verified and signed, subscriptions
    and the retry queue survive restarts, and the Slack signing secret is entered
    at a hidden prompt (plug auth slack-events set) and kept in the Keychain.
    Off unless configured; Slack only. See docs/slack-mcp-events.md.

  • owner_proof_until lets the owner prove Slack event delivery alone for up to
    one hour by sending one exact test marker. Every other owner message stays
    excluded.

  • Grok Build is a client. plug link grok-build writes [mcp_servers.plug] to
    ~/.grok/config.toml (or .grok/config.toml with --project), import reads
    servers from it, and a Grok Build session is named in Clients. Grok Bot,
    which reaches Plug over the internet only, is recognised by name and shows
    its icon when the Grok Bot app is installed.

  • Plug links Hermes Agent. plug link hermes adds a plug entry under
    mcp_servers in ~/.hermes/config.yaml and changes no other line of the
    file. A link written there by hand, Plug or plug, is recognised and
    replaced. plug import hermes reads its servers.

  • The app shows Warp, Kiro, and Hermes Agent with their own icons, and names
    Gemini, Perplexity, Le Chat, and Poke when they connect.

  • Plug links Kimi Code and Qwen Code. plug link kimi-code writes
    ~/.kimi-code/mcp.json and plug link qwen-code writes
    ~/.qwen/settings.json; both also import from those files and show in the
    app's client list.

  • An HTTP API can be a server. plug server add <name> --openapi <url-or-file>
    reads an OpenAPI 3 document, JSON or YAML, and lists each operation as one
    tool; a call makes the HTTP request. --url sets where the API lives when
    the document does not say, --bearer-token signs in, and --operations
    picks which operations to expose, which an API with more than 50 requires.
    GET and HEAD operations are marked read-only, a status of 400 or above is a
    tool error, and requests go only to the API's own address. In the config
    this is transport = "openapi" with spec and operations.

  • The app adds an HTTP API as a server. Paste the address or the file path of
    an OpenAPI document into Add Server; Plug guesses whether an address is a
    server or an API document, and a picker corrects the guess.

  • An API server can sign in with an API key. When the OpenAPI document says
    the key goes in a header or a query parameter, the token from
    --bearer-token is sent there; --token-in header:<name>, query:<name>,
    or bearer (token_in in the config) says so when the document does not.

  • Add Server lists an API's operations, grouped as the document groups them,
    with a checkbox on each. An API with more than 50 operations starts with
    none chosen and is added once 50 or fewer are.

Changed

  • Plug has a new icon: a white power symbol on blue. It shows in the Dock, in
    Finder, and inside clients that picture the servers they connect to.
  • Clients shows one row and one switch for each client. Press a row to see
    which servers the client can use, what is connected now, and to rename it.
    Sessions, ids, and Revoke are no longer on the page: turning off a client
    that connects over the network asks first, then removes its access.
  • The menu bar panel and the window now agree. Both show the same count line
    ("12 servers · 140 tools"), the panel lists servers that are off, dimmed and
    last, and a server row says "14 tools" in both places.
  • Every sheet has the same width, the same footer, and the same way of saying
    what went wrong, including Add Another Account and Watch a Tool. Switches in
    rows are one size.
  • A problem says what happened and what to do. A press that fails now reads
    "Could not restart notion.", then the reason, then the next step, and it
    stays until you dismiss it; it used to be the raw error and leave after 8
    seconds. The window, the menu bar panel, and every sheet show a problem the
    same way.
  • An import that adds some servers and not others names the ones it could not
    add, with the reason under each, and leaves only those ticked so trying
    again retries only what failed.
  • A call's duration reads the same in Activity, the menu bar panel, and a
    server's recent calls. A caller Plug cannot name is "Unknown client".
  • Adding and editing a server are one form. After a pick or a paste, Add
    Server shows the same fields Edit does, filled in, so what Plug understood
    can be read and corrected before it is saved. The fields are Address and
    Key, or Command and Arguments, and Settings; the form says a key is kept in
    the Keychain. When Edit cannot read a server's settings it says why and
    offers Try Again, where it used to show an empty sheet.
  • The command line uses the app's words. plug status leads with whether
    Plug is running, how many clients are connected, and one line per server
    (Running, Unsteady, Down, Sign-in needed; On this Mac or Over the network);
    the connection and address detail moved behind plug status -v.
    plug doctor names each check the way the app's Checkup does, and the app
    now takes those names from the same list. plug clients says Set up, On
    this Mac, and Connected now, and keeps link and lazy-tool detail for -v.
  • plug server on|off and plug tools on|off replace enable|disable; the
    old words still work. plug --help no longer lists the commands only Plug
    itself runs (connect, serve, stop, reload); they still work.
  • Settings is a section of the Plug window, next to Servers, Clients, Events,
    and Activity, as one page: the switch that turns Plug off, Restart, Checkup,
    the three preferences, the settings file and logs, and the version. The
    separate Settings window is gone, and the gear in the menu bar panel opens
    this section. When Plug is stopped or several servers need attention, the
    banner offers Checkup, which opens Settings and runs it.
  • The app uses one word for one thing. A server is "On this Mac" or "Over the
    network", the same as in plug status. The file is always the "settings
    file". Whatever uses Plug is a "client", never an "app". A tool locked by a
    rule is "Off by rule" everywhere, the list of calls is "Recent calls"
    everywhere, importing is "Import Servers…" everywhere, and the guide has one
    title, "How Plug works". A server Plug has not started yet offers "Load It".
  • Devin replaces Windsurf everywhere Plug speaks: the target is devin
    (windsurf still works as an alias), it writes
    ~/.config/devin/mcp_config.json, the file Devin reads today, and import
    also scans the old ~/.codeium/windsurf/mcp_config.json. plug doctor no
    longer warns that a linked Devin accepts only 100 tools; that ceiling is
    Cascade's, the desktop app's legacy agent, and still applies to a session
    that introduces itself as windsurf-client.
  • The window's Apps tab is now Clients, and every program that uses tools
    through Plug is called a client across the app, the README, and the docs.
    Agents, apps, and scripts are all clients; plug clients already said so.
    The vision doc (docs/VISION.md) now carries the five words Plug uses and
    the words it avoids.
  • Docs match the shipped product: the README describes the app, the
    architecture and dual-era guides describe main instead of a development
    branch, and the August app design review moved to docs/archive/.

Fixed

  • A server that is off stays off. Editing its settings, moving its key to
    the Keychain, or turning it off used to start it again until the next
    restart of the service, and Restart in the app started it too.
  • plug server add with flags no longer stops to ask for arguments when the
    command takes none.
  • MCP Apps work through Plug. Plug now tells each server it can show app
    pages, so servers that check before offering one offer it; the ui field
    that links a tool to its page and carries the page's sandbox settings is
    passed on instead of dropped; and a page can call its server's tools by the
    names that server gave them, as long as only one listed tool has that name.
  • A removed server that never connected, one waiting for sign-in or one that
    failed to start, stayed in plug servers and the app until the service
    restarted. It now leaves at once.
  • Linking VS Code wrote a file VS Code does not read, in a shape it does not
    accept. The link now writes top-level servers to mcp.json in the VS Code
    user folder, or to .vscode/mcp.json for a project link. Link VS Code again
    to pick this up; the old mcp entry in ~/.copilot/mcp-config.json is
    ignored by both programs and can be deleted.