open-neko · 8 plugins

OpenNeko Official

First-party plugins for OpenNeko. Published by the maintainers under @open-neko/* on npm. Written, tested, and supported by the OpenNeko team.

Third parties: publish your own marketplace.json at any HTTPS URL — see the publish guide for the schema, integrity-hash recipe, and CI checks.

How operators install

openneko install <name> writes the manifest entry and pulls the pinned version from npm. On the next worker start, every listed plugin boots in its own OpenShell sandbox.

Marketplace URL

open-neko.github.io/plugins/marketplace.json

Trusted by default — the openneko CLI fetches it on every install. Third parties: openneko marketplace add <url>.

Plugins listed

8

Plugins

Click view source for each plugin's repository. Every plugin runs inside an OpenShell sandbox with outbound network limited to the hosts shown on the card — the manifest declaration is enforced at the sandbox boundary.

Telegram channel

@open-neko/channel-telegram v0.7.2

Bidirectional Telegram channel: delivers the agent's Briefing, findings, and approvals to a chat (HTML + inline Approve/Reject buttons) and turns replies and button taps back into agent intents. Authenticated via a bot token from @BotFather, stored in the per-user secrets file.

api.telegram.org
prompts at install for:
🔒 TELEGRAM_BOT_TOKEN🔒 TELEGRAM_WEBHOOK_SECRET?
openneko install @open-neko/channel-telegram view source ↗

Parallel.ai Search MCP

@open-neko/plugin-parallel-search v0.3.1

Web search + page fetch via Parallel.ai's Search MCP over Streamable HTTP. Anonymous tier supported; Bearer-token authenticated tier optional. Two actions: web_search and web_fetch.

web_searchweb_fetchsearch.parallel.ai
openneko install @open-neko/plugin-parallel-search view source ↗

Scalekit SSO

@open-neko/plugin-scalekit v0.5.0

Enterprise SSO via Scalekit. One integration that fronts Okta, Entra ID, Google Workspace, JumpCloud, and other identity providers. Implements OpenNeko's generic OIDC auth contract — install this plugin and the 'Sign in with Scalekit' button lights up in the web app.

SSO provider: Scalekitlist_environmentsget_environment_detailsget_environment_credentialslist_environment_rolescreate_environment_rolelist_environment_scopescreate_environment_scopelist_workspace_membersinvite_workspace_memberlist_organizationsget_organization_detailscreate_organizationgenerate_admin_portal_linklist_environment_connectionslist_organization_connectionsenable_environment_connectionlist_connected_accountscreate_connected_account_magic_linkcreate_organization_userlist_organization_usersupdate_organization_settingslist_mcp_serversregister_mcp_serverupdate_mcp_serverswitch_mcp_auth_to_scalekitsearch_connectorssearch_toolssearch_docslist_redirect_urisadd_redirect_uriremove_redirect_uriset_initiate_login_uriremove_initiate_login_uriadd_post_logout_redirect_uriremove_post_logout_redirect_uri*.scalekit.com*.scalekit.dev
prompts at install for:
SCALEKIT_ENVIRONMENT_URLSCALEKIT_CLIENT_ID🔒 SCALEKIT_CLIENT_SECRETSCALEKIT_ORGANIZATION_ID?SCALEKIT_MCP_URL?
openneko install @open-neko/plugin-scalekit view source ↗

Google Workspace connector

@open-neko/connector-google-workspace v0.2.1

Per-operator Google Workspace connector — PKCE OAuth2 against your own Cloud Console OAuth client. Each operator authorises independently; OpenNeko persists their refresh token in the per-operator section of the secrets file and rotates the access token on demand. Three actions: send_gmail, list_calendar_events, append_sheet_row.

send_gmaillist_calendar_eventsappend_sheet_rowaccounts.google.comoauth2.googleapis.comgmail.googleapis.comwww.googleapis.comsheets.googleapis.comdocs.googleapis.com
prompts at install for:
GOOGLE_CLIENT_ID🔒 GOOGLE_CLIENT_SECRET
openneko install @open-neko/connector-google-workspace view source ↗

Shopify Admin connector

@open-neko/plugin-shopify v0.2.1

Per-deployment Shopify Admin API connector — list orders, fetch order detail, update internal order notes. Bound to one *.myshopify.com store via a deployment-wide Admin API access token. Three actions: list_shopify_orders, get_shopify_order, update_shopify_order_note.

list_shopify_ordersget_shopify_orderupdate_shopify_order_note*.myshopify.com
prompts at install for:
SHOPIFY_STORE_DOMAIN🔒 SHOPIFY_ACCESS_TOKENSHOPIFY_API_VERSION?
openneko install @open-neko/plugin-shopify view source ↗

Slack

@open-neko/plugin-slack v0.5.0

A bidirectional Slack channel — DM the agent, @-mention it in a channel, and run /openneko slash commands (inbound over Socket Mode) — plus four separately approvable actions: post messages, send DMs, react with emoji, and look up users/channels. Authenticated via a Slack bot token (xoxb-); inbound adds an app-level token (xapp-).

send_slack_messagesend_slack_dmreact_slack_messagelookup_slack_entityslack.com
prompts at install for:
🔒 SLACK_BOT_TOKEN🔒 SLACK_SIGNING_SECRET?🔒 SLACK_APP_TOKEN?
openneko install @open-neko/plugin-slack view source ↗

Magic-link sign-in

@open-neko/plugin-magic-link v0.3.1

Passwordless email sign-in implementing OpenNeko's auth contract with manual provisioning: an admin creates each user (email + role) in OpenNeko first, and only those users can request a single-use, HMAC-signed sign-in link — possession of a mailbox never mints an account. Link delivery via Resend, Postmark, or SendGrid, selected by which API key is configured.

SSO provider: Email linkapi.resend.comapi.postmarkapp.comapi.sendgrid.com
prompts at install for:
🔒 MAGIC_LINK_SIGNING_SECRETMAGIC_LINK_FROM🔒 RESEND_API_KEY?🔒 POSTMARK_SERVER_TOKEN?🔒 SENDGRID_API_KEY?MAGIC_LINK_TTL_SECONDS?
openneko install @open-neko/plugin-magic-link view source ↗

Resend operational email

@open-neko/plugin-resend v0.2.1

Operational email through Resend. The agent sends an email from a Resend template, from Markdown in a house layout with your logo and color, or from HTML, and checks delivery status. Operators design alert emails in plain language; the agent asks how to show the content and saves the layout in the workflow. Approval rules match the real recipient domains. Four actions: send_email, list_email_templates, get_email_template, get_email_status.

send_emaillist_email_templatesget_email_templateget_email_statusapi.resend.com
prompts at install for:
🔒 RESEND_API_KEYRESEND_FROMRESEND_REPLY_TO?RESEND_ALLOWED_RECIPIENTS?RESEND_LOGO_URL?RESEND_BRAND_COLOR?RESEND_FOOTER_TEXT?
openneko install @open-neko/plugin-resend view source ↗

Trust model

This is the official OpenNeko marketplace — written, tested, and supported by the OpenNeko team. Anyone else who ships plugins to OpenNeko users publishes their own marketplace.json. Operators trust each one explicitly.

First-party

Listed here

The OpenNeko maintainers write these. Code lives in open-neko/plugins; we yank a version if it ever turns malicious.

Third-party

Add your own

Publish your marketplace.json at any HTTPS URL, then operators trust it with openneko marketplace add <url>. OpenNeko makes no representation about non-official marketplaces.

Bypass

openneko install <name> --unverified

Skip every marketplace and install straight from npm. Loud warning. For plugin authoring or emergency hotfixes — the integrity hash is taken on trust, but sandboxing and capability enforcement still apply.

For developers

The exact bytes the openneko CLI fetches when an operator runs openneko marketplace add or openneko install. Use the schema if you're publishing your own marketplace.json. Each block is also served at a stable URL so you can curl it.

marketplace.json GET https://open-neko.github.io/plugins/marketplace.json · 96.4 KB
{
  "$schema": "https://open-neko.github.io/plugins/marketplace.schema.json",
  "name": "OpenNeko Official",
  "owner": "open-neko",
  "homepage": "https://open-neko.github.io/plugins/",
  "description": "First-party plugins for OpenNeko. Published by the maintainers under @open-neko/* on npm. Written, tested, and supported by the OpenNeko team.",
  "plugins": [
    {
      "name": "@open-neko/channel-telegram",
      "title": "Telegram channel",
      "description": "Bidirectional Telegram channel: delivers the agent's Briefing, findings, and approvals to a chat (HTML + inline Approve/Reject buttons) and turns replies and button taps back into agent intents. Authenticated via a bot token from @BotFather, stored in the per-user secrets file.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/telegram",
      "homepage": "https://core.telegram.org/bots/api",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.3.1",
          "integrity": "sha512-fhQgHLdnVkOCfCNDnnAyUmDMNrIZhFzerllcqZGBLJp+Vmrn9lLLxa18wyMXrSD2GEdmZLcI0TlRXYq7A3WDKA==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "Bot token from @BotFather (e.g. 123456789:AAH...). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token set via setWebhook; verify_inbound checks Telegram's X-Telegram-Bot-Api-Secret-Token header against it. Not needed for getUpdates long-poll."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.3.0",
          "integrity": "sha512-dKx2Ro0X0KdjZkMxTR/tFJt3bIyUl+byq8CUfC/iwNgcs0A6/R6Vxzv1EWniKxEay+h91vE1MLCtXtOr75+XGg==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "Bot token from @BotFather (e.g. 123456789:AAH...). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token set via setWebhook; verify_inbound checks Telegram's X-Telegram-Bot-Api-Secret-Token header against it. Not needed for getUpdates long-poll."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-05-25"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-6DCDiVh+CMU6wCuyp3N2RMIhpehs/C0vC2nP08XzFzo/8uK1GLO0YpN4wXYp3RUMcrYBiOvCLyx4+gbuNE/yEw==",
          "provenanceWaived": true,
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "Bot token from @BotFather (e.g. 123456789:AAH...). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token set via setWebhook; verify_inbound checks Telegram's X-Telegram-Bot-Api-Secret-Token header against it. Not needed for getUpdates long-poll."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-05-25"
        },
        {
          "version": "0.4.0",
          "integrity": "sha512-VyemqbEcmj3q90JWyQd6m9WOQP7ml8J2Aa7IUSvVPoc48bzyIStBSj14UDNshex6bZDz+uN+Ytih2tyT04zr3A==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "Bot token from @BotFather (e.g. 123456789:AAH...). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token set via setWebhook; verify_inbound checks Telegram's X-Telegram-Bot-Api-Secret-Token header against it. Not needed for getUpdates long-poll."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-11"
        },
        {
          "version": "0.5.0",
          "integrity": "sha512-FqMkx69a97sACbBGQOjGGFbpljJsScsDDNweiT0/sNXU6iM6B8Eo9Vl1OYt9owFLcT5DvIA3GxFhcGJS0R2WFQ==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "Bot token from @BotFather (e.g. 123456789:AAH…). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver. When unset at exec time the plugin runs in dry-run mode — it still projects the native payload but sends nothing."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token you set when registering a webhook via setWebhook. When present, verify_inbound requires Telegram's X-Telegram-Bot-Api-Secret-Token header to match it (constant-time). Not needed for long-polling (getUpdates)."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-24"
        },
        {
          "version": "0.6.0",
          "integrity": "sha512-Lq9rKJD0GdvsgEi/L3K5aLIoAJQlKAHypNJ4/tBqYpCDtQ1QukwfthA2KL4op7SdcuDfB47HjA4eZ5YCbfatLA==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "Bot token from @BotFather (e.g. 123456789:AAH…). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver. When unset at exec time the plugin runs in dry-run mode — it still projects the native payload but sends nothing."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token you set when registering a webhook via setWebhook. When present, verify_inbound requires Telegram's X-Telegram-Bot-Api-Secret-Token header to match it (constant-time). Not needed for long-polling (getUpdates)."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-26"
        },
        {
          "version": "0.7.0",
          "integrity": "sha512-f1VEYn3YMIHc7sjnirjJ9kSi4m2lLR3bPz3NvcyfLM7JNHE2GPkdcaFDARrxPFVY+Z4pcilH4IbJCbllu26B3w==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "Bot token from @BotFather (e.g. 123456789:AAH…). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver. When unset at exec time the plugin runs in dry-run mode — it still projects the native payload but sends nothing."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token you set when registering a webhook via setWebhook. When present, verify_inbound requires Telegram's X-Telegram-Bot-Api-Secret-Token header to match it (constant-time). Not needed for long-polling (getUpdates)."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-26"
        },
        {
          "version": "0.7.2",
          "integrity": "sha512-aU3rW2ab5Nn6kjEp8WHJP9nAn1W2jL3QoEkYJhMGM6z2T2GdPPJ9sFc3UFr4lh/pA8ROYRNVCbCw9Jdb05JdyA==",
          "permissions": {
            "network": [
              "api.telegram.org"
            ],
            "env": [
              {
                "key": "TELEGRAM_BOT_TOKEN",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "Bot token from @BotFather (e.g. 123456789:AAH…). The plugin calls https://api.telegram.org/bot<token>/sendMessage to deliver. When unset at exec time the plugin runs in dry-run mode — it still projects the native payload but sends nothing."
              },
              {
                "key": "TELEGRAM_WEBHOOK_SECRET",
                "required": false,
                "secret": true,
                "description": "Optional secret_token you set when registering a webhook via setWebhook. When present, verify_inbound requires Telegram's X-Telegram-Bot-Api-Secret-Token header to match it (constant-time). Not needed for long-polling (getUpdates)."
              }
            ]
          },
          "capabilities": {
            "channel": {
              "providerLabel": "Telegram",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "webhook",
              "profile": {
                "modalities": [
                  "text"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": false,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "maxOutboundChars": 4096,
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-26"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-parallel-search",
      "title": "Parallel.ai Search MCP",
      "description": "Web search + page fetch via Parallel.ai's Search MCP over Streamable HTTP. Anonymous tier supported; Bearer-token authenticated tier optional. Two actions: web_search and web_fetch.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/parallel-search",
      "homepage": "https://docs.parallel.ai/integrations/mcp/search-mcp",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.3.1",
          "integrity": "sha512-n5yLgTAVBqoGyhZjn9KJB1Z2m6kf8lurgnpQ2Z4Qk2FpiHSae29QPwv1xy/HFgmSqnhjXxFyU/l3l+lReWnaGA==",
          "permissions": {
            "network": [
              "search.parallel.ai"
            ],
            "env": []
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "web_search",
                  "description": "Search the web via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                },
                {
                  "kind": "web_fetch",
                  "description": "Fetch a single page via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-gX6PcjZvyl2ggW1HLy0v9KANPHoBi96DhsBVzDmY4v2nDiQHjufDacazwaHi+OInT8+wz+Hf+gqSZETLDse79A==",
          "provenanceWaived": true,
          "permissions": {
            "network": [
              "search.parallel.ai"
            ],
            "env": []
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "web_search",
                  "description": "Search the web via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                },
                {
                  "kind": "web_fetch",
                  "description": "Fetch a single page via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-05-17"
        },
        {
          "version": "0.3.0",
          "integrity": "sha512-NMAgy8RvNKhrmHFBEc6BGdbzVlsUkCALK3XYvZ8k7QqxUBYrgy5ogpIlJJMlmVckDDr42dZ+GflsKMTVC8qpBw==",
          "permissions": {
            "network": [
              "search.parallel.ai"
            ],
            "env": []
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "web_search",
                  "description": "Search the web via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                },
                {
                  "kind": "web_fetch",
                  "description": "Fetch a single page via Parallel.ai's Search MCP.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-05-24"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-scalekit",
      "title": "Scalekit SSO",
      "description": "Enterprise SSO via Scalekit. One integration that fronts Okta, Entra ID, Google Workspace, JumpCloud, and other identity providers. Implements OpenNeko's generic OIDC auth contract — install this plugin and the 'Sign in with Scalekit' button lights up in the web app.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/scalekit",
      "homepage": "https://docs.scalekit.com/sso/quickstart",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.2.1",
          "integrity": "sha512-COH/05vyBYCyNNHJ+GjBKTHFRvJf6cXkCYTpqrbtUJ4jXFM0AFWSl1YPW/zXROf+2IC1xCH+NChDKQTTdxNR5Q==",
          "permissions": {
            "network": [
              "*.scalekit.com"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard under API config."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "The OAuth client_id from the Scalekit dashboard. Public — paired with the secret below for token exchange."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "The OAuth client_secret from the Scalekit dashboard. Stored in the per-user secrets file, never echoed."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Scalekit"
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.1.0",
          "integrity": "sha512-XTDCF4qaMptWHrD4d0ojd+gs5fb7q3GHe0Qhi4dBzGwerZilQDBGorUVGy4TRiFVTo/s7Rbx6lzD8LbXNV5RMA==",
          "provenanceWaived": true,
          "permissions": {
            "network": [
              "*.scalekit.com"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "OAuth client_id from the Scalekit dashboard."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "OAuth client_secret from the Scalekit dashboard. Stored in the per-user secrets file."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Scalekit"
            }
          },
          "publishedAt": "2026-05-18"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-uMaoqLnHW//RI0mm+f1Dnr+89FKE/R0MtR/9FIGFi1ZmOxpEBbEWcrBjgSln+0cq6salv8O7dlBwYqsqF+Tbsg==",
          "permissions": {
            "network": [
              "*.scalekit.com"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard under API config."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "The OAuth client_id from the Scalekit dashboard. Public — paired with the secret below for token exchange."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "The OAuth client_secret from the Scalekit dashboard. Stored in the per-user secrets file, never echoed."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Scalekit"
            }
          },
          "publishedAt": "2026-05-24"
        },
        {
          "version": "0.3.0",
          "integrity": "sha512-BgSXmwm3iveiyxZyt6EyPWlnmYpWtycbGWJBOvCRx8827zgFPtMRUkP2qXiMZNHj99NTbbj61FSwbgqh0ZhjiQ==",
          "permissions": {
            "network": [
              "*.scalekit.com",
              "*.scalekit.dev"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard under API config. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "The OAuth client_id from the Scalekit dashboard. Public — paired with the secret below for token exchange. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "The OAuth client_secret from the Scalekit dashboard. Shown only once in the dashboard — stored in the per-user secrets file, never echoed."
              },
              {
                "key": "SCALEKIT_MCP_URL",
                "required": false,
                "secret": false,
                "description": "Optional Scalekit MCP server URL for workspace management. Defaults to the hosted https://mcp.scalekit.com/."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "list_environments",
                  "description": "List all Scalekit environments in the workspace (Dev/Prod, ids + domains).",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_details",
                  "description": "Get details of one Scalekit environment by id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_credentials",
                  "description": "Return SCALEKIT_ENVIRONMENT_URL + SCALEKIT_CLIENT_ID for an environment (the client secret is dashboard-only).",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_environment_roles",
                  "description": "List roles defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_role",
                  "description": "Create a new role in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_scopes",
                  "description": "List scopes defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_scope",
                  "description": "Create a new scope in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_workspace_members",
                  "description": "List members of the Scalekit workspace.",
                  "default_mode": "auto"
                },
                {
                  "kind": "invite_workspace_member",
                  "description": "Invite a member to the Scalekit workspace by email.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organizations",
                  "description": "List organizations under a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_organization_details",
                  "description": "Get details of one Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_organization",
                  "description": "Create a new organization under a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "generate_admin_portal_link",
                  "description": "Generate a single-use admin portal magic link for an organization (guides the operator through IdP setup).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_connections",
                  "description": "List SSO/OIDC connections configured in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_organization_connections",
                  "description": "List connections for an organization (status DRAFT/IN_PROGRESS/COMPLETED).",
                  "default_mode": "auto"
                },
                {
                  "kind": "enable_environment_connection",
                  "description": "Enable an existing connection in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_connected_accounts",
                  "description": "List connected accounts (connector authorizations) in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_connected_account_magic_link",
                  "description": "Create a magic link to connect an OAuth connector account at the environment level.",
                  "default_mode": "ask"
                },
                {
                  "kind": "create_organization_user",
                  "description": "Create a user in a Scalekit organization.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organization_users",
                  "description": "List users of a Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "update_organization_settings",
                  "description": "Update an organization's settings (e.g. directory sync features).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_mcp_servers",
                  "description": "List MCP servers registered in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "register_mcp_server",
                  "description": "Register a new MCP server in an environment (Scalekit-auth or custom provider).",
                  "default_mode": "ask"
                },
                {
                  "kind": "update_mcp_server",
                  "description": "Update a registered MCP server in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "switch_mcp_auth_to_scalekit",
                  "description": "Switch an MCP server's authentication to Scalekit.",
                  "default_mode": "ask"
                },
                {
                  "kind": "search_connectors",
                  "description": "Search the Scalekit connector catalog for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_tools",
                  "description": "Search tools (actions) exposed by connectors in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_docs",
                  "description": "Search Scalekit documentation by keyword.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_redirect_uris",
                  "description": "List allowed callback URLs (redirect URIs) for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "add_redirect_uri",
                  "description": "Add a callback URL to an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_redirect_uri",
                  "description": "Remove a callback URL from an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "set_initiate_login_uri",
                  "description": "Set the initiate-login URI for an environment (IdP-initiated SSO).",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_initiate_login_uri",
                  "description": "Clear the initiate-login URI for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "add_post_logout_redirect_uri",
                  "description": "Add a post-logout redirect URL for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_post_logout_redirect_uri",
                  "description": "Remove a post-logout redirect URL from an environment.",
                  "default_mode": "ask"
                }
              ]
            },
            "connect": {
              "providerLabel": "Scalekit workspace",
              "flow": "mcp-oauth",
              "credentialScope": "deployment",
              "scopes": [
                "wks:read",
                "wks:write",
                "env:read",
                "env:write",
                "org:read",
                "org:write"
              ]
            },
            "auth": {
              "providerLabel": "Scalekit"
            }
          },
          "publishedAt": "2026-08-13"
        },
        {
          "version": "0.4.0",
          "integrity": "sha512-ylINJ/IRDUiKlDgtVTLeSUSXvIK1fuulmaGpZUN5EwTUxfGJUiYpCJMbE8ZqVG/MsyrWjc7RDcap1Dx5z24e+w==",
          "permissions": {
            "network": [
              "*.scalekit.com",
              "*.scalekit.dev"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard under API config. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "The OAuth client_id from the Scalekit dashboard. Public — paired with the secret below for token exchange. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "The OAuth client_secret from the Scalekit dashboard. Shown only once in the dashboard — stored in the per-user secrets file, never echoed."
              },
              {
                "key": "SCALEKIT_MCP_URL",
                "required": false,
                "secret": false,
                "description": "Optional Scalekit MCP server URL for workspace management. Defaults to the hosted https://mcp.scalekit.com/."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "list_environments",
                  "description": "List all Scalekit environments in the workspace (Dev/Prod, ids + domains).",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_details",
                  "description": "Get details of one Scalekit environment by id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_credentials",
                  "description": "Return SCALEKIT_ENVIRONMENT_URL + SCALEKIT_CLIENT_ID for an environment (the client secret is dashboard-only).",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_environment_roles",
                  "description": "List roles defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_role",
                  "description": "Create a new role in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_scopes",
                  "description": "List scopes defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_scope",
                  "description": "Create a new scope in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_workspace_members",
                  "description": "List members of the Scalekit workspace.",
                  "default_mode": "auto"
                },
                {
                  "kind": "invite_workspace_member",
                  "description": "Invite a member to the Scalekit workspace by email.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organizations",
                  "description": "List organizations under a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_organization_details",
                  "description": "Get details of one Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_organization",
                  "description": "Create a new organization under a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "generate_admin_portal_link",
                  "description": "Generate a single-use admin portal magic link for an organization (guides the operator through IdP setup).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_connections",
                  "description": "List SSO/OIDC connections configured in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_organization_connections",
                  "description": "List connections for an organization (status DRAFT/IN_PROGRESS/COMPLETED).",
                  "default_mode": "auto"
                },
                {
                  "kind": "enable_environment_connection",
                  "description": "Enable an existing connection in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_connected_accounts",
                  "description": "List connected accounts (connector authorizations) in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_connected_account_magic_link",
                  "description": "Create a magic link to connect an OAuth connector account at the environment level.",
                  "default_mode": "ask"
                },
                {
                  "kind": "create_organization_user",
                  "description": "Create a user in a Scalekit organization.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organization_users",
                  "description": "List users of a Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "update_organization_settings",
                  "description": "Update an organization's settings (e.g. directory sync features).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_mcp_servers",
                  "description": "List MCP servers registered in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "register_mcp_server",
                  "description": "Register a new MCP server in an environment (Scalekit-auth or custom provider).",
                  "default_mode": "ask"
                },
                {
                  "kind": "update_mcp_server",
                  "description": "Update a registered MCP server in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "switch_mcp_auth_to_scalekit",
                  "description": "Switch an MCP server's authentication to Scalekit.",
                  "default_mode": "ask"
                },
                {
                  "kind": "search_connectors",
                  "description": "Search the Scalekit connector catalog for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_tools",
                  "description": "Search tools (actions) exposed by connectors in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_docs",
                  "description": "Search Scalekit documentation by keyword.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_redirect_uris",
                  "description": "List allowed callback URLs (redirect URIs) for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "add_redirect_uri",
                  "description": "Add a callback URL to an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_redirect_uri",
                  "description": "Remove a callback URL from an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "set_initiate_login_uri",
                  "description": "Set the initiate-login URI for an environment (IdP-initiated SSO).",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_initiate_login_uri",
                  "description": "Clear the initiate-login URI for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "add_post_logout_redirect_uri",
                  "description": "Add a post-logout redirect URL for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_post_logout_redirect_uri",
                  "description": "Remove a post-logout redirect URL from an environment.",
                  "default_mode": "ask"
                }
              ]
            },
            "connect": {
              "providerLabel": "Scalekit workspace",
              "flow": "mcp-oauth",
              "credentialScope": "deployment",
              "scopes": [
                "wks:read",
                "wks:write",
                "env:read",
                "env:write",
                "org:read",
                "org:write"
              ]
            },
            "auth": {
              "providerLabel": "Scalekit"
            }
          },
          "publishedAt": "2026-08-13"
        },
        {
          "version": "0.5.0",
          "integrity": "sha512-Rhq5pOJa2Z60RG46RRY2DsWt7uhjTB3zHmAu6DPWNOkv51drJfP0yE/kvITXvElCNQxMf7TMDFHv69di3hh4Fg==",
          "permissions": {
            "network": [
              "*.scalekit.com",
              "*.scalekit.dev"
            ],
            "env": [
              {
                "key": "SCALEKIT_ENVIRONMENT_URL",
                "required": true,
                "secret": false,
                "description": "Your Scalekit environment URL, e.g. https://your-app.scalekit.com — copied from the Scalekit dashboard under API config. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "The OAuth client_id from the Scalekit dashboard. Public — paired with the secret below for token exchange. The agent can fetch this automatically via get_environment_credentials."
              },
              {
                "key": "SCALEKIT_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "The OAuth client_secret from the Scalekit dashboard. Shown only once in the dashboard — stored in the per-user secrets file, never echoed."
              },
              {
                "key": "SCALEKIT_ORGANIZATION_ID",
                "required": false,
                "secret": false,
                "description": "The Scalekit organization whose SCIM directory OpenNeko syncs, e.g. org_123. Needed for directory sync and for creating users. The agent can find it with list_organizations."
              },
              {
                "key": "SCALEKIT_MCP_URL",
                "required": false,
                "secret": false,
                "description": "Optional Scalekit MCP server URL for workspace management. Defaults to the hosted https://mcp.scalekit.com/."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "list_environments",
                  "description": "List all Scalekit environments in the workspace (Dev/Prod, ids + domains).",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_details",
                  "description": "Get details of one Scalekit environment by id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_environment_credentials",
                  "description": "Return SCALEKIT_ENVIRONMENT_URL + SCALEKIT_CLIENT_ID for an environment (the client secret is dashboard-only).",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_environment_roles",
                  "description": "List roles defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_role",
                  "description": "Create a new role in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_scopes",
                  "description": "List scopes defined in a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_environment_scope",
                  "description": "Create a new scope in a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_workspace_members",
                  "description": "List members of the Scalekit workspace.",
                  "default_mode": "auto"
                },
                {
                  "kind": "invite_workspace_member",
                  "description": "Invite a member to the Scalekit workspace by email.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organizations",
                  "description": "List organizations under a Scalekit environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_organization_details",
                  "description": "Get details of one Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_organization",
                  "description": "Create a new organization under a Scalekit environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "generate_admin_portal_link",
                  "description": "Generate a single-use admin portal magic link for an organization (guides the operator through IdP setup).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_environment_connections",
                  "description": "List SSO/OIDC connections configured in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_organization_connections",
                  "description": "List connections for an organization (status DRAFT/IN_PROGRESS/COMPLETED).",
                  "default_mode": "auto"
                },
                {
                  "kind": "enable_environment_connection",
                  "description": "Enable an existing connection in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_connected_accounts",
                  "description": "List connected accounts (connector authorizations) in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "create_connected_account_magic_link",
                  "description": "Create a magic link to connect an OAuth connector account at the environment level.",
                  "default_mode": "ask"
                },
                {
                  "kind": "create_organization_user",
                  "description": "Create a user in a Scalekit organization.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_organization_users",
                  "description": "List users of a Scalekit organization.",
                  "default_mode": "auto"
                },
                {
                  "kind": "update_organization_settings",
                  "description": "Update an organization's settings (e.g. directory sync features).",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_mcp_servers",
                  "description": "List MCP servers registered in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "register_mcp_server",
                  "description": "Register a new MCP server in an environment (Scalekit-auth or custom provider).",
                  "default_mode": "ask"
                },
                {
                  "kind": "update_mcp_server",
                  "description": "Update a registered MCP server in an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "switch_mcp_auth_to_scalekit",
                  "description": "Switch an MCP server's authentication to Scalekit.",
                  "default_mode": "ask"
                },
                {
                  "kind": "search_connectors",
                  "description": "Search the Scalekit connector catalog for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_tools",
                  "description": "Search tools (actions) exposed by connectors in an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "search_docs",
                  "description": "Search Scalekit documentation by keyword.",
                  "default_mode": "auto"
                },
                {
                  "kind": "list_redirect_uris",
                  "description": "List allowed callback URLs (redirect URIs) for an environment.",
                  "default_mode": "auto"
                },
                {
                  "kind": "add_redirect_uri",
                  "description": "Add a callback URL to an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_redirect_uri",
                  "description": "Remove a callback URL from an environment's allowed redirect URIs.",
                  "default_mode": "ask"
                },
                {
                  "kind": "set_initiate_login_uri",
                  "description": "Set the initiate-login URI for an environment (IdP-initiated SSO).",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_initiate_login_uri",
                  "description": "Clear the initiate-login URI for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "add_post_logout_redirect_uri",
                  "description": "Add a post-logout redirect URL for an environment.",
                  "default_mode": "ask"
                },
                {
                  "kind": "remove_post_logout_redirect_uri",
                  "description": "Remove a post-logout redirect URL from an environment.",
                  "default_mode": "ask"
                }
              ]
            },
            "connect": {
              "providerLabel": "Scalekit workspace",
              "flow": "mcp-oauth",
              "credentialScope": "deployment",
              "scopes": [
                "wks:read",
                "wks:write",
                "env:read",
                "env:write",
                "org:read",
                "org:write"
              ]
            },
            "auth": {
              "providerLabel": "Scalekit"
            },
            "directory": {
              "providerLabel": "Scalekit directory",
              "read": {
                "users": true,
                "groups": true,
                "memberships": true
              },
              "write": {
                "createUser": true,
                "deactivateUser": false
              }
            }
          },
          "publishedAt": "2026-09-16"
        }
      ]
    },
    {
      "name": "@open-neko/connector-google-workspace",
      "title": "Google Workspace connector",
      "description": "Per-operator Google Workspace connector — PKCE OAuth2 against your own Cloud Console OAuth client. Each operator authorises independently; OpenNeko persists their refresh token in the per-operator section of the secrets file and rotates the access token on demand. Three actions: send_gmail, list_calendar_events, append_sheet_row.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/google-workspace",
      "homepage": "https://developers.google.com/identity/protocols/oauth2",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.2.1",
          "integrity": "sha512-RD07xb8mmk27Vl0ebIpvTWtmPi+oOBWibfiO2fbolsQX66fMDJLdW3jeZ0sdDTJWL47BUmO2vsZPXzZNElPIKw==",
          "permissions": {
            "network": [
              "accounts.google.com",
              "oauth2.googleapis.com",
              "gmail.googleapis.com",
              "www.googleapis.com",
              "sheets.googleapis.com",
              "docs.googleapis.com"
            ],
            "env": [
              {
                "key": "GOOGLE_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "OAuth 2.0 Client ID from Google Cloud Console (deployment-wide — all operators share one client). Create at https://console.cloud.google.com/apis/credentials → Create credentials → OAuth client ID → Web application; set the redirect URI to your deployment's connect callback."
              },
              {
                "key": "GOOGLE_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "OAuth 2.0 Client Secret paired with the client ID above. Stored in the per-user secrets file, never echoed."
              }
            ]
          },
          "capabilities": {
            "connect": {
              "providerLabel": "Google Workspace",
              "scopes": [
                "openid",
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/gmail.send",
                "https://www.googleapis.com/auth/calendar.events.readonly",
                "https://www.googleapis.com/auth/spreadsheets",
                "https://www.googleapis.com/auth/documents"
              ],
              "flow": "oauth2-pkce"
            },
            "action": {
              "kinds": [
                {
                  "kind": "send_gmail",
                  "description": "Send an email from the connected user's Gmail account.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_calendar_events",
                  "description": "List upcoming events on the connected user's primary calendar.",
                  "default_mode": "auto"
                },
                {
                  "kind": "append_sheet_row",
                  "description": "Append a row to a Google Sheet the connected user can edit.",
                  "default_mode": "ask"
                }
              ]
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-VzsTtkvvk75QRZ8tt1EdCMX6+ltjqgXaI2nVjo05aSKeL6UEouAkauDPBTD84cim1cbc2IV4/B2y/2yAji1vMg==",
          "permissions": {
            "network": [
              "accounts.google.com",
              "oauth2.googleapis.com",
              "gmail.googleapis.com",
              "www.googleapis.com",
              "sheets.googleapis.com",
              "docs.googleapis.com"
            ],
            "env": [
              {
                "key": "GOOGLE_CLIENT_ID",
                "required": true,
                "secret": false,
                "description": "OAuth 2.0 Client ID from Google Cloud Console (deployment-wide — all operators share one client). Create at https://console.cloud.google.com/apis/credentials → Create credentials → OAuth client ID → Web application; set the redirect URI to your deployment's connect callback."
              },
              {
                "key": "GOOGLE_CLIENT_SECRET",
                "required": true,
                "secret": true,
                "description": "OAuth 2.0 Client Secret paired with the client ID above. Stored in the per-user secrets file, never echoed."
              }
            ]
          },
          "capabilities": {
            "connect": {
              "providerLabel": "Google Workspace",
              "scopes": [
                "openid",
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/gmail.send",
                "https://www.googleapis.com/auth/calendar.events.readonly",
                "https://www.googleapis.com/auth/spreadsheets",
                "https://www.googleapis.com/auth/documents"
              ],
              "flow": "oauth2-pkce"
            },
            "action": {
              "kinds": [
                {
                  "kind": "send_gmail",
                  "description": "Send an email from the connected user's Gmail account.",
                  "default_mode": "ask"
                },
                {
                  "kind": "list_calendar_events",
                  "description": "List upcoming events on the connected user's primary calendar.",
                  "default_mode": "auto"
                },
                {
                  "kind": "append_sheet_row",
                  "description": "Append a row to a Google Sheet the connected user can edit.",
                  "default_mode": "ask"
                }
              ]
            }
          },
          "publishedAt": "2026-05-24"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-shopify",
      "title": "Shopify Admin connector",
      "description": "Per-deployment Shopify Admin API connector — list orders, fetch order detail, update internal order notes. Bound to one *.myshopify.com store via a deployment-wide Admin API access token. Three actions: list_shopify_orders, get_shopify_order, update_shopify_order_note.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/shopify",
      "homepage": "https://shopify.dev/docs/api/admin-rest",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.2.1",
          "integrity": "sha512-P/dC8a8UMMIYBASc2QRzhN+vDbB9y1IqTuhW7A4a/zPujpImSeV0quFNDo5i8EP8eKbDk7b9HDgNZZFBgzXpaQ==",
          "permissions": {
            "network": [
              "*.myshopify.com"
            ],
            "env": [
              {
                "key": "SHOPIFY_STORE_DOMAIN",
                "required": true,
                "secret": false,
                "description": "Your store's permanent myshopify.com subdomain — e.g. acme.myshopify.com. Use the .myshopify.com domain even if you've configured a custom storefront domain; the Admin API only honors the canonical one."
              },
              {
                "key": "SHOPIFY_ACCESS_TOKEN",
                "required": true,
                "secret": true,
                "description": "Shopify Admin API access token (starts with shpat_). Create at admin → Settings → Apps and sales channels → Develop apps → Create an app → Configuration → Admin API access scopes. Needs read_orders + write_orders. Token is shown ONCE on install — copy it immediately."
              },
              {
                "key": "SHOPIFY_API_VERSION",
                "required": false,
                "secret": false,
                "description": "Shopify Admin API version to pin (defaults to 2026-01). Shopify rotates quarterly; pin a stable version to avoid surprise breakage."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "list_shopify_orders",
                  "description": "List recent orders, optionally filtered by financialStatus, fulfillmentStatus, or a date range (createdAtMin/createdAtMax).",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_shopify_order",
                  "description": "Fetch full detail for one order by id — line items, customer, addresses, refunds, tags.",
                  "default_mode": "auto"
                },
                {
                  "kind": "update_shopify_order_note",
                  "description": "Set or append the internal note on an order (user-visible in Shopify admin only; not customer-facing).",
                  "default_mode": "ask"
                }
              ]
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-JnzuEr8ag+U7/yL1eyTk/VwwK84zoP9GTRxPF6LTGukNTk1CJOloeE3XZmK+U8+5lCZ2dZrdv0yMbFDTDBp7gA==",
          "permissions": {
            "network": [
              "*.myshopify.com"
            ],
            "env": [
              {
                "key": "SHOPIFY_STORE_DOMAIN",
                "required": true,
                "secret": false,
                "description": "Your store's permanent myshopify.com subdomain — e.g. acme.myshopify.com. Use the .myshopify.com domain even if you've configured a custom storefront domain; the Admin API only honors the canonical one."
              },
              {
                "key": "SHOPIFY_ACCESS_TOKEN",
                "required": true,
                "secret": true,
                "description": "Shopify Admin API access token (starts with shpat_). Create at admin → Settings → Apps and sales channels → Develop apps → Create an app → Configuration → Admin API access scopes. Needs read_orders + write_orders. Token is shown ONCE on install — copy it immediately."
              },
              {
                "key": "SHOPIFY_API_VERSION",
                "required": false,
                "secret": false,
                "description": "Shopify Admin API version to pin (defaults to 2026-01). Shopify rotates quarterly; pin a stable version to avoid surprise breakage."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "list_shopify_orders",
                  "description": "List recent orders, optionally filtered by financialStatus, fulfillmentStatus, or a date range (createdAtMin/createdAtMax).",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_shopify_order",
                  "description": "Fetch full detail for one order by id — line items, customer, addresses, refunds, tags.",
                  "default_mode": "auto"
                },
                {
                  "kind": "update_shopify_order_note",
                  "description": "Set or append the internal note on an order (user-visible in Shopify admin only; not customer-facing).",
                  "default_mode": "ask"
                }
              ]
            }
          },
          "publishedAt": "2026-05-24"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-slack",
      "title": "Slack",
      "description": "A bidirectional Slack channel — DM the agent, @-mention it in a channel, and run /openneko slash commands (inbound over Socket Mode) — plus four separately approvable actions: post messages, send DMs, react with emoji, and look up users/channels. Authenticated via a Slack bot token (xoxb-); inbound adds an app-level token (xapp-).",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/slack",
      "homepage": "https://api.slack.com/web",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.2.1",
          "integrity": "sha512-4M9fp8UcSJWJahiHAJnfUHPB2IUo56sq3bR6rM4mLNphPqNZB2q3Z59Qp+fSpfOO7YtBR5YeSQSyV6paddrZxw==",
          "permissions": {
            "network": [
              "slack.com"
            ],
            "env": [
              {
                "key": "SLACK_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "xoxb-... bot token from your Slack app. Needs scopes: chat:write, im:write (for DMs), reactions:write, users:read, users:read.email (for email lookup), channels:read, groups:read (for channel lookup)."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_slack_message",
                  "description": "Post a message to a Slack channel.",
                  "default_mode": "auto"
                },
                {
                  "kind": "send_slack_dm",
                  "description": "Send a direct message to a Slack user. `user` may be a name, email, or Slack id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "react_slack_message",
                  "description": "Add an emoji reaction to a Slack message.",
                  "default_mode": "auto"
                },
                {
                  "kind": "lookup_slack_entity",
                  "description": "Look up a Slack user or channel by name or ID.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-06-02"
        },
        {
          "version": "0.1.0",
          "integrity": "sha512-+H6gDUp8vNfs5pVvffnEByN5ZDt9c5HiYGF1uQ2Hq5b6NZYNn7DHlQtMMAXXv1BOKuiHnCPBmYyL5+ltrMa8rQ==",
          "provenanceWaived": true,
          "permissions": {
            "network": [
              "slack.com"
            ],
            "env": [
              {
                "key": "SLACK_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "xoxb-... bot token from your Slack app. Needs scopes: chat:write, im:write, reactions:write, users:read, users:read.email, channels:read, groups:read (depending on which actions you'll allow)."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_slack_message",
                  "description": "Post a message to a Slack channel.",
                  "default_mode": "ask"
                },
                {
                  "kind": "send_slack_dm",
                  "description": "Send a direct message to a Slack user.",
                  "default_mode": "ask"
                },
                {
                  "kind": "react_slack_message",
                  "description": "Add an emoji reaction to a Slack message.",
                  "default_mode": "ask"
                },
                {
                  "kind": "lookup_slack_entity",
                  "description": "Look up a Slack user or channel by name or ID.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-05-17"
        },
        {
          "version": "0.2.0",
          "integrity": "sha512-rg/Md77UMQCKGiCLYHOF1ecTPAtU35VIkLF7sRDZNtYAj5YjKPzi19DZ+a05ezPWn2BCMtujrJT7nYm4bQvW8w==",
          "permissions": {
            "network": [
              "slack.com"
            ],
            "env": [
              {
                "key": "SLACK_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "xoxb-... bot token from your Slack app. Needs scopes: chat:write, im:write (for DMs), reactions:write, users:read, users:read.email (for email lookup), channels:read, groups:read (for channel lookup)."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_slack_message",
                  "description": "Post a message to a Slack channel.",
                  "default_mode": "auto"
                },
                {
                  "kind": "send_slack_dm",
                  "description": "Send a direct message to a Slack user. `user` may be a name, email, or Slack id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "react_slack_message",
                  "description": "Add an emoji reaction to a Slack message.",
                  "default_mode": "auto"
                },
                {
                  "kind": "lookup_slack_entity",
                  "description": "Look up a Slack user or channel by name or ID.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-05-24"
        },
        {
          "version": "0.4.0",
          "integrity": "sha512-oRknzVVbidkkl2c1p46IEGgG26cs0w9gGFEkZ6Q8yIcak+IOIp04GeA4Iyd6a0RDDDT+3Z2QEX7oGQcA0TVLog==",
          "permissions": {
            "network": [
              "slack.com"
            ],
            "env": [
              {
                "key": "SLACK_BOT_TOKEN",
                "required": true,
                "secret": true,
                "description": "xoxb-... bot token from your Slack app. Scopes: chat:write, im:write, im:history (DMs), app_mentions:read (mentions), reactions:write, users:read, users:read.email (email lookup), channels:read, groups:read (channel lookup)."
              },
              {
                "key": "SLACK_APP_TOKEN",
                "required": false,
                "secret": true,
                "description": "xapp-... app-level token with connections:write. Enables inbound (DMs, @-mentions, slash commands) over Socket Mode. Omit for outbound/action-only installs."
              },
              {
                "key": "SLACK_SIGNING_SECRET",
                "required": false,
                "secret": true,
                "description": "Slack signing secret — only for the legacy webhook ingress; Socket Mode (the default) doesn't use it."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_slack_message",
                  "description": "Post a message to a Slack channel.",
                  "default_mode": "auto"
                },
                {
                  "kind": "send_slack_dm",
                  "description": "Send a direct message to a Slack user. `user` may be a name, email, or Slack id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "react_slack_message",
                  "description": "Add an emoji reaction to a Slack message.",
                  "default_mode": "auto"
                },
                {
                  "kind": "lookup_slack_entity",
                  "description": "Look up a Slack user or channel by name or ID.",
                  "default_mode": "auto"
                }
              ]
            },
            "channel": {
              "providerLabel": "Slack",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "socket",
              "profile": {
                "modalities": [
                  "text",
                  "visual"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": true,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-15"
        },
        {
          "version": "0.5.0",
          "integrity": "sha512-SMNIMM27wyYHZgW2J8tXfOIi7i/3W350g2Zr663QD1V26o+I4EC7at0T9uVWrmAujdSpI4jDE5aBH8WWPUYu3g==",
          "permissions": {
            "network": [
              "slack.com"
            ],
            "env": [
              {
                "key": "SLACK_BOT_TOKEN",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "xoxb-... bot token from your Slack app. Scopes: chat:write, im:write, im:history (DMs), app_mentions:read (mentions), reactions:write, users:read, users:read.email (email lookup), channels:read, groups:read (channel lookup)."
              },
              {
                "key": "SLACK_SIGNING_SECRET",
                "required": false,
                "secret": true,
                "description": "Slack app signing secret - verifies inbound webhook requests (X-Slack-Signature over v0:<ts>:<body>). Only needed for webhook ingress; Socket Mode (the default) doesn't use it."
              },
              {
                "key": "SLACK_APP_TOKEN",
                "required": false,
                "secret": true,
                "inject": "egress",
                "description": "xapp-... app-level token with connections:write. Enables inbound (DMs, @-mentions, slash commands) over Socket Mode. Omit for outbound/action-only installs. Subscribe bot events message.im + app_mention and add a /openneko slash command in the Slack app."
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_slack_message",
                  "description": "Post a message to a Slack channel.",
                  "default_mode": "auto"
                },
                {
                  "kind": "send_slack_dm",
                  "description": "Send a direct message to a Slack user. `user` may be a name, email, or Slack id.",
                  "default_mode": "auto"
                },
                {
                  "kind": "react_slack_message",
                  "description": "Add an emoji reaction to a Slack message.",
                  "default_mode": "auto"
                },
                {
                  "kind": "lookup_slack_entity",
                  "description": "Look up a Slack user or channel by name or ID.",
                  "default_mode": "auto"
                }
              ]
            },
            "channel": {
              "providerLabel": "Slack",
              "directions": [
                "outbound",
                "inbound"
              ],
              "ingress": "socket",
              "profile": {
                "modalities": [
                  "text",
                  "visual"
                ],
                "richMedia": {
                  "markdown": true,
                  "cards": true,
                  "charts": false,
                  "images": true,
                  "interactiveControls": true
                },
                "interaction": {
                  "turnTaking": "async",
                  "canApproveInline": true,
                  "quickReplies": true
                },
                "constraints": {
                  "latencyClass": "interactive",
                  "attentionModel": "push"
                },
                "fidelity": "summary"
              }
            }
          },
          "publishedAt": "2026-06-26"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-magic-link",
      "title": "Magic-link sign-in",
      "description": "Passwordless email sign-in implementing OpenNeko's auth contract with manual provisioning: an admin creates each user (email + role) in OpenNeko first, and only those users can request a single-use, HMAC-signed sign-in link — possession of a mailbox never mints an account. Link delivery via Resend, Postmark, or SendGrid, selected by which API key is configured.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/magic-link",
      "homepage": "https://github.com/open-neko/plugins/tree/main/packages/magic-link",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.1.0",
          "integrity": "sha512-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
          "draft": true,
          "permissions": {
            "network": [
              "api.resend.com",
              "api.postmarkapp.com",
              "api.sendgrid.com"
            ],
            "env": [
              {
                "key": "MAGIC_LINK_SIGNING_SECRET",
                "required": true,
                "secret": true,
                "autogenerate": true,
                "description": "HMAC key that signs each sign-in token. Generated and stored by the host automatically — never prompted, never seen. Deleting the stored value and restarting rotates it, which invalidates every outstanding link."
              },
              {
                "key": "MAGIC_LINK_FROM",
                "required": true,
                "secret": false,
                "description": "From address for the sign-in email, e.g. \"OpenNeko <signin@company.com>\". Must be a sender verified with your email provider."
              },
              {
                "key": "RESEND_API_KEY",
                "required": false,
                "secret": true,
                "description": "Resend API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY — it selects the delivery provider."
              },
              {
                "key": "POSTMARK_SERVER_TOKEN",
                "required": false,
                "secret": true,
                "description": "Postmark server token. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "SENDGRID_API_KEY",
                "required": false,
                "secret": true,
                "description": "SendGrid API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "MAGIC_LINK_TTL_SECONDS",
                "required": false,
                "secret": false,
                "description": "Sign-in link lifetime in seconds, 60–600. Defaults to 600 (10 minutes) — the core's state cookie expires then anyway, so longer values buy nothing."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Email link",
              "provisioning": "manual",
              "loginHintRequired": true
            }
          },
          "publishedAt": "2026-08-15"
        },
        {
          "version": "0.3.0",
          "integrity": "sha512-1fTyvpl5sPt7BKFXlG+4oTgMWbrBDU/Ry6TllDbzItMi0yeeSqBkk2WHEIZ99ugSQgufvSMWEg/7OoUws/Qe3A==",
          "permissions": {
            "network": [
              "api.resend.com",
              "api.postmarkapp.com",
              "api.sendgrid.com"
            ],
            "env": [
              {
                "key": "MAGIC_LINK_SIGNING_SECRET",
                "required": true,
                "secret": true,
                "autogenerate": true,
                "description": "HMAC key that signs each sign-in token. Generated and stored by the host automatically — never prompted, never seen. Deleting the stored value and restarting rotates it, which invalidates every outstanding link."
              },
              {
                "key": "MAGIC_LINK_FROM",
                "required": true,
                "secret": false,
                "description": "From address for the sign-in email, e.g. \"OpenNeko <signin@company.com>\". Must be a sender verified with your email provider."
              },
              {
                "key": "RESEND_API_KEY",
                "required": false,
                "secret": true,
                "description": "Resend API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY — it selects the delivery provider."
              },
              {
                "key": "POSTMARK_SERVER_TOKEN",
                "required": false,
                "secret": true,
                "description": "Postmark server token. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "SENDGRID_API_KEY",
                "required": false,
                "secret": true,
                "description": "SendGrid API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "MAGIC_LINK_TTL_SECONDS",
                "required": false,
                "secret": false,
                "description": "Sign-in link lifetime in seconds, 60–600. Defaults to 600 (10 minutes) — the core's state cookie expires then anyway, so longer values buy nothing."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Email link",
              "provisioning": "manual",
              "loginHintRequired": true
            }
          },
          "publishedAt": "2026-09-16",
          "draft": true
        },
        {
          "version": "0.3.1",
          "integrity": "sha512-BBHQ8L6q7shZgaP2CuQgIp8i82QqDOsq9MjBnTmCKcUYv60jJqmN6ehl2b0W4pcIjVipEk763j71QiRp4RCaCA==",
          "permissions": {
            "network": [
              "api.resend.com",
              "api.postmarkapp.com",
              "api.sendgrid.com"
            ],
            "env": [
              {
                "key": "MAGIC_LINK_SIGNING_SECRET",
                "required": true,
                "secret": true,
                "autogenerate": true,
                "description": "HMAC key that signs each sign-in token. The host generates and stores it for you, and never shows it. Delete the stored value and restart to rotate it, which invalidates every outstanding link."
              },
              {
                "key": "MAGIC_LINK_FROM",
                "required": true,
                "secret": false,
                "description": "From address for the sign-in email, e.g. \"OpenNeko <signin@company.com>\". Must be a sender verified with your email provider."
              },
              {
                "key": "RESEND_API_KEY",
                "required": false,
                "secret": true,
                "description": "Resend API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY. The key you set selects the delivery provider."
              },
              {
                "key": "POSTMARK_SERVER_TOKEN",
                "required": false,
                "secret": true,
                "description": "Postmark server token. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "SENDGRID_API_KEY",
                "required": false,
                "secret": true,
                "description": "SendGrid API key. Set exactly one of RESEND_API_KEY, POSTMARK_SERVER_TOKEN, or SENDGRID_API_KEY."
              },
              {
                "key": "MAGIC_LINK_TTL_SECONDS",
                "required": false,
                "secret": false,
                "description": "Sign-in link lifetime in seconds, 60 to 600. The default is 600, which is 10 minutes. The state cookie expires then anyway, so a longer value buys nothing."
              }
            ]
          },
          "capabilities": {
            "auth": {
              "providerLabel": "Email link",
              "provisioning": "manual",
              "loginHintRequired": true
            }
          },
          "publishedAt": "2026-09-16"
        }
      ]
    },
    {
      "name": "@open-neko/plugin-resend",
      "title": "Resend operational email",
      "description": "Operational email through Resend. The agent sends an email from a Resend template, from Markdown in a house layout with your logo and color, or from HTML, and checks delivery status. Operators design alert emails in plain language; the agent asks how to show the content and saves the layout in the workflow. Approval rules match the real recipient domains. Four actions: send_email, list_email_templates, get_email_template, get_email_status.",
      "source": "https://github.com/open-neko/plugins/tree/main/packages/resend",
      "homepage": "https://resend.com/docs/api-reference/emails/send-email",
      "maintainers": [
        {
          "name": "open-neko",
          "url": "https://github.com/open-neko"
        }
      ],
      "versions": [
        {
          "version": "0.2.0",
          "integrity": "sha512-9S2m56S/k0akOsPf1oaEM6JIlCs7VSV04BOggjJOwcAB2QZ9mh8ai6sIaT5ky+0vTiOWpyUOlsH6ATSQQ4pa1w==",
          "permissions": {
            "network": [
              "api.resend.com"
            ],
            "env": [
              {
                "key": "RESEND_API_KEY",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "Resend API key (starts with re_). Create it at resend.com → API Keys with Sending access, or Full access to also list templates. The gateway holds the key; the plugin sandbox never sees it."
              },
              {
                "key": "RESEND_FROM",
                "required": true,
                "secret": false,
                "description": "Sender for every email, e.g. \"Acme Ops <ops@mail.acme.com>\". The domain must be verified in Resend. The agent cannot change it."
              },
              {
                "key": "RESEND_REPLY_TO",
                "required": false,
                "secret": false,
                "description": "Default reply-to address. The agent can set another one per email."
              },
              {
                "key": "RESEND_ALLOWED_RECIPIENTS",
                "required": false,
                "secret": false,
                "description": "Comma-separated recipient domains, e.g. \"acme.com, *.acme.com, partner.com\". When set, the plugin refuses any other recipient, even on an approved email."
              },
              {
                "key": "RESEND_LOGO_URL",
                "required": false,
                "secret": false,
                "description": "HTTPS URL of the logo at the top of the house layout (Markdown emails only)."
              },
              {
                "key": "RESEND_BRAND_COLOR",
                "required": false,
                "secret": false,
                "description": "Hex color for links and the top border in the house layout, e.g. #1f6feb."
              },
              {
                "key": "RESEND_FOOTER_TEXT",
                "required": false,
                "secret": false,
                "description": "One line at the bottom of the house layout, e.g. \"Sent by OpenNeko for Acme Operations.\""
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_email",
                  "description": "Send one email. Give to (and optional cc, bcc), a subject, and exactly one body: template (a Resend template id or alias with variables), markdown (rendered in the house layout), or html.",
                  "default_mode": "ask",
                  "targets": {
                    "fields": [
                      "to",
                      "cc",
                      "bcc"
                    ],
                    "as": "email_domain"
                  }
                },
                {
                  "kind": "list_email_templates",
                  "description": "List the published Resend templates: id, alias, and name.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_email_template",
                  "description": "Get one Resend template by id or alias: its subject and the variable keys it expects.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_email_status",
                  "description": "Get the delivery status of a sent email by the id that send_email returned, e.g. delivered, bounced, or opened.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-09-29",
          "provenanceWaived": true
        },
        {
          "version": "0.2.1",
          "integrity": "sha512-vlsF5nIxS1/CbZ8JTKPlEd7tIbilCCX7S4dBBOuBD5BsuvtqyFjtox0rjOqkq+ObcguYuHNp1tUwCNANIcJ8Fg==",
          "permissions": {
            "network": [
              "api.resend.com"
            ],
            "env": [
              {
                "key": "RESEND_API_KEY",
                "required": true,
                "secret": true,
                "inject": "egress",
                "description": "Resend API key (starts with re_). Create it at resend.com → API Keys with Sending access, or Full access to also list templates. The gateway holds the key; the plugin sandbox never sees it."
              },
              {
                "key": "RESEND_FROM",
                "required": true,
                "secret": false,
                "description": "Sender for every email, e.g. \"Acme Ops <ops@mail.acme.com>\". The domain must be verified in Resend. The agent cannot change it."
              },
              {
                "key": "RESEND_REPLY_TO",
                "required": false,
                "secret": false,
                "description": "Default reply-to address. The agent can set another one per email."
              },
              {
                "key": "RESEND_ALLOWED_RECIPIENTS",
                "required": false,
                "secret": false,
                "description": "Comma-separated recipient domains, e.g. \"acme.com, *.acme.com, partner.com\". When set, the plugin refuses any other recipient, even on an approved email."
              },
              {
                "key": "RESEND_LOGO_URL",
                "required": false,
                "secret": false,
                "description": "HTTPS URL of the logo at the top of the house layout (Markdown emails only)."
              },
              {
                "key": "RESEND_BRAND_COLOR",
                "required": false,
                "secret": false,
                "description": "Hex color for links and the top border in the house layout, e.g. #1f6feb."
              },
              {
                "key": "RESEND_FOOTER_TEXT",
                "required": false,
                "secret": false,
                "description": "One line at the bottom of the house layout, e.g. \"Sent by OpenNeko for Acme Operations.\""
              }
            ]
          },
          "capabilities": {
            "action": {
              "kinds": [
                {
                  "kind": "send_email",
                  "description": "Send one email. Give to (and optional cc, bcc), a subject, and exactly one body: template (a Resend template id or alias with variables), markdown (rendered in the house layout), or html.",
                  "default_mode": "ask",
                  "targets": {
                    "fields": [
                      "to",
                      "cc",
                      "bcc"
                    ],
                    "as": "email_domain"
                  }
                },
                {
                  "kind": "list_email_templates",
                  "description": "List the published Resend templates: id, alias, and name.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_email_template",
                  "description": "Get one Resend template by id or alias: its subject and the variable keys it expects.",
                  "default_mode": "auto"
                },
                {
                  "kind": "get_email_status",
                  "description": "Get the delivery status of a sent email by the id that send_email returned, e.g. delivered, bounced, or opened.",
                  "default_mode": "auto"
                }
              ]
            }
          },
          "publishedAt": "2026-09-29"
        }
      ]
    }
  ]
}
marketplace.schema.json GET https://open-neko.github.io/plugins/marketplace.schema.json · 15.0 KB
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://open-neko.github.io/plugins/marketplace.schema.json",
  "title": "OpenNeko plugin marketplace",
  "description": "Single-file catalog of plugins, modeled on Claude Code's marketplace.json plus the security fields the OpenNeko CLI enforces (integrity, permissions, capabilities). Publish your own marketplace.json at a stable URL and operators can trust it with `openneko marketplace add <url>`.",
  "type": "object",
  "required": ["name", "owner", "description", "plugins"],
  "additionalProperties": true,
  "properties": {
    "$schema": { "type": "string" },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80,
      "description": "Human-readable name. Shown when the operator adds this marketplace."
    },
    "owner": {
      "type": "string",
      "minLength": 1,
      "description": "GitHub org / individual / company that publishes this marketplace."
    },
    "homepage": { "type": "string", "format": "uri" },
    "description": {
      "type": "string",
      "minLength": 10,
      "maxLength": 800
    },
    "plugins": {
      "type": "array",
      "items": { "$ref": "#/$defs/plugin" }
    }
  },
  "$defs": {
    "plugin": {
      "type": "object",
      "required": ["name", "title", "description", "source", "versions"],
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^(@[a-z0-9-]+/)?[a-z0-9][a-z0-9-_]*$",
          "description": "npm package name."
        },
        "title": { "type": "string", "minLength": 3, "maxLength": 80 },
        "description": { "type": "string", "minLength": 10, "maxLength": 800 },
        "source": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://(github\\.com|gitlab\\.com|codeberg\\.org)/"
        },
        "homepage": { "type": "string", "format": "uri" },
        "maintainers": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "required": ["name"],
            "additionalProperties": false,
            "properties": {
              "name": { "type": "string" },
              "url": { "type": "string", "format": "uri" }
            }
          }
        },
        "versions": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/$defs/version" }
        }
      }
    },
    "version": {
      "type": "object",
      "required": ["version", "integrity", "permissions", "capabilities", "publishedAt"],
      "additionalProperties": false,
      "properties": {
        "version": {
          "type": "string",
          "pattern": "^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?$",
          "description": "Pinned semver — no ranges."
        },
        "integrity": {
          "type": "string",
          "pattern": "^sha512-[A-Za-z0-9+/=]+$",
          "description": "Pinned npm dist.integrity hash. Use the all-`a` placeholder pattern ONLY in combination with `draft: true` while the package is still pre-publish."
        },
        "permissions": { "$ref": "#/$defs/permissions" },
        "capabilities": { "$ref": "#/$defs/capabilities" },
        "publishedAt": { "type": "string", "format": "date" },
        "yanked": { "type": "boolean", "default": false },
        "yanked_reason": { "type": "string" },
        "draft": {
          "type": "boolean",
          "default": false,
          "description": "Set to true when the version isn't on npm yet (chicken-and-egg case for a brand-new package whose first publish hasn't fired). `validate-live` skips every live check for draft entries — they're treated as informational. Flip to false and pin the real integrity hash once the publish workflow has succeeded."
        },
        "provenanceWaived": {
          "type": "boolean",
          "default": false,
          "description": "Set to true for legacy versions that were published before the publish workflow started using --provenance. `validate-live` still enforces integrity but skips the provenance check. Don't use on new versions — bump and re-publish with --provenance instead."
        }
      }
    },
    "permissions": {
      "type": "object",
      "description": "What the plugin needs from the runtime: outbound network hosts and operator-supplied env vars. Same shape lives in the installed manifest entry.",
      "additionalProperties": false,
      "properties": {
        "network": {
          "type": "array",
          "default": [],
          "items": {
            "type": "string",
            "pattern": "^[a-z0-9*]([a-z0-9-.*])*[a-z0-9*]$"
          },
          "description": "Hostnames the sandbox is allowed to reach. Enforced at the VM boundary."
        },
        "env": {
          "type": "array",
          "default": [],
          "items": { "$ref": "#/$defs/envRequirement" },
          "description": "Env vars the operator must supply. `openneko install` prompts for required ones and refuses to complete if missing."
        }
      }
    },
    "envRequirement": {
      "type": "object",
      "required": ["key", "description"],
      "additionalProperties": false,
      "properties": {
        "key": {
          "type": "string",
          "pattern": "^[A-Z][A-Z0-9_]*$",
          "maxLength": 64,
          "description": "UPPER_SNAKE_CASE env var name the plugin reads."
        },
        "required": { "type": "boolean", "default": true },
        "secret": {
          "type": "boolean",
          "default": true,
          "description": "Hide the value at prompt; the CLI will not echo it back."
        },
        "inject": {
          "enum": ["egress", "box"],
          "description": "How a secret reaches the plugin VM. 'egress': held gateway-side and substituted by the proxy onto outbound requests — the box sees only a placeholder (for credentials sent to an external API, e.g. a bot token). 'box' (default): the value lives in the VM, for secrets compared locally and never sent out (e.g. a webhook signing secret)."
        },
        "autogenerate": {
          "type": "boolean",
          "default": false,
          "description": "The host mints this value itself (48 random bytes, base64url) at install/load and stores it in the secrets file — the operator is never prompted and never sees it. For purely internal secrets like HMAC signing keys."
        },
        "description": {
          "type": "string",
          "minLength": 1,
          "maxLength": 280
        }
      }
    },
    "capabilities": {
      "type": "object",
      "description": "Surfaces this plugin contributes. The keyset declares what the plugin does — `action`, `auth`, and/or `connect`. At least one must be present.",
      "additionalProperties": false,
      "minProperties": 1,
      "properties": {
        "action": {
          "type": "object",
          "description": "The plugin contributes one or more named action handlers.",
          "required": ["kinds"],
          "additionalProperties": false,
          "properties": {
            "kinds": {
              "type": "array",
              "minItems": 1,
              "items": { "$ref": "#/$defs/actionDeclaration" }
            }
          }
        },
        "auth": {
          "type": "object",
          "description": "The plugin acts as the SSO provider. Singleton — only one installed plugin may declare this.",
          "additionalProperties": false,
          "properties": {
            "providerLabel": {
              "type": "string",
              "minLength": 1,
              "description": "Short label rendered on the sign-in button (e.g. \"Scalekit\", \"Okta\")."
            },
            "provisioning": {
              "type": "string",
              "enum": ["automatic", "manual"],
              "default": "automatic",
              "description": "automatic: IdP-attested identity — the core may create an app_user on first sign-in. manual: self-asserted identity (e.g. magic link) — the core only signs in users an admin pre-provisioned and silently drops unknown emails."
            },
            "loginHintRequired": {
              "type": "boolean",
              "default": false,
              "description": "begin_auth is unusable without a loginHint (e.g. magic link needs the email). The sign-in page requires the email field and the begin route rejects hint-less requests."
            }
          }
        },
        "connect": {
          "type": "object",
          "description": "The plugin offers a per-operator OAuth connector. Non-singleton — any number of installed plugins may declare this, and each operator connects independently. Credentials land in the per-operator section of the secrets store.",
          "required": ["providerLabel", "scopes"],
          "additionalProperties": false,
          "properties": {
            "providerLabel": {
              "type": "string",
              "minLength": 1,
              "description": "Display label shown on the Connect button + status row (e.g. \"Google Workspace\", \"GitHub\")."
            },
            "scopes": {
              "type": "array",
              "minItems": 1,
              "items": { "type": "string", "minLength": 1, "maxLength": 256 },
              "description": "OAuth scopes the connector will request at consent time."
            },
            "flow": {
              "type": "string",
              "enum": ["oauth2-pkce", "mcp-oauth"],
              "default": "oauth2-pkce",
              "description": "Flow type the worker should drive. oauth2-pkce: pre-registered client, core-minted code_verifier. mcp-oauth: the plugin does MCP-OAuth-2.1 discovery + DCR and bridges begin → complete via the oauthState echo."
            },
            "credentialScope": {
              "type": "string",
              "enum": ["operator", "deployment"],
              "default": "operator",
              "description": "operator: per-operator credentials. deployment: one org-wide credential consented by an admin, injected on every action call and stored under a reserved secrets slot."
            }
          }
        },
        "channel": {
          "type": "object",
          "description": "The plugin is a frontend (channel) — Slack, Telegram, voice, etc. Non-singleton; the worker projects modality-free InteractionEvents into the substrate inside the plugin VM and normalizes inbound payloads back into agent intents.",
          "required": ["providerLabel", "profile", "directions"],
          "additionalProperties": false,
          "properties": {
            "providerLabel": {
              "type": "string",
              "minLength": 1,
              "description": "Display label for the channel (e.g. \"Telegram\", \"Slack\")."
            },
            "directions": {
              "type": "array",
              "minItems": 1,
              "items": { "type": "string", "enum": ["inbound", "outbound"] },
              "description": "Which directions the channel supports."
            },
            "ingress": {
              "type": "string",
              "enum": ["webhook", "socket", "none"],
              "default": "none",
              "description": "How inbound arrives: an HTTP webhook, a persistent socket, or none (outbound-only)."
            },
            "profile": { "$ref": "#/$defs/capabilityProfile" }
          }
        },
        "directory": {
          "type": "object",
          "description": "Lists the identity provider's users, groups and group memberships. Singleton per deployment.",
          "required": ["providerLabel"],
          "additionalProperties": false,
          "properties": {
            "providerLabel": { "type": "string", "minLength": 1 },
            "read": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "users": { "type": "boolean" },
                "groups": { "type": "boolean" },
                "memberships": { "type": "boolean" }
              }
            },
            "write": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "createUser": { "type": "boolean" },
                "deactivateUser": { "type": "boolean" }
              }
            }
          }
        }
      }
    },
    "capabilityProfile": {
      "type": "object",
      "description": "What the substrate can carry — the only thing a projection may branch on. Additive: new fields default such that existing channels are unaffected, so unknown properties are tolerated.",
      "required": ["modalities", "richMedia", "interaction", "constraints", "fidelity"],
      "properties": {
        "modalities": {
          "type": "array",
          "minItems": 1,
          "items": { "type": "string", "enum": ["text", "visual", "voice", "haptic", "neural"] }
        },
        "richMedia": { "type": "object" },
        "interaction": { "type": "object" },
        "constraints": { "type": "object" },
        "fidelity": { "type": "string", "enum": ["headline", "summary", "full"] }
      }
    },
    "actionDeclaration": {
      "type": "object",
      "required": ["kind", "description"],
      "additionalProperties": false,
      "properties": {
        "kind": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_]*$",
          "description": "Snake_case action identifier."
        },
        "description": {
          "type": "string",
          "minLength": 1,
          "description": "Short description the agent uses to pick this kind."
        },
        "default_mode": {
          "description": "Seeded approval policy when the plugin is freshly installed. auto = run inline with no human gate (read-only kinds). ask = suspend agent turn, render approval card to the user (externally observable kinds). deny = never invokable without explicit opt-in. Operators can override later in /settings/rules. Defaults to ask when omitted — safer to surprise the user with a prompt than a side effect. Accepts either a scalar (applies to all scopes) or a per-scope object {external?, internal?} when the kind needs different defaults depending on the scope it's invoked under.",
          "oneOf": [
            { "type": "string", "enum": ["auto", "ask", "deny"] },
            {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "external": { "type": "string", "enum": ["auto", "ask", "deny"] },
                "internal": { "type": "string", "enum": ["auto", "ask", "deny"] }
              }
            }
          ]
        },
        "targets": {
          "description": "Payload fields that hold the action's targets. The host reads the targets from these fields, so approval rules match where the action really goes. value: each value as written. email_domain: the lowercase domain of each email address.",
          "type": "object",
          "required": ["fields"],
          "additionalProperties": false,
          "properties": {
            "fields": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } },
            "as": { "type": "string", "enum": ["value", "email_domain"] }
          }
        }
      }
    }
  }
}