From fb667fd4d08e7bb118b60f2b40018baebc09ad48 Mon Sep 17 00:00:00 2001 From: Max Gerber <89937743+max-stytch@users.noreply.github.com> Date: Fri, 14 Mar 2025 16:16:31 -0700 Subject: [PATCH 01/20] fix: Prefer 127.0.0.1 over localhost --- bin/cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cli.js b/bin/cli.js index 94348fb..115e118 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -96,7 +96,7 @@ async function main() { await Promise.any([server, client, delay(2 * 1000)]); const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${SERVER_PORT}`; console.log( - `\nšŸ” MCP Inspector is up and running at http://localhost:${CLIENT_PORT}${portParam} šŸš€`, + `\nšŸ” MCP Inspector is up and running at http://127.0.0.1:${CLIENT_PORT}${portParam} šŸš€`, ); try { From cda3905e5a64ebd0c8c3072c852fc777b5d0fd80 Mon Sep 17 00:00:00 2001 From: Maxwell Gerber Date: Fri, 14 Mar 2025 16:33:39 -0700 Subject: [PATCH 02/20] fix: Update URL in CONTRIBUTING.md too --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ad5699..b225713 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Thanks for your interest in contributing! This guide explains how to get involve 1. Fork the repository and clone it locally 2. Install dependencies with `npm install` 3. Run `npm run dev` to start both client and server in development mode -4. Use the web UI at http://localhost:5173 to interact with the inspector +4. Use the web UI at http://127.0.0.1:5173 to interact with the inspector ## Development Process & Pull Requests From 536b7e0a99170b402fec55946b157642bb6f5e74 Mon Sep 17 00:00:00 2001 From: Maxwell Gerber Date: Tue, 18 Mar 2025 09:29:48 -0700 Subject: [PATCH 03/20] fix: Update vite host --- client/vite.config.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/vite.config.ts b/client/vite.config.ts index b3d0f45..c971d58 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -5,7 +5,9 @@ import { defineConfig } from "vite"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], - server: {}, + server: { + host: "127.0.0.1", + }, resolve: { alias: { "@": path.resolve(__dirname, "./src"), From 029e482e05a57f5610662d080c5aba59f2dd762c Mon Sep 17 00:00:00 2001 From: Nathan Arseneau Date: Wed, 19 Mar 2025 20:15:14 -0400 Subject: [PATCH 04/20] fix: set default value for input fields in ToolsTab component --- client/src/components/ToolsTab.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 777db80..dcfae44 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -229,6 +229,7 @@ const ToolsTab = ({ id={key} name={key} placeholder={prop.description} + value={(params[key] as string) ?? ""} onChange={(e) => setParams({ ...params, From dcbd1dad410dc8e6abb6e98cda17688a6c64ce4f Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Fri, 21 Mar 2025 06:54:46 -0700 Subject: [PATCH 05/20] Bump prismjs from 1.29.0 to 1.30.0 to address --- client/package.json | 2 +- package-lock.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/package.json b/client/package.json index 0471765..700bbee 100644 --- a/client/package.json +++ b/client/package.json @@ -38,7 +38,7 @@ "cmdk": "^1.0.4", "lucide-react": "^0.447.0", "pkce-challenge": "^4.1.0", - "prismjs": "^1.29.0", + "prismjs": "^1.30.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-simple-code-editor": "^0.14.1", diff --git a/package-lock.json b/package-lock.json index 21c9c30..1db7ef2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "cmdk": "^1.0.4", "lucide-react": "^0.447.0", "pkce-challenge": "^4.1.0", - "prismjs": "^1.29.0", + "prismjs": "^1.30.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-simple-code-editor": "^0.14.1", @@ -8841,9 +8841,9 @@ } }, "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", "engines": { "node": ">=6" From 210975e38531b68be7af1eae72dee7aa0c0c5ab0 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 12:44:30 -0700 Subject: [PATCH 06/20] Add test dependencies --- client/package.json | 4 +- package-lock.json | 272 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+), 1 deletion(-) diff --git a/client/package.json b/client/package.json index 0471765..c3e4ed3 100644 --- a/client/package.json +++ b/client/package.json @@ -24,8 +24,8 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.6.1", - "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-checkbox": "^1.1.4", + "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.1.0", "@radix-ui/react-popover": "^1.1.3", @@ -50,6 +50,8 @@ }, "devDependencies": { "@eslint/js": "^9.11.1", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.2.0", "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/react": "^18.3.10", diff --git a/package-lock.json b/package-lock.json index 68929c5..23bc2a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,8 @@ }, "devDependencies": { "@eslint/js": "^9.11.1", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.2.0", "@types/jest": "^29.5.14", "@types/node": "^22.7.5", "@types/react": "^18.3.10", @@ -87,6 +89,13 @@ "vite": "^5.4.8" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", + "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "dev": true, + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -576,6 +585,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", @@ -3786,6 +3808,148 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/jest-dom/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@testing-library/react": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.2.0.tgz", + "integrity": "sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -3820,6 +3984,14 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "license": "MIT" }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4585,6 +4757,16 @@ "node": ">=10" } }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -5331,6 +5513,13 @@ "node": ">= 8" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -5467,6 +5656,16 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -5524,6 +5723,14 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -6796,6 +7003,16 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -7984,6 +8201,17 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/make-dir": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", @@ -8137,6 +8365,16 @@ "node": ">=6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9151,6 +9389,27 @@ "node": ">=8.10.0" } }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9837,6 +10096,19 @@ "node": ">=6" } }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", From fc76a7c7d49cf2a05c70846387c8da6daabcb454 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 12:46:30 -0700 Subject: [PATCH 07/20] Add setup file and remove old testing mock that no longer exists from moduleNameMapper --- client/jest.config.cjs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/client/jest.config.cjs b/client/jest.config.cjs index 3830e79..73e0d16 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -1,12 +1,11 @@ module.exports = { preset: "ts-jest", testEnvironment: "jsdom", + setupFilesAfterEnv: [ + '/src/setupTests.ts' + ], moduleNameMapper: { - "^@/(.*)$": "/src/$1", - "^../components/DynamicJsonForm$": - "/src/utils/__mocks__/DynamicJsonForm.ts", - "^../../components/DynamicJsonForm$": - "/src/utils/__mocks__/DynamicJsonForm.ts", + "^@/(.*)$": "/src/$1" }, transform: { "^.+\\.tsx?$": [ @@ -14,9 +13,9 @@ module.exports = { { useESM: true, jsx: "react-jsx", - tsconfig: "tsconfig.jest.json", - }, - ], + tsconfig: "tsconfig.jest.json" + } + ] }, extensionsToTreatAsEsm: [".ts", ".tsx"], testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", @@ -25,13 +24,13 @@ module.exports = { "/node_modules/", "/dist/", "/bin/", - "\\.config\\.(js|ts|cjs|mjs)$", + "\\.config\\.(js|ts|cjs|mjs)$" ], // Exclude the same patterns from coverage reports coveragePathIgnorePatterns: [ "/node_modules/", "/dist/", "/bin/", - "\\.config\\.(js|ts|cjs|mjs)$", - ], + "\\.config\\.(js|ts|cjs|mjs)$" + ] }; From 85f0e216791d5c0e6e610bb1b30743de8b4b15a7 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 13:22:13 -0700 Subject: [PATCH 08/20] Use commonjs for jest --- client/jest.config.cjs | 1 - 1 file changed, 1 deletion(-) diff --git a/client/jest.config.cjs b/client/jest.config.cjs index 73e0d16..6a48e7d 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -11,7 +11,6 @@ module.exports = { "^.+\\.tsx?$": [ "ts-jest", { - useESM: true, jsx: "react-jsx", tsconfig: "tsconfig.jest.json" } From 668cc915e4028132dd13254b406919a74b76bfd8 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 13:22:31 -0700 Subject: [PATCH 09/20] Add jest-dom types --- client/tsconfig.app.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json index 980c215..e6620f7 100644 --- a/client/tsconfig.app.json +++ b/client/tsconfig.app.json @@ -24,7 +24,8 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "types": ["jest", "@testing-library/jest-dom", "node"] }, "include": ["src"] } From 451704471c6324007cd263acf557a66ac943f95d Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 13:25:06 -0700 Subject: [PATCH 10/20] Remove setup --- client/jest.config.cjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/jest.config.cjs b/client/jest.config.cjs index 6a48e7d..949df20 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -1,9 +1,6 @@ module.exports = { preset: "ts-jest", testEnvironment: "jsdom", - setupFilesAfterEnv: [ - '/src/setupTests.ts' - ], moduleNameMapper: { "^@/(.*)$": "/src/$1" }, From 61e229a5529d343134c8333e2fb1700a43b4a79b Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Sun, 23 Mar 2025 13:35:24 -0700 Subject: [PATCH 11/20] Add sidebar tests --- .../src/components/__tests__/Sidebar.test.tsx | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 client/src/components/__tests__/Sidebar.test.tsx diff --git a/client/src/components/__tests__/Sidebar.test.tsx b/client/src/components/__tests__/Sidebar.test.tsx new file mode 100644 index 0000000..765de2f --- /dev/null +++ b/client/src/components/__tests__/Sidebar.test.tsx @@ -0,0 +1,278 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { describe, it, beforeEach, jest } from '@jest/globals'; +import Sidebar from '../Sidebar'; + +// Mock theme hook +jest.mock('../../lib/useTheme', () => ({ + __esModule: true, + default: () => ['light', jest.fn()], +})); + +describe('Sidebar Environment Variables', () => { + const defaultProps = { + connectionStatus: 'disconnected' as const, + transportType: 'stdio' as const, + setTransportType: jest.fn(), + command: '', + setCommand: jest.fn(), + args: '', + setArgs: jest.fn(), + sseUrl: '', + setSseUrl: jest.fn(), + env: {}, + setEnv: jest.fn(), + bearerToken: '', + setBearerToken: jest.fn(), + onConnect: jest.fn(), + stdErrNotifications: [], + logLevel: 'info' as const, + sendLogLevelRequest: jest.fn(), + loggingSupported: true, + }; + + const renderSidebar = (props = {}) => { + return render(); + }; + + const openEnvVarsSection = () => { + const button = screen.getByText('Environment Variables'); + fireEvent.click(button); + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('Basic Operations', () => { + it('should add a new environment variable', () => { + const setEnv = jest.fn(); + renderSidebar({ env: {}, setEnv }); + + openEnvVarsSection(); + + const addButton = screen.getByText('Add Environment Variable'); + fireEvent.click(addButton); + + expect(setEnv).toHaveBeenCalledWith({ '': '' }); + }); + + it('should remove an environment variable', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const removeButton = screen.getByRole('button', { name: 'Ɨ' }); + fireEvent.click(removeButton); + + expect(setEnv).toHaveBeenCalledWith({}); + }); + + it('should update environment variable value', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const valueInput = screen.getByDisplayValue('test_value'); + fireEvent.change(valueInput, { target: { value: 'new_value' } }); + + expect(setEnv).toHaveBeenCalledWith({ TEST_KEY: 'new_value' }); + }); + + it('should toggle value visibility', () => { + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv }); + + openEnvVarsSection(); + + const valueInput = screen.getByDisplayValue('test_value'); + expect(valueInput).toHaveProperty('type', 'password'); + + const toggleButton = screen.getByRole('button', { name: /show value/i }); + fireEvent.click(toggleButton); + + expect(valueInput).toHaveProperty('type', 'text'); + }); + }); + + describe('Key Editing', () => { + it('should maintain order when editing first key', () => { + const setEnv = jest.fn(); + const initialEnv = { + FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + THIRD_KEY: 'third_value', + }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const firstKeyInput = screen.getByDisplayValue('FIRST_KEY'); + fireEvent.change(firstKeyInput, { target: { value: 'NEW_FIRST_KEY' } }); + + expect(setEnv).toHaveBeenCalledWith({ + NEW_FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + THIRD_KEY: 'third_value', + }); + }); + + it('should maintain order when editing middle key', () => { + const setEnv = jest.fn(); + const initialEnv = { + FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + THIRD_KEY: 'third_value', + }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const middleKeyInput = screen.getByDisplayValue('SECOND_KEY'); + fireEvent.change(middleKeyInput, { target: { value: 'NEW_SECOND_KEY' } }); + + expect(setEnv).toHaveBeenCalledWith({ + FIRST_KEY: 'first_value', + NEW_SECOND_KEY: 'second_value', + THIRD_KEY: 'third_value', + }); + }); + + it('should maintain order when editing last key', () => { + const setEnv = jest.fn(); + const initialEnv = { + FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + THIRD_KEY: 'third_value', + }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const lastKeyInput = screen.getByDisplayValue('THIRD_KEY'); + fireEvent.change(lastKeyInput, { target: { value: 'NEW_THIRD_KEY' } }); + + expect(setEnv).toHaveBeenCalledWith({ + FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + NEW_THIRD_KEY: 'third_value', + }); + }); + }); + + describe('Multiple Operations', () => { + it('should maintain state after multiple key edits', () => { + const setEnv = jest.fn(); + const initialEnv = { + FIRST_KEY: 'first_value', + SECOND_KEY: 'second_value', + }; + const { rerender } = renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + // First key edit + const firstKeyInput = screen.getByDisplayValue('FIRST_KEY'); + fireEvent.change(firstKeyInput, { target: { value: 'NEW_FIRST_KEY' } }); + + // Get the updated env from the first setEnv call + const updatedEnv = (setEnv.mock.calls[0][0] as Record); + + // Rerender with the updated env + rerender(); + + // Second key edit + const secondKeyInput = screen.getByDisplayValue('SECOND_KEY'); + fireEvent.change(secondKeyInput, { target: { value: 'NEW_SECOND_KEY' } }); + + // Verify the final state matches what we expect + expect(setEnv).toHaveBeenLastCalledWith({ + NEW_FIRST_KEY: 'first_value', + NEW_SECOND_KEY: 'second_value', + }); + }); + + it('should maintain visibility state after key edit', () => { + const initialEnv = { TEST_KEY: 'test_value' }; + const { rerender } = renderSidebar({ env: initialEnv }); + + openEnvVarsSection(); + + // Show the value + const toggleButton = screen.getByRole('button', { name: /show value/i }); + fireEvent.click(toggleButton); + + const valueInput = screen.getByDisplayValue('test_value'); + expect(valueInput).toHaveProperty('type', 'text'); + + // Edit the key + const keyInput = screen.getByDisplayValue('TEST_KEY'); + fireEvent.change(keyInput, { target: { value: 'NEW_KEY' } }); + + // Rerender with updated env + rerender(); + + // Value should still be visible + const updatedValueInput = screen.getByDisplayValue('test_value'); + expect(updatedValueInput).toHaveProperty('type', 'text'); + }); + }); + + describe('Edge Cases', () => { + it('should handle empty key', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const keyInput = screen.getByDisplayValue('TEST_KEY'); + fireEvent.change(keyInput, { target: { value: '' } }); + + expect(setEnv).toHaveBeenCalledWith({ '': 'test_value' }); + }); + + it('should handle special characters in key', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const keyInput = screen.getByDisplayValue('TEST_KEY'); + fireEvent.change(keyInput, { target: { value: 'TEST-KEY@123' } }); + + expect(setEnv).toHaveBeenCalledWith({ 'TEST-KEY@123': 'test_value' }); + }); + + it('should handle unicode characters', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const keyInput = screen.getByDisplayValue('TEST_KEY'); + fireEvent.change(keyInput, { target: { value: 'TEST_šŸ”‘' } }); + + expect(setEnv).toHaveBeenCalledWith({ 'TEST_šŸ”‘': 'test_value' }); + }); + + it('should handle very long key names', () => { + const setEnv = jest.fn(); + const initialEnv = { TEST_KEY: 'test_value' }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + const keyInput = screen.getByDisplayValue('TEST_KEY'); + const longKey = 'A'.repeat(100); + fireEvent.change(keyInput, { target: { value: longKey } }); + + expect(setEnv).toHaveBeenCalledWith({ [longKey]: 'test_value' }); + }); + }); +}); From cab1ed3dd849a85b37255eb2ec20ee7764565a4c Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 08:28:28 -0700 Subject: [PATCH 12/20] Add some json form tests and handle css in ui tests --- client/jest.config.cjs | 3 +- client/src/__mocks__/styleMock.js | 1 + .../__tests__/DynamicJsonForm.test.tsx | 61 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 client/src/__mocks__/styleMock.js create mode 100644 client/src/components/__tests__/DynamicJsonForm.test.tsx diff --git a/client/jest.config.cjs b/client/jest.config.cjs index 949df20..b87383e 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -2,7 +2,8 @@ module.exports = { preset: "ts-jest", testEnvironment: "jsdom", moduleNameMapper: { - "^@/(.*)$": "/src/$1" + "^@/(.*)$": "/src/$1", + "\\.css$": "/src/__mocks__/styleMock.js" }, transform: { "^.+\\.tsx?$": [ diff --git a/client/src/__mocks__/styleMock.js b/client/src/__mocks__/styleMock.js new file mode 100644 index 0000000..f053ebf --- /dev/null +++ b/client/src/__mocks__/styleMock.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/client/src/components/__tests__/DynamicJsonForm.test.tsx b/client/src/components/__tests__/DynamicJsonForm.test.tsx new file mode 100644 index 0000000..d140663 --- /dev/null +++ b/client/src/components/__tests__/DynamicJsonForm.test.tsx @@ -0,0 +1,61 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import { describe, it, expect, jest } from '@jest/globals'; +import DynamicJsonForm from '../DynamicJsonForm'; +import type { JsonSchemaType } from '../DynamicJsonForm'; + +describe('DynamicJsonForm Integer Fields', () => { + const renderForm = (props = {}) => { + const defaultProps = { + schema: { + type: "integer" as const, + description: "Test integer field" + } satisfies JsonSchemaType, + value: undefined, + onChange: jest.fn() + }; + return render(); + }; + + describe('Basic Operations', () => { + it('should render number input with step=1', () => { + renderForm(); + const input = screen.getByRole('spinbutton'); + expect(input).toHaveProperty('type', 'number'); + expect(input).toHaveProperty('step', '1'); + }); + + it('should pass integer values to onChange', () => { + const onChange = jest.fn(); + renderForm({ onChange }); + + const input = screen.getByRole('spinbutton'); + fireEvent.change(input, { target: { value: '42' } }); + + expect(onChange).toHaveBeenCalledWith(42); + // Verify the value is a number, not a string + expect(typeof onChange.mock.calls[0][0]).toBe('number'); + }); + + it('should not pass string values to onChange', () => { + const onChange = jest.fn(); + renderForm({ onChange }); + + const input = screen.getByRole('spinbutton'); + fireEvent.change(input, { target: { value: 'abc' } }); + + expect(onChange).not.toHaveBeenCalled(); + }); + }); + + describe('Edge Cases', () => { + it('should handle non-numeric input by not calling onChange', () => { + const onChange = jest.fn(); + renderForm({ onChange }); + + const input = screen.getByRole('spinbutton'); + fireEvent.change(input, { target: { value: 'abc' } }); + + expect(onChange).not.toHaveBeenCalled(); + }); + }); +}); From 5735f2347a4d1465033806e4648583a5a35a4e0f Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 08:52:45 -0700 Subject: [PATCH 13/20] Add tests related to issues/187 to confirm fixed --- .../__tests__/DynamicJsonForm.test.tsx | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/client/src/components/__tests__/DynamicJsonForm.test.tsx b/client/src/components/__tests__/DynamicJsonForm.test.tsx index d140663..f18c15f 100644 --- a/client/src/components/__tests__/DynamicJsonForm.test.tsx +++ b/client/src/components/__tests__/DynamicJsonForm.test.tsx @@ -3,6 +3,40 @@ import { describe, it, expect, jest } from '@jest/globals'; import DynamicJsonForm from '../DynamicJsonForm'; import type { JsonSchemaType } from '../DynamicJsonForm'; +describe('DynamicJsonForm String Fields', () => { + const renderForm = (props = {}) => { + const defaultProps = { + schema: { + type: "string" as const, + description: "Test string field" + } satisfies JsonSchemaType, + value: undefined, + onChange: jest.fn() + }; + return render(); + }; + + describe('Type Validation', () => { + it('should handle numeric input as string type', () => { + const onChange = jest.fn(); + renderForm({ onChange }); + + const input = screen.getByRole('textbox'); + fireEvent.change(input, { target: { value: '123321' } }); + + expect(onChange).toHaveBeenCalledWith('123321'); + // Verify the value is a string, not a number + expect(typeof onChange.mock.calls[0][0]).toBe('string'); + }); + + it('should render as text input, not number input', () => { + renderForm(); + const input = screen.getByRole('textbox'); + expect(input).toHaveProperty('type', 'text'); + }); + }); +}); + describe('DynamicJsonForm Integer Fields', () => { const renderForm = (props = {}) => { const defaultProps = { From fa3e2867c97e27c2bb434be7eaacd6698dc8fb4b Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 09:07:53 -0700 Subject: [PATCH 14/20] Fix formatting --- client/jest.config.cjs | 14 +- .../__tests__/DynamicJsonForm.test.tsx | 86 ++--- .../src/components/__tests__/Sidebar.test.tsx | 296 +++++++++--------- 3 files changed, 198 insertions(+), 198 deletions(-) diff --git a/client/jest.config.cjs b/client/jest.config.cjs index b87383e..c360e72 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -3,16 +3,16 @@ module.exports = { testEnvironment: "jsdom", moduleNameMapper: { "^@/(.*)$": "/src/$1", - "\\.css$": "/src/__mocks__/styleMock.js" + "\\.css$": "/src/__mocks__/styleMock.js", }, transform: { "^.+\\.tsx?$": [ "ts-jest", { jsx: "react-jsx", - tsconfig: "tsconfig.jest.json" - } - ] + tsconfig: "tsconfig.jest.json", + }, + ], }, extensionsToTreatAsEsm: [".ts", ".tsx"], testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", @@ -21,13 +21,13 @@ module.exports = { "/node_modules/", "/dist/", "/bin/", - "\\.config\\.(js|ts|cjs|mjs)$" + "\\.config\\.(js|ts|cjs|mjs)$", ], // Exclude the same patterns from coverage reports coveragePathIgnorePatterns: [ "/node_modules/", "/dist/", "/bin/", - "\\.config\\.(js|ts|cjs|mjs)$" - ] + "\\.config\\.(js|ts|cjs|mjs)$", + ], }; diff --git a/client/src/components/__tests__/DynamicJsonForm.test.tsx b/client/src/components/__tests__/DynamicJsonForm.test.tsx index f18c15f..fce6014 100644 --- a/client/src/components/__tests__/DynamicJsonForm.test.tsx +++ b/client/src/components/__tests__/DynamicJsonForm.test.tsx @@ -1,94 +1,94 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, it, expect, jest } from '@jest/globals'; -import DynamicJsonForm from '../DynamicJsonForm'; -import type { JsonSchemaType } from '../DynamicJsonForm'; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, jest } from "@jest/globals"; +import DynamicJsonForm from "../DynamicJsonForm"; +import type { JsonSchemaType } from "../DynamicJsonForm"; -describe('DynamicJsonForm String Fields', () => { +describe("DynamicJsonForm String Fields", () => { const renderForm = (props = {}) => { const defaultProps = { schema: { type: "string" as const, - description: "Test string field" + description: "Test string field", } satisfies JsonSchemaType, value: undefined, - onChange: jest.fn() + onChange: jest.fn(), }; return render(); }; - describe('Type Validation', () => { - it('should handle numeric input as string type', () => { + describe("Type Validation", () => { + it("should handle numeric input as string type", () => { const onChange = jest.fn(); renderForm({ onChange }); - - const input = screen.getByRole('textbox'); - fireEvent.change(input, { target: { value: '123321' } }); - - expect(onChange).toHaveBeenCalledWith('123321'); + + const input = screen.getByRole("textbox"); + fireEvent.change(input, { target: { value: "123321" } }); + + expect(onChange).toHaveBeenCalledWith("123321"); // Verify the value is a string, not a number - expect(typeof onChange.mock.calls[0][0]).toBe('string'); + expect(typeof onChange.mock.calls[0][0]).toBe("string"); }); - it('should render as text input, not number input', () => { + it("should render as text input, not number input", () => { renderForm(); - const input = screen.getByRole('textbox'); - expect(input).toHaveProperty('type', 'text'); + const input = screen.getByRole("textbox"); + expect(input).toHaveProperty("type", "text"); }); }); }); -describe('DynamicJsonForm Integer Fields', () => { +describe("DynamicJsonForm Integer Fields", () => { const renderForm = (props = {}) => { const defaultProps = { schema: { type: "integer" as const, - description: "Test integer field" + description: "Test integer field", } satisfies JsonSchemaType, value: undefined, - onChange: jest.fn() + onChange: jest.fn(), }; return render(); }; - describe('Basic Operations', () => { - it('should render number input with step=1', () => { + describe("Basic Operations", () => { + it("should render number input with step=1", () => { renderForm(); - const input = screen.getByRole('spinbutton'); - expect(input).toHaveProperty('type', 'number'); - expect(input).toHaveProperty('step', '1'); + const input = screen.getByRole("spinbutton"); + expect(input).toHaveProperty("type", "number"); + expect(input).toHaveProperty("step", "1"); }); - it('should pass integer values to onChange', () => { + it("should pass integer values to onChange", () => { const onChange = jest.fn(); renderForm({ onChange }); - - const input = screen.getByRole('spinbutton'); - fireEvent.change(input, { target: { value: '42' } }); - + + const input = screen.getByRole("spinbutton"); + fireEvent.change(input, { target: { value: "42" } }); + expect(onChange).toHaveBeenCalledWith(42); // Verify the value is a number, not a string - expect(typeof onChange.mock.calls[0][0]).toBe('number'); + expect(typeof onChange.mock.calls[0][0]).toBe("number"); }); - it('should not pass string values to onChange', () => { + it("should not pass string values to onChange", () => { const onChange = jest.fn(); renderForm({ onChange }); - - const input = screen.getByRole('spinbutton'); - fireEvent.change(input, { target: { value: 'abc' } }); - + + const input = screen.getByRole("spinbutton"); + fireEvent.change(input, { target: { value: "abc" } }); + expect(onChange).not.toHaveBeenCalled(); }); }); - describe('Edge Cases', () => { - it('should handle non-numeric input by not calling onChange', () => { + describe("Edge Cases", () => { + it("should handle non-numeric input by not calling onChange", () => { const onChange = jest.fn(); renderForm({ onChange }); - - const input = screen.getByRole('spinbutton'); - fireEvent.change(input, { target: { value: 'abc' } }); - + + const input = screen.getByRole("spinbutton"); + fireEvent.change(input, { target: { value: "abc" } }); + expect(onChange).not.toHaveBeenCalled(); }); }); diff --git a/client/src/components/__tests__/Sidebar.test.tsx b/client/src/components/__tests__/Sidebar.test.tsx index 765de2f..8c0b313 100644 --- a/client/src/components/__tests__/Sidebar.test.tsx +++ b/client/src/components/__tests__/Sidebar.test.tsx @@ -1,31 +1,31 @@ -import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, it, beforeEach, jest } from '@jest/globals'; -import Sidebar from '../Sidebar'; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, beforeEach, jest } from "@jest/globals"; +import Sidebar from "../Sidebar"; // Mock theme hook -jest.mock('../../lib/useTheme', () => ({ +jest.mock("../../lib/useTheme", () => ({ __esModule: true, - default: () => ['light', jest.fn()], + default: () => ["light", jest.fn()], })); -describe('Sidebar Environment Variables', () => { +describe("Sidebar Environment Variables", () => { const defaultProps = { - connectionStatus: 'disconnected' as const, - transportType: 'stdio' as const, + connectionStatus: "disconnected" as const, + transportType: "stdio" as const, setTransportType: jest.fn(), - command: '', + command: "", setCommand: jest.fn(), - args: '', + args: "", setArgs: jest.fn(), - sseUrl: '', + sseUrl: "", setSseUrl: jest.fn(), env: {}, setEnv: jest.fn(), - bearerToken: '', + bearerToken: "", setBearerToken: jest.fn(), onConnect: jest.fn(), stdErrNotifications: [], - logLevel: 'info' as const, + logLevel: "info" as const, sendLogLevelRequest: jest.fn(), loggingSupported: true, }; @@ -35,7 +35,7 @@ describe('Sidebar Environment Variables', () => { }; const openEnvVarsSection = () => { - const button = screen.getByText('Environment Variables'); + const button = screen.getByText("Environment Variables"); fireEvent.click(button); }; @@ -43,236 +43,236 @@ describe('Sidebar Environment Variables', () => { jest.clearAllMocks(); }); - describe('Basic Operations', () => { - it('should add a new environment variable', () => { + describe("Basic Operations", () => { + it("should add a new environment variable", () => { const setEnv = jest.fn(); renderSidebar({ env: {}, setEnv }); - + openEnvVarsSection(); - - const addButton = screen.getByText('Add Environment Variable'); + + const addButton = screen.getByText("Add Environment Variable"); fireEvent.click(addButton); - - expect(setEnv).toHaveBeenCalledWith({ '': '' }); + + expect(setEnv).toHaveBeenCalledWith({ "": "" }); }); - it('should remove an environment variable', () => { + it("should remove an environment variable", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const removeButton = screen.getByRole('button', { name: 'Ɨ' }); + + const removeButton = screen.getByRole("button", { name: "Ɨ" }); fireEvent.click(removeButton); - + expect(setEnv).toHaveBeenCalledWith({}); }); - it('should update environment variable value', () => { + it("should update environment variable value", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const valueInput = screen.getByDisplayValue('test_value'); - fireEvent.change(valueInput, { target: { value: 'new_value' } }); - - expect(setEnv).toHaveBeenCalledWith({ TEST_KEY: 'new_value' }); + + const valueInput = screen.getByDisplayValue("test_value"); + fireEvent.change(valueInput, { target: { value: "new_value" } }); + + expect(setEnv).toHaveBeenCalledWith({ TEST_KEY: "new_value" }); }); - it('should toggle value visibility', () => { - const initialEnv = { TEST_KEY: 'test_value' }; + it("should toggle value visibility", () => { + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv }); - + openEnvVarsSection(); - - const valueInput = screen.getByDisplayValue('test_value'); - expect(valueInput).toHaveProperty('type', 'password'); - - const toggleButton = screen.getByRole('button', { name: /show value/i }); + + const valueInput = screen.getByDisplayValue("test_value"); + expect(valueInput).toHaveProperty("type", "password"); + + const toggleButton = screen.getByRole("button", { name: /show value/i }); fireEvent.click(toggleButton); - - expect(valueInput).toHaveProperty('type', 'text'); + + expect(valueInput).toHaveProperty("type", "text"); }); }); - describe('Key Editing', () => { - it('should maintain order when editing first key', () => { + describe("Key Editing", () => { + it("should maintain order when editing first key", () => { const setEnv = jest.fn(); const initialEnv = { - FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', - THIRD_KEY: 'third_value', + FIRST_KEY: "first_value", + SECOND_KEY: "second_value", + THIRD_KEY: "third_value", }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const firstKeyInput = screen.getByDisplayValue('FIRST_KEY'); - fireEvent.change(firstKeyInput, { target: { value: 'NEW_FIRST_KEY' } }); - + + const firstKeyInput = screen.getByDisplayValue("FIRST_KEY"); + fireEvent.change(firstKeyInput, { target: { value: "NEW_FIRST_KEY" } }); + expect(setEnv).toHaveBeenCalledWith({ - NEW_FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', - THIRD_KEY: 'third_value', + NEW_FIRST_KEY: "first_value", + SECOND_KEY: "second_value", + THIRD_KEY: "third_value", }); }); - it('should maintain order when editing middle key', () => { + it("should maintain order when editing middle key", () => { const setEnv = jest.fn(); const initialEnv = { - FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', - THIRD_KEY: 'third_value', + FIRST_KEY: "first_value", + SECOND_KEY: "second_value", + THIRD_KEY: "third_value", }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const middleKeyInput = screen.getByDisplayValue('SECOND_KEY'); - fireEvent.change(middleKeyInput, { target: { value: 'NEW_SECOND_KEY' } }); - + + const middleKeyInput = screen.getByDisplayValue("SECOND_KEY"); + fireEvent.change(middleKeyInput, { target: { value: "NEW_SECOND_KEY" } }); + expect(setEnv).toHaveBeenCalledWith({ - FIRST_KEY: 'first_value', - NEW_SECOND_KEY: 'second_value', - THIRD_KEY: 'third_value', + FIRST_KEY: "first_value", + NEW_SECOND_KEY: "second_value", + THIRD_KEY: "third_value", }); }); - it('should maintain order when editing last key', () => { + it("should maintain order when editing last key", () => { const setEnv = jest.fn(); const initialEnv = { - FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', - THIRD_KEY: 'third_value', + FIRST_KEY: "first_value", + SECOND_KEY: "second_value", + THIRD_KEY: "third_value", }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const lastKeyInput = screen.getByDisplayValue('THIRD_KEY'); - fireEvent.change(lastKeyInput, { target: { value: 'NEW_THIRD_KEY' } }); - + + const lastKeyInput = screen.getByDisplayValue("THIRD_KEY"); + fireEvent.change(lastKeyInput, { target: { value: "NEW_THIRD_KEY" } }); + expect(setEnv).toHaveBeenCalledWith({ - FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', - NEW_THIRD_KEY: 'third_value', + FIRST_KEY: "first_value", + SECOND_KEY: "second_value", + NEW_THIRD_KEY: "third_value", }); }); }); - describe('Multiple Operations', () => { - it('should maintain state after multiple key edits', () => { + describe("Multiple Operations", () => { + it("should maintain state after multiple key edits", () => { const setEnv = jest.fn(); const initialEnv = { - FIRST_KEY: 'first_value', - SECOND_KEY: 'second_value', + FIRST_KEY: "first_value", + SECOND_KEY: "second_value", }; const { rerender } = renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - + // First key edit - const firstKeyInput = screen.getByDisplayValue('FIRST_KEY'); - fireEvent.change(firstKeyInput, { target: { value: 'NEW_FIRST_KEY' } }); - + const firstKeyInput = screen.getByDisplayValue("FIRST_KEY"); + fireEvent.change(firstKeyInput, { target: { value: "NEW_FIRST_KEY" } }); + // Get the updated env from the first setEnv call - const updatedEnv = (setEnv.mock.calls[0][0] as Record); - + const updatedEnv = setEnv.mock.calls[0][0] as Record; + // Rerender with the updated env rerender(); - + // Second key edit - const secondKeyInput = screen.getByDisplayValue('SECOND_KEY'); - fireEvent.change(secondKeyInput, { target: { value: 'NEW_SECOND_KEY' } }); - + const secondKeyInput = screen.getByDisplayValue("SECOND_KEY"); + fireEvent.change(secondKeyInput, { target: { value: "NEW_SECOND_KEY" } }); + // Verify the final state matches what we expect expect(setEnv).toHaveBeenLastCalledWith({ - NEW_FIRST_KEY: 'first_value', - NEW_SECOND_KEY: 'second_value', + NEW_FIRST_KEY: "first_value", + NEW_SECOND_KEY: "second_value", }); }); - it('should maintain visibility state after key edit', () => { - const initialEnv = { TEST_KEY: 'test_value' }; + it("should maintain visibility state after key edit", () => { + const initialEnv = { TEST_KEY: "test_value" }; const { rerender } = renderSidebar({ env: initialEnv }); - + openEnvVarsSection(); - + // Show the value - const toggleButton = screen.getByRole('button', { name: /show value/i }); + const toggleButton = screen.getByRole("button", { name: /show value/i }); fireEvent.click(toggleButton); - - const valueInput = screen.getByDisplayValue('test_value'); - expect(valueInput).toHaveProperty('type', 'text'); - + + const valueInput = screen.getByDisplayValue("test_value"); + expect(valueInput).toHaveProperty("type", "text"); + // Edit the key - const keyInput = screen.getByDisplayValue('TEST_KEY'); - fireEvent.change(keyInput, { target: { value: 'NEW_KEY' } }); - + const keyInput = screen.getByDisplayValue("TEST_KEY"); + fireEvent.change(keyInput, { target: { value: "NEW_KEY" } }); + // Rerender with updated env - rerender(); - + rerender(); + // Value should still be visible - const updatedValueInput = screen.getByDisplayValue('test_value'); - expect(updatedValueInput).toHaveProperty('type', 'text'); + const updatedValueInput = screen.getByDisplayValue("test_value"); + expect(updatedValueInput).toHaveProperty("type", "text"); }); }); - describe('Edge Cases', () => { - it('should handle empty key', () => { + describe("Edge Cases", () => { + it("should handle empty key", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const keyInput = screen.getByDisplayValue('TEST_KEY'); - fireEvent.change(keyInput, { target: { value: '' } }); - - expect(setEnv).toHaveBeenCalledWith({ '': 'test_value' }); + + const keyInput = screen.getByDisplayValue("TEST_KEY"); + fireEvent.change(keyInput, { target: { value: "" } }); + + expect(setEnv).toHaveBeenCalledWith({ "": "test_value" }); }); - it('should handle special characters in key', () => { + it("should handle special characters in key", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const keyInput = screen.getByDisplayValue('TEST_KEY'); - fireEvent.change(keyInput, { target: { value: 'TEST-KEY@123' } }); - - expect(setEnv).toHaveBeenCalledWith({ 'TEST-KEY@123': 'test_value' }); + + const keyInput = screen.getByDisplayValue("TEST_KEY"); + fireEvent.change(keyInput, { target: { value: "TEST-KEY@123" } }); + + expect(setEnv).toHaveBeenCalledWith({ "TEST-KEY@123": "test_value" }); }); - it('should handle unicode characters', () => { + it("should handle unicode characters", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const keyInput = screen.getByDisplayValue('TEST_KEY'); - fireEvent.change(keyInput, { target: { value: 'TEST_šŸ”‘' } }); - - expect(setEnv).toHaveBeenCalledWith({ 'TEST_šŸ”‘': 'test_value' }); + + const keyInput = screen.getByDisplayValue("TEST_KEY"); + fireEvent.change(keyInput, { target: { value: "TEST_šŸ”‘" } }); + + expect(setEnv).toHaveBeenCalledWith({ "TEST_šŸ”‘": "test_value" }); }); - it('should handle very long key names', () => { + it("should handle very long key names", () => { const setEnv = jest.fn(); - const initialEnv = { TEST_KEY: 'test_value' }; + const initialEnv = { TEST_KEY: "test_value" }; renderSidebar({ env: initialEnv, setEnv }); - + openEnvVarsSection(); - - const keyInput = screen.getByDisplayValue('TEST_KEY'); - const longKey = 'A'.repeat(100); + + const keyInput = screen.getByDisplayValue("TEST_KEY"); + const longKey = "A".repeat(100); fireEvent.change(keyInput, { target: { value: longKey } }); - - expect(setEnv).toHaveBeenCalledWith({ [longKey]: 'test_value' }); + + expect(setEnv).toHaveBeenCalledWith({ [longKey]: "test_value" }); }); }); }); From a7f25153c445769add41e89dfaf15b7f5c60971f Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 09:18:58 -0700 Subject: [PATCH 15/20] Add failing ToolsTab test that should get fixed with pull/198 --- .../components/__tests__/ToolsTab.test.tsx | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 client/src/components/__tests__/ToolsTab.test.tsx diff --git a/client/src/components/__tests__/ToolsTab.test.tsx b/client/src/components/__tests__/ToolsTab.test.tsx new file mode 100644 index 0000000..2688b52 --- /dev/null +++ b/client/src/components/__tests__/ToolsTab.test.tsx @@ -0,0 +1,72 @@ +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, jest } from "@jest/globals"; +import ToolsTab from "../ToolsTab"; +import { Tool } from "@modelcontextprotocol/sdk/types.js"; +import { Tabs } from "@/components/ui/tabs"; + +describe("ToolsTab", () => { + const mockTools: Tool[] = [ + { + name: "tool1", + description: "First tool", + inputSchema: { + type: "object" as const, + properties: { + num: { type: "number" as const } + } + } + }, + { + name: "tool2", + description: "Second tool", + inputSchema: { + type: "object" as const, + properties: { + num: { type: "number" as const } + } + } + } + ]; + + const defaultProps = { + tools: mockTools, + listTools: jest.fn(), + clearTools: jest.fn(), + callTool: jest.fn(), + selectedTool: null, + setSelectedTool: jest.fn(), + toolResult: null, + nextCursor: "", + error: null + }; + + const renderToolsTab = (props = {}) => { + return render( + + + + ); + }; + + it("should reset input values when switching tools", () => { + const { rerender } = renderToolsTab({ + selectedTool: mockTools[0] + }); + + // Enter a value in the first tool's input + const input = screen.getByRole("spinbutton") as HTMLInputElement; + fireEvent.change(input, { target: { value: "42" } }); + expect(input.value).toBe("42"); + + // Switch to second tool + rerender( + + + + ); + + // Verify input is reset + const newInput = screen.getByRole("spinbutton") as HTMLInputElement; + expect(newInput.value).toBe(""); + }); +}); From b7fa23676a6255176dad029dd1e79252ccba9cb4 Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 09:27:51 -0700 Subject: [PATCH 16/20] Fix formatting --- .../components/__tests__/ToolsTab.test.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/client/src/components/__tests__/ToolsTab.test.tsx b/client/src/components/__tests__/ToolsTab.test.tsx index 2688b52..2a45065 100644 --- a/client/src/components/__tests__/ToolsTab.test.tsx +++ b/client/src/components/__tests__/ToolsTab.test.tsx @@ -12,9 +12,9 @@ describe("ToolsTab", () => { inputSchema: { type: "object" as const, properties: { - num: { type: "number" as const } - } - } + num: { type: "number" as const }, + }, + }, }, { name: "tool2", @@ -22,10 +22,10 @@ describe("ToolsTab", () => { inputSchema: { type: "object" as const, properties: { - num: { type: "number" as const } - } - } - } + num: { type: "number" as const }, + }, + }, + }, ]; const defaultProps = { @@ -37,20 +37,20 @@ describe("ToolsTab", () => { setSelectedTool: jest.fn(), toolResult: null, nextCursor: "", - error: null + error: null, }; const renderToolsTab = (props = {}) => { return render( - + , ); }; it("should reset input values when switching tools", () => { const { rerender } = renderToolsTab({ - selectedTool: mockTools[0] + selectedTool: mockTools[0], }); // Enter a value in the first tool's input @@ -62,7 +62,7 @@ describe("ToolsTab", () => { rerender( - + , ); // Verify input is reset From 379486b5ea4d4ab2e2faae5a96c79276e374234f Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 09:43:48 -0700 Subject: [PATCH 17/20] Add failing test for pull/206 --- .../src/components/__tests__/Sidebar.test.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/client/src/components/__tests__/Sidebar.test.tsx b/client/src/components/__tests__/Sidebar.test.tsx index 8c0b313..fc8a5f4 100644 --- a/client/src/components/__tests__/Sidebar.test.tsx +++ b/client/src/components/__tests__/Sidebar.test.tsx @@ -161,6 +161,31 @@ describe("Sidebar Environment Variables", () => { NEW_THIRD_KEY: "third_value", }); }); + + it("should maintain order during key editing", () => { + const setEnv = jest.fn(); + const initialEnv = { + KEY1: "value1", + KEY2: "value2" + }; + renderSidebar({ env: initialEnv, setEnv }); + + openEnvVarsSection(); + + // Type "NEW_" one character at a time + const key1Input = screen.getByDisplayValue("KEY1"); + "NEW_".split("").forEach((char) => { + fireEvent.change(key1Input, { target: { value: char + "KEY1".slice(1) } }); + }); + + // Verify the last setEnv call maintains the order + const lastCall = setEnv.mock.calls[setEnv.mock.calls.length - 1][0] as Record; + const entries = Object.entries(lastCall); + + // The values should stay with their original keys + expect(entries[0][1]).toBe("value1"); // First entry should still have value1 + expect(entries[1][1]).toBe("value2"); // Second entry should still have value2 + }); }); describe("Multiple Operations", () => { From 65a0d46816aca50e87643e325d80160a4743b33b Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 09:47:34 -0700 Subject: [PATCH 18/20] Fix formatting --- client/src/components/__tests__/Sidebar.test.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/client/src/components/__tests__/Sidebar.test.tsx b/client/src/components/__tests__/Sidebar.test.tsx index fc8a5f4..710c80d 100644 --- a/client/src/components/__tests__/Sidebar.test.tsx +++ b/client/src/components/__tests__/Sidebar.test.tsx @@ -166,7 +166,7 @@ describe("Sidebar Environment Variables", () => { const setEnv = jest.fn(); const initialEnv = { KEY1: "value1", - KEY2: "value2" + KEY2: "value2", }; renderSidebar({ env: initialEnv, setEnv }); @@ -175,13 +175,17 @@ describe("Sidebar Environment Variables", () => { // Type "NEW_" one character at a time const key1Input = screen.getByDisplayValue("KEY1"); "NEW_".split("").forEach((char) => { - fireEvent.change(key1Input, { target: { value: char + "KEY1".slice(1) } }); + fireEvent.change(key1Input, { + target: { value: char + "KEY1".slice(1) }, + }); }); // Verify the last setEnv call maintains the order - const lastCall = setEnv.mock.calls[setEnv.mock.calls.length - 1][0] as Record; + const lastCall = setEnv.mock.calls[ + setEnv.mock.calls.length - 1 + ][0] as Record; const entries = Object.entries(lastCall); - + // The values should stay with their original keys expect(entries[0][1]).toBe("value1"); // First entry should still have value1 expect(entries[1][1]).toBe("value2"); // Second entry should still have value2 From f2f209dbd3ded70d76a181557a1c598a6721dfe5 Mon Sep 17 00:00:00 2001 From: Mark Anthony Cianfrani Date: Sat, 22 Mar 2025 12:52:56 -0400 Subject: [PATCH 19/20] fix(sidebar): maintain order when changing values --- client/src/components/Sidebar.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/client/src/components/Sidebar.tsx b/client/src/components/Sidebar.tsx index aa930e5..4f60a77 100644 --- a/client/src/components/Sidebar.tsx +++ b/client/src/components/Sidebar.tsx @@ -187,9 +187,17 @@ const Sidebar = ({ value={key} onChange={(e) => { const newKey = e.target.value; - const newEnv = { ...env }; - delete newEnv[key]; - newEnv[newKey] = value; + const newEnv = Object.entries(env).reduce( + (acc, [k, v]) => { + if (k === key) { + acc[newKey] = value; + } else { + acc[k] = v; + } + return acc; + }, + {} as Record, + ); setEnv(newEnv); setShownEnvVars((prev) => { const next = new Set(prev); From 16b38071e7554eb5556491f2f04339e58c5a073c Mon Sep 17 00:00:00 2001 From: Ola Hungerford Date: Mon, 24 Mar 2025 12:36:17 -0700 Subject: [PATCH 20/20] Bump version to 0.7.0 --- client/package.json | 2 +- package-lock.json | 12 ++++++------ package.json | 6 +++--- server/package.json | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/client/package.json b/client/package.json index 0471765..30cf37f 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-client", - "version": "0.6.0", + "version": "0.7.0", "description": "Client-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", diff --git a/package-lock.json b/package-lock.json index 68929c5..eec3c95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.6.0", + "version": "0.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@modelcontextprotocol/inspector", - "version": "0.6.0", + "version": "0.7.0", "license": "MIT", "workspaces": [ "client", "server" ], "dependencies": { - "@modelcontextprotocol/inspector-client": "^0.6.0", - "@modelcontextprotocol/inspector-server": "^0.6.0", + "@modelcontextprotocol/inspector-client": "^0.7.0", + "@modelcontextprotocol/inspector-server": "^0.7.0", "concurrently": "^9.0.1", "shell-quote": "^1.8.2", "spawn-rx": "^5.1.2", @@ -32,7 +32,7 @@ }, "client": { "name": "@modelcontextprotocol/inspector-client", - "version": "0.6.0", + "version": "0.7.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.6.1", @@ -11299,7 +11299,7 @@ }, "server": { "name": "@modelcontextprotocol/inspector-server", - "version": "0.6.0", + "version": "0.7.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.6.1", diff --git a/package.json b/package.json index e3bce92..66cc1a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector", - "version": "0.6.0", + "version": "0.7.0", "description": "Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)", @@ -34,8 +34,8 @@ "publish-all": "npm publish --workspaces --access public && npm publish --access public" }, "dependencies": { - "@modelcontextprotocol/inspector-client": "^0.6.0", - "@modelcontextprotocol/inspector-server": "^0.6.0", + "@modelcontextprotocol/inspector-client": "^0.7.0", + "@modelcontextprotocol/inspector-server": "^0.7.0", "concurrently": "^9.0.1", "shell-quote": "^1.8.2", "spawn-rx": "^5.1.2", diff --git a/server/package.json b/server/package.json index 5d8839f..732993f 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/inspector-server", - "version": "0.6.0", + "version": "0.7.0", "description": "Server-side application for the Model Context Protocol inspector", "license": "MIT", "author": "Anthropic, PBC (https://anthropic.com)",