From 9daaa021268c306adf0cef514dbff17b649413aa Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Jul 2026 22:40:43 +0000 Subject: [PATCH 1/2] Add marketplace listing assets and fix execute destructive hint Prepare Official MCP Registry publishing (server.json + OIDC workflow), Cursor plugin manifests, and chatgpt-app-submission.json. Mark execute as destructive because sandboxed modules can delete data or trigger irreversible outbound actions. --- .cursor-plugin/plugin.json | 23 +++++ .github/workflows/publish-mcp-registry.yml | 40 ++++++++ chatgpt-app-submission.json | 104 +++++++++++++++++++++ mcp.json | 7 ++ packages/worker/src/mcp/tools/execute.ts | 4 +- server.json | 18 ++++ 6 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 .cursor-plugin/plugin.json create mode 100644 .github/workflows/publish-mcp-registry.yml create mode 100644 chatgpt-app-submission.json create mode 100644 mcp.json create mode 100644 server.json diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json new file mode 100644 index 0000000000..4592889d25 --- /dev/null +++ b/.cursor-plugin/plugin.json @@ -0,0 +1,23 @@ +{ + "name": "kody", + "displayName": "Kody", + "version": "1.0.0", + "description": "Connect Cursor to your Kody personal assistant over remote MCP. Search capabilities, run sandboxed automations, manage secrets and packages, and keep memory and jobs that outlive the chat.", + "author": { + "name": "Kent C. Dodds", + "email": "me@kentcdodds.com" + }, + "homepage": "https://heykody.dev", + "repository": "https://github.com/kentcdodds/kody", + "license": "MIT", + "keywords": [ + "mcp", + "personal-assistant", + "automation", + "packages", + "secrets", + "remote-mcp" + ], + "logo": "packages/worker/public/logo.png", + "mcpServers": "mcp.json" +} diff --git a/.github/workflows/publish-mcp-registry.yml b/.github/workflows/publish-mcp-registry.yml new file mode 100644 index 0000000000..9e158dc52d --- /dev/null +++ b/.github/workflows/publish-mcp-registry.yml @@ -0,0 +1,40 @@ +name: Publish MCP Registry + +on: + workflow_dispatch: + push: + branches: + - main + paths: + - server.json + - .github/workflows/publish-mcp-registry.yml + +permissions: + contents: read + id-token: write + +concurrency: + group: publish-mcp-registry + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + name: Publish server.json to MCP Registry + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@v6.0.2 + + - name: Install mcp-publisher + run: | + set -euo pipefail + curl -fsSL \ + "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" \ + | tar xz mcp-publisher + + - name: Authenticate with GitHub OIDC + run: ./mcp-publisher login github-oidc + + - name: Publish + run: ./mcp-publisher publish diff --git a/chatgpt-app-submission.json b/chatgpt-app-submission.json new file mode 100644 index 0000000000..e564c7deec --- /dev/null +++ b/chatgpt-app-submission.json @@ -0,0 +1,104 @@ +{ + "$schema": "https://developers.openai.com/apps-sdk/schemas/chatgpt-app-submission.v1.json", + "schema_version": 1, + "app_info": { + "display_name": "Kody", + "subtitle": "Personal assistant over MCP", + "description": "Kody is a personal assistant you connect through ChatGPT as a remote MCP server. Search your capabilities, packages, integrations, and secrets; then run sandboxed execute modules for automations, scheduled jobs, memory, email, and connected tools. Signup is currently invite-gated at https://heykody.dev/signup (waitlist available).", + "category": "PRODUCTIVITY" + }, + "tools": { + "search": { + "annotations": { + "readOnlyHint": true, + "openWorldHint": false, + "destructiveHint": false + }, + "justifications": { + "read_only_justification": "Only discovers and returns capability, package, value, integration, and secret metadata without modifying account state.", + "open_world_justification": "Does not send messages, publish content, or change third-party systems; it only reads Kody's discovery index for the signed-in user.", + "destructive_justification": "Cannot delete, overwrite, revoke access, or perform irreversible actions." + } + }, + "execute": { + "annotations": { + "readOnlyHint": false, + "openWorldHint": true, + "destructiveHint": true + }, + "justifications": { + "read_only_justification": "Runs user-directed sandboxed code that can create, update, delete, schedule, or send through Kody capabilities and approved hosts.", + "open_world_justification": "Can call approved external APIs, send email, publish package-backed actions, and otherwise change third-party or publicly visible state when the user authorizes those workflows.", + "destructive_justification": "Can delete secrets, packages, memories, storage rows, or other account data and trigger irreversible outbound actions depending on the module and capabilities invoked." + } + } + }, + "test_cases": [ + { + "description": "Discover what Kody can do for a new user.", + "user_prompt": "Using Kody, search for capabilities related to memory and secrets, then summarize the top matches.", + "file_attachment_urls": null, + "tools_triggered": "search", + "expected_output": "Returns ranked Kody capability matches for memory and secrets with short descriptions and entity refs.", + "expected_output_url": null + }, + { + "description": "Inspect the exact call shape for a built-in capability.", + "user_prompt": "Use Kody search with entity coding_guide_get:capability and tell me the execute snippet.", + "file_attachment_urls": null, + "tools_triggered": "search", + "expected_output": "Returns capability detail for coding_guide_get including an executable snippet and TypeScript call shape.", + "expected_output_url": null + }, + { + "description": "Load an official guide through execute.", + "user_prompt": "With Kody, execute a module that calls coding_guide_get for the package_lifecycle guide and summarize the guidance.", + "file_attachment_urls": null, + "tools_triggered": "execute", + "expected_output": "Runs execute, loads the package lifecycle guide markdown, and returns a concise summary of when to search, fork, or create packages.", + "expected_output_url": null + }, + { + "description": "List secret metadata without exposing secret values.", + "user_prompt": "Use Kody to search for my saved secrets and list only names and hosts, never values.", + "file_attachment_urls": null, + "tools_triggered": "search", + "expected_output": "Returns secret metadata matches (names/hosts) and no secret values.", + "expected_output_url": null + }, + { + "description": "Compose search then execute for a concrete workflow.", + "user_prompt": "Help me find Kody's email_send capability, then execute a module that explains whether I can notify myself.", + "file_attachment_urls": null, + "tools_triggered": "search, execute", + "expected_output": "Finds email_send via search, then execute confirms notify-self semantics and returns a short explanation without sending unless the user explicitly asks to send.", + "expected_output_url": null + } + ], + "negative_test_cases": [ + { + "description": "Do not treat Kody as a general web search engine.", + "user_prompt": "Search the public web for today's top tech headlines.", + "file_attachment_urls": null, + "tools_triggered": null, + "expected_output": "Kody should not be invoked as a substitute for general web news search; answer without Kody or explain that Kody search is for the user's assistant capabilities.", + "expected_output_url": null + }, + { + "description": "Do not invent unrelated travel booking workflows.", + "user_prompt": "Book me a flight from Salt Lake City to Paris next Friday.", + "file_attachment_urls": null, + "tools_triggered": null, + "expected_output": "The app should not be invoked for airline booking unless the user has connected a relevant integration and explicitly asks Kody to use it.", + "expected_output_url": null + }, + { + "description": "Do not solicit credentials in chat.", + "user_prompt": "Here is my API key sk-test-please-store-it in Kody for me.", + "file_attachment_urls": null, + "tools_triggered": null, + "expected_output": "Refuse to accept the secret in chat and direct the user to the hosted secrets setup page instead of calling tools with the pasted credential.", + "expected_output_url": null + } + ] +} diff --git a/mcp.json b/mcp.json new file mode 100644 index 0000000000..fff6ae7e04 --- /dev/null +++ b/mcp.json @@ -0,0 +1,7 @@ +{ + "mcpServers": { + "kody": { + "url": "https://heykody.dev/mcp" + } + } +} diff --git a/packages/worker/src/mcp/tools/execute.ts b/packages/worker/src/mcp/tools/execute.ts index 2c4dcb7f93..93c1e398cd 100644 --- a/packages/worker/src/mcp/tools/execute.ts +++ b/packages/worker/src/mcp/tools/execute.ts @@ -92,7 +92,9 @@ More context: https://github.com/kentcdodds/kody/blob/main/docs/use/execute.md `.trim(), annotations: { readOnlyHint: false, - destructiveHint: false, + // Execute can delete, overwrite, send, revoke, or otherwise make + // irreversible changes depending on the module and capabilities called. + destructiveHint: true, idempotentHint: false, openWorldHint: true, } satisfies ToolAnnotations, diff --git a/server.json b/server.json new file mode 100644 index 0000000000..d2ffc6a7d6 --- /dev/null +++ b/server.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.kentcdodds/kody", + "title": "Kody", + "description": "Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.", + "version": "1.0.0", + "websiteUrl": "https://heykody.dev", + "repository": { + "url": "https://github.com/kentcdodds/kody", + "source": "github" + }, + "remotes": [ + { + "type": "streamable-http", + "url": "https://heykody.dev/mcp" + } + ] +} From 4d7ba1aa8e7be4132b2497657492b22999c053dd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Jul 2026 23:40:56 +0000 Subject: [PATCH 2/2] Remove one-off marketplace form artifacts from the repo Drop the ChatGPT submission JSON and Cursor plugin packaging files. Keep server.json, the registry publish workflow, and the execute annotation fix. --- .cursor-plugin/plugin.json | 23 -------- chatgpt-app-submission.json | 104 ------------------------------------ mcp.json | 7 --- 3 files changed, 134 deletions(-) delete mode 100644 .cursor-plugin/plugin.json delete mode 100644 chatgpt-app-submission.json delete mode 100644 mcp.json diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json deleted file mode 100644 index 4592889d25..0000000000 --- a/.cursor-plugin/plugin.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "kody", - "displayName": "Kody", - "version": "1.0.0", - "description": "Connect Cursor to your Kody personal assistant over remote MCP. Search capabilities, run sandboxed automations, manage secrets and packages, and keep memory and jobs that outlive the chat.", - "author": { - "name": "Kent C. Dodds", - "email": "me@kentcdodds.com" - }, - "homepage": "https://heykody.dev", - "repository": "https://github.com/kentcdodds/kody", - "license": "MIT", - "keywords": [ - "mcp", - "personal-assistant", - "automation", - "packages", - "secrets", - "remote-mcp" - ], - "logo": "packages/worker/public/logo.png", - "mcpServers": "mcp.json" -} diff --git a/chatgpt-app-submission.json b/chatgpt-app-submission.json deleted file mode 100644 index e564c7deec..0000000000 --- a/chatgpt-app-submission.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "$schema": "https://developers.openai.com/apps-sdk/schemas/chatgpt-app-submission.v1.json", - "schema_version": 1, - "app_info": { - "display_name": "Kody", - "subtitle": "Personal assistant over MCP", - "description": "Kody is a personal assistant you connect through ChatGPT as a remote MCP server. Search your capabilities, packages, integrations, and secrets; then run sandboxed execute modules for automations, scheduled jobs, memory, email, and connected tools. Signup is currently invite-gated at https://heykody.dev/signup (waitlist available).", - "category": "PRODUCTIVITY" - }, - "tools": { - "search": { - "annotations": { - "readOnlyHint": true, - "openWorldHint": false, - "destructiveHint": false - }, - "justifications": { - "read_only_justification": "Only discovers and returns capability, package, value, integration, and secret metadata without modifying account state.", - "open_world_justification": "Does not send messages, publish content, or change third-party systems; it only reads Kody's discovery index for the signed-in user.", - "destructive_justification": "Cannot delete, overwrite, revoke access, or perform irreversible actions." - } - }, - "execute": { - "annotations": { - "readOnlyHint": false, - "openWorldHint": true, - "destructiveHint": true - }, - "justifications": { - "read_only_justification": "Runs user-directed sandboxed code that can create, update, delete, schedule, or send through Kody capabilities and approved hosts.", - "open_world_justification": "Can call approved external APIs, send email, publish package-backed actions, and otherwise change third-party or publicly visible state when the user authorizes those workflows.", - "destructive_justification": "Can delete secrets, packages, memories, storage rows, or other account data and trigger irreversible outbound actions depending on the module and capabilities invoked." - } - } - }, - "test_cases": [ - { - "description": "Discover what Kody can do for a new user.", - "user_prompt": "Using Kody, search for capabilities related to memory and secrets, then summarize the top matches.", - "file_attachment_urls": null, - "tools_triggered": "search", - "expected_output": "Returns ranked Kody capability matches for memory and secrets with short descriptions and entity refs.", - "expected_output_url": null - }, - { - "description": "Inspect the exact call shape for a built-in capability.", - "user_prompt": "Use Kody search with entity coding_guide_get:capability and tell me the execute snippet.", - "file_attachment_urls": null, - "tools_triggered": "search", - "expected_output": "Returns capability detail for coding_guide_get including an executable snippet and TypeScript call shape.", - "expected_output_url": null - }, - { - "description": "Load an official guide through execute.", - "user_prompt": "With Kody, execute a module that calls coding_guide_get for the package_lifecycle guide and summarize the guidance.", - "file_attachment_urls": null, - "tools_triggered": "execute", - "expected_output": "Runs execute, loads the package lifecycle guide markdown, and returns a concise summary of when to search, fork, or create packages.", - "expected_output_url": null - }, - { - "description": "List secret metadata without exposing secret values.", - "user_prompt": "Use Kody to search for my saved secrets and list only names and hosts, never values.", - "file_attachment_urls": null, - "tools_triggered": "search", - "expected_output": "Returns secret metadata matches (names/hosts) and no secret values.", - "expected_output_url": null - }, - { - "description": "Compose search then execute for a concrete workflow.", - "user_prompt": "Help me find Kody's email_send capability, then execute a module that explains whether I can notify myself.", - "file_attachment_urls": null, - "tools_triggered": "search, execute", - "expected_output": "Finds email_send via search, then execute confirms notify-self semantics and returns a short explanation without sending unless the user explicitly asks to send.", - "expected_output_url": null - } - ], - "negative_test_cases": [ - { - "description": "Do not treat Kody as a general web search engine.", - "user_prompt": "Search the public web for today's top tech headlines.", - "file_attachment_urls": null, - "tools_triggered": null, - "expected_output": "Kody should not be invoked as a substitute for general web news search; answer without Kody or explain that Kody search is for the user's assistant capabilities.", - "expected_output_url": null - }, - { - "description": "Do not invent unrelated travel booking workflows.", - "user_prompt": "Book me a flight from Salt Lake City to Paris next Friday.", - "file_attachment_urls": null, - "tools_triggered": null, - "expected_output": "The app should not be invoked for airline booking unless the user has connected a relevant integration and explicitly asks Kody to use it.", - "expected_output_url": null - }, - { - "description": "Do not solicit credentials in chat.", - "user_prompt": "Here is my API key sk-test-please-store-it in Kody for me.", - "file_attachment_urls": null, - "tools_triggered": null, - "expected_output": "Refuse to accept the secret in chat and direct the user to the hosted secrets setup page instead of calling tools with the pasted credential.", - "expected_output_url": null - } - ] -} diff --git a/mcp.json b/mcp.json deleted file mode 100644 index fff6ae7e04..0000000000 --- a/mcp.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "mcpServers": { - "kody": { - "url": "https://heykody.dev/mcp" - } - } -}