更新插件端架构

This commit is contained in:
锦恢 2025-04-30 19:49:14 +08:00
parent 354380cf23
commit 34936d944d
25 changed files with 621 additions and 137 deletions

View File

@ -17,6 +17,7 @@ service/**
test/** test/**
servers/** servers/**
scripts/** scripts/**
software/**
*.sh *.sh
*.ps1 *.ps1

View File

@ -1,5 +1,12 @@
# Change Log # Change Log
## [main] 0.0.6
- 修复部分因为服务器名称特殊字符而导致的保存实效的错误
- 插件模式下左侧管理面板中的「MCP连接工作区」视图可以进行增删改查了
- 新增「MCP连接全局用于安装全局范围的 mcp server
## [main] 0.0.5 ## [main] 0.0.5
- 支持对已经打开过的文件项目进行管理 - 支持对已经打开过的文件项目进行管理
- 支持对用户对应服务器的调试工作内容进行保存 - 支持对用户对应服务器的调试工作内容进行保存

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 54 KiB

274
package-lock.json generated
View File

@ -9,6 +9,7 @@
"version": "0.0.5", "version": "0.0.5",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.10.2", "@modelcontextprotocol/sdk": "^1.10.2",
"@seald-io/nedb": "^4.1.1",
"axios": "^1.7.7", "axios": "^1.7.7",
"bson": "^6.8.0", "bson": "^6.8.0",
"openai": "^4.93.0", "openai": "^4.93.0",
@ -119,6 +120,22 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@seald-io/binary-search-tree": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.3.tgz",
"integrity": "sha512-qv3jnwoakeax2razYaMsGI/luWdliBLHTdC6jU55hQt1hcFqzauH/HsBollQ7IR4ySTtYhT+xyHoijpA16C+tA=="
},
"node_modules/@seald-io/nedb": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@seald-io/nedb/-/nedb-4.1.1.tgz",
"integrity": "sha512-u7fVfzKQ/3ZaIOnYQONf2lPZtGUeQtMPjfcaQkCw/GZv5dzn20qKW6sfN0NkVbr0ksJMlWcFXNGcXYsQSb1a1g==",
"license": "MIT",
"dependencies": {
"@seald-io/binary-search-tree": "^1.0.3",
"localforage": "^1.9.0",
"util": "^0.12.4"
}
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-9.6.1.tgz", "resolved": "https://registry.npmmirror.com/@types/eslint/-/eslint-9.6.1.tgz",
@ -526,6 +543,21 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/axios": { "node_modules/axios": {
"version": "1.8.4", "version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
@ -631,6 +663,24 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/call-bind": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
"integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.0",
"es-define-property": "^1.0.0",
"get-intrinsic": "^1.2.4",
"set-function-length": "^1.2.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": { "node_modules/call-bind-apply-helpers": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
@ -844,6 +894,23 @@
} }
} }
}, },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
"gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": { "node_modules/delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@ -1270,6 +1337,21 @@
} }
} }
}, },
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
@ -1401,6 +1483,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/has-property-descriptors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": { "node_modules/has-symbols": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
@ -1483,6 +1577,12 @@
"integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==",
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
"license": "MIT"
},
"node_modules/import-local": { "node_modules/import-local": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmmirror.com/import-local/-/import-local-3.2.0.tgz", "resolved": "https://registry.npmmirror.com/import-local/-/import-local-3.2.0.tgz",
@ -1526,6 +1626,34 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/is-arguments": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
"integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.16.1", "version": "2.16.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
@ -1541,6 +1669,24 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-generator-function": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
"get-proto": "^1.0.0",
"has-tostringtag": "^1.0.2",
"safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number": { "node_modules/is-number": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz",
@ -1568,6 +1714,39 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
"integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-typed-array": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-url": { "node_modules/is-url": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
@ -1639,6 +1818,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/lie": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
"license": "MIT",
"dependencies": {
"immediate": "~3.0.5"
}
},
"node_modules/loader-runner": { "node_modules/loader-runner": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz",
@ -1648,6 +1836,15 @@
"node": ">=6.11.5" "node": ">=6.11.5"
} }
}, },
"node_modules/localforage": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
"license": "Apache-2.0",
"dependencies": {
"lie": "3.1.1"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
@ -2009,6 +2206,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/proxy-addr": { "node_modules/proxy-addr": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -2180,6 +2386,23 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/safe-regex-test": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
"integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-regex": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@ -2284,6 +2507,23 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
"get-intrinsic": "^1.2.4",
"gopd": "^1.0.1",
"has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@ -2681,6 +2921,19 @@
"browserslist": ">= 4.21.0" "browserslist": ">= 4.21.0"
} }
}, },
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
"is-generator-function": "^1.0.7",
"is-typed-array": "^1.1.3",
"which-typed-array": "^1.1.2"
}
},
"node_modules/uuid": { "node_modules/uuid": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
@ -2886,6 +3139,27 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/which-typed-array": {
"version": "1.1.19",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
"integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
"call-bind": "^1.0.8",
"call-bound": "^1.0.4",
"for-each": "^0.3.5",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/wildcard": { "node_modules/wildcard": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz",

View File

@ -41,10 +41,29 @@
"dark": "./icons/dark/protocol.svg" "dark": "./icons/dark/protocol.svg"
} }
}, },
{
"command": "openmcp.sidebar.workspace-connection.deleteConnection",
"title": "删除连接",
"category": "openmcp",
"icon": "$(trash)"
},
{ {
"command": "openmcp.sidebar.workspace-connection.refresh", "command": "openmcp.sidebar.workspace-connection.refresh",
"title": "刷新", "title": "刷新",
"category": "openmcp" "category": "openmcp",
"icon": "$(refresh)"
},
{
"command": "openmcp.sidebar.workspace-connection.addConnection",
"title": "添加连接",
"category": "openmcp",
"icon": "$(add)"
},
{
"command": "openmcp.sidebar.workspace-connection.openConfiguration",
"title": "打开配置",
"category": "openmcp",
"icon": "$(gear)"
} }
], ],
"menus": { "menus": {
@ -55,6 +74,23 @@
"when": "editorLangId == python || editorLangId == javascript || editorLangId == typescript || editorLangId == java || editorLangId == csharp" "when": "editorLangId == python || editorLangId == javascript || editorLangId == typescript || editorLangId == java || editorLangId == csharp"
} }
], ],
"view/title": [
{
"command": "openmcp.sidebar.workspace-connection.refresh",
"group": "navigation",
"when": "view == openmcp.sidebar-view.workspace-connection"
},
{
"command": "openmcp.sidebar.workspace-connection.addConnection",
"group": "navigation",
"when": "view == openmcp.sidebar-view.workspace-connection"
},
{
"command": "openmcp.sidebar.workspace-connection.openConfiguration",
"group": "navigation",
"when": "view == openmcp.sidebar-view.workspace-connection"
}
],
"view/item/context": [ "view/item/context": [
{ {
"command": "openmcp.sidebar.workspace-connection.revealWebviewPanel", "command": "openmcp.sidebar.workspace-connection.revealWebviewPanel",
@ -63,6 +99,14 @@
"args": { "args": {
"view": "${viewItem}" "view": "${viewItem}"
} }
},
{
"command": "openmcp.sidebar.workspace-connection.deleteConnection",
"group": "inline@2",
"when": "view == openmcp.sidebar-view.workspace-connection",
"args": {
"view": "${viewItem}"
}
} }
] ]
}, },
@ -102,6 +146,7 @@
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.10.2", "@modelcontextprotocol/sdk": "^1.10.2",
"@seald-io/nedb": "^4.1.1",
"axios": "^1.7.7", "axios": "^1.7.7",
"bson": "^6.8.0", "bson": "^6.8.0",
"openai": "^4.93.0", "openai": "^4.93.0",

View File

@ -82,7 +82,7 @@ class MessageBridge {
this.postMessage = (message) => { this.postMessage = (message) => {
if (this.ws?.readyState === WebSocket.OPEN) { if (this.ws?.readyState === WebSocket.OPEN) {
console.log('send', { command: message.command }); console.log('send', message);
this.ws.send(JSON.stringify(message)); this.ws.send(JSON.stringify(message));
} }
}; };

2
service/.gitignore vendored
View File

@ -24,6 +24,6 @@ pnpm-debug.log*
config.json config.json
setting.json setting.json
tabs.example-servers/puppeteer.json
*.traineddata *.traineddata
.env .env
tabs.example-servers_puppeteer.json

View File

@ -104,6 +104,11 @@ class DiskStorage {
} }
public setSync(filename: string, data: string | Buffer, options?: fs.WriteFileOptions): void { public setSync(filename: string, data: string | Buffer, options?: fs.WriteFileOptions): void {
if (!fs.existsSync(this.#storageHome)) {
fs.mkdirSync(this.#storageHome, { recursive: true });
}
const filePath = path.join(this.#storageHome, filename); const filePath = path.join(this.#storageHome, filename);
fs.writeFileSync(filePath, data, options); fs.writeFileSync(filePath, data, options);
} }

View File

@ -12,7 +12,11 @@ const DEFAULT_TABS: SaveTab = {
function getTabSavePath(serverInfo: IServerVersion) { function getTabSavePath(serverInfo: IServerVersion) {
const { name = 'untitle', version = '0.0.0' } = serverInfo || {}; const { name = 'untitle', version = '0.0.0' } = serverInfo || {};
const tabSaveName = `tabs.${name}.json`;
// 过滤所有不能成为路径的字符
const escapeName = name.replace(/[\\/:*?"<>|]/g, '_');
const tabSaveName = `tabs.${escapeName}.json`;
// 如果是 vscode 插件下,则修改为 ~/.vscode/openmcp.json // 如果是 vscode 插件下,则修改为 ~/.vscode/openmcp.json
if (VSCODE_WORKSPACE) { if (VSCODE_WORKSPACE) {

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -31,7 +31,7 @@
}, },
"build": { "build": {
"appId": "com.electron.openmcp", "appId": "com.electron.openmcp",
"productName": "OpenMCP", "productName": "OpenMCP Desktop",
"asar": true, "asar": true,
"asarUnpack": "*.node", "asarUnpack": "*.node",
"directories": { "directories": {

View File

@ -77,6 +77,10 @@ function createWindow(): void {
const indexPath = path.join(__dirname, '..', 'resources/renderer/index.html'); const indexPath = path.join(__dirname, '..', 'resources/renderer/index.html');
mainWindow.loadFile(indexPath); mainWindow.loadFile(indexPath);
setTimeout(() => {
mainWindow.webContents.openDevTools();
}, 1000);
} }
app.whenReady().then(() => { app.whenReady().then(() => {

View File

@ -2,6 +2,7 @@
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as os from 'os';
export class ElectronIPCLike { export class ElectronIPCLike {
private webContents: Electron.WebContents; private webContents: Electron.WebContents;
@ -49,8 +50,17 @@ export function refreshConnectionOption(envPath: string) {
return defaultOption; return defaultOption;
} }
function getEnvPath() {
const homepath = os.homedir();
const envPathDir = path.join(homepath, '.openmcp', 'desktop');
if (!fs.existsSync(envPathDir)) {
fs.mkdirSync(envPathDir, { recursive: true });
}
return path.join(envPathDir, '.env');
}
export function getInitConnectionOption() { export function getInitConnectionOption() {
const envPath = path.join(__dirname, '..', '.env'); const envPath = getEnvPath();
if (!fs.existsSync(envPath)) { if (!fs.existsSync(envPath)) {
return refreshConnectionOption(envPath); return refreshConnectionOption(envPath);
@ -66,7 +76,7 @@ export function getInitConnectionOption() {
} }
export function updateConnectionOption(data: any) { export function updateConnectionOption(data: any) {
const envPath = path.join(__dirname, '..', '.env'); const envPath = getEnvPath();
if (data.connectionType === 'STDIO') { if (data.connectionType === 'STDIO') {
const connectionItem = { const connectionItem = {

22
src/common/entry.ts Normal file
View File

@ -0,0 +1,22 @@
import * as vscode from 'vscode';
import { registerCommands, registerTreeDataProviders } from '.';
export const InstallModules = [
];
export function launch(context: vscode.ExtensionContext) {
for (const [command, value] of registerCommands) {
context.subscriptions.push(vscode.commands.registerCommand(command, (...args: any[]) => {
value.handler(context, ...args);
}));
}
for (const [providerId, value] of registerTreeDataProviders) {
context.subscriptions.push(
vscode.window.registerTreeDataProvider(providerId, value.provider)
);
}
}

24
src/common/index.dto.ts Normal file
View File

@ -0,0 +1,24 @@
import type { TreeDataProvider, ExtensionContext } from 'vscode';
export interface CustomDescriptor<T> {
configurable?: boolean;
enumerable?: boolean;
value?: T;
writable?: boolean;
get?(): any;
set?(v: any): void;
}
export interface IRegisterCommandItem {
handler: (context: ExtensionContext, ...args: any[]) => void;
options?: any;
}
export type CommandHandlerDescriptor = CustomDescriptor<IRegisterCommandItem['handler']>;
export interface IRegisterTreeDataProviderItem<T> {
provider: TreeDataProvider<T>;
options?: any;
}
export type TreeDataProviderDescriptor<T> = CustomDescriptor<IRegisterTreeDataProviderItem<T>['provider']>;

34
src/common/index.ts Normal file
View File

@ -0,0 +1,34 @@
import { CommandHandlerDescriptor, IRegisterCommandItem, IRegisterTreeDataProviderItem, TreeDataProviderDescriptor } from "./index.dto";
export const registerCommands = new Map<string, IRegisterCommandItem>();
export const registerTreeDataProviders = new Map<string, IRegisterTreeDataProviderItem<any>>();
export function RegisterCommand(command: string, options?: any) {
return function(target: any, propertyKey: string, descriptor: CommandHandlerDescriptor) {
const handler = descriptor.value;
// 根据 option 进行的操作
// ...
if (handler) {
registerCommands.set(command, { handler, options });
}
return descriptor;
}
}
export function RegisterTreeDataProvider<T>(command: string, options?: any) {
return function(target: any, propertyKey: string, descriptor: TreeDataProviderDescriptor<T>) {
const provider = descriptor.value;
// 根据 option 进行的操作
// ...
if (provider) {
registerTreeDataProviders.set(command, { provider, options });
}
return descriptor;
}
}

View File

@ -1,10 +1,10 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as fspath from 'path';
import * as OpenMCPService from '../resources/service'; import * as OpenMCPService from '../resources/service';
import { getDefaultLanunchSigature, getLaunchCWD, revealOpenMcpWebviewPanel } from './webview'; import { getDefaultLanunchSigature, getLaunchCWD, revealOpenMcpWebviewPanel } from './webview';
import { ConnectionViewItem, registerSidebar } from './sidebar'; import { registerSidebar } from './sidebar';
import { getWorkspaceConnectionConfigItemByPath, ISSEConnectionItem, IStdioConnectionItem } from './global'; import { getWorkspaceConnectionConfigItemByPath } from './global';
import type { ConnectionViewItem } from './sidebar/common';
export function activate(context: vscode.ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
console.log('activate openmcp'); console.log('activate openmcp');
@ -21,8 +21,14 @@ export function activate(context: vscode.ExtensionContext) {
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.revealWebviewPanel', (view: ConnectionViewItem) => { vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.revealWebviewPanel', (view: ConnectionViewItem) => {
const item = view.item; const item = view.item;
revealOpenMcpWebviewPanel(context, item.filePath || item.name, item); revealOpenMcpWebviewPanel(context, item.filePath || item.name, item);
}) }
); ));
context.subscriptions.push(
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.deleteConnection', (view: ConnectionViewItem) => {
deleteConnection(context, view);
}
));
context.subscriptions.push( context.subscriptions.push(
vscode.commands.registerCommand('openmcp.showOpenMCP', async (uri: vscode.Uri) => { vscode.commands.registerCommand('openmcp.showOpenMCP', async (uri: vscode.Uri) => {

View File

@ -1,122 +0,0 @@
import * as vscode from 'vscode';
import { getConnectionConfig, getWorkspaceConnectionConfig, IConnectionItem } from './global';
class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<ConnectionViewItem> {
private _onDidChangeTreeData: vscode.EventEmitter<ConnectionViewItem | undefined | null | void> = new vscode.EventEmitter<ConnectionViewItem | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<ConnectionViewItem | undefined | null | void> = this._onDidChangeTreeData.event;
constructor(private context: vscode.ExtensionContext) {
}
// 实现 TreeDataProvider 接口
getTreeItem(element: ConnectionViewItem): vscode.TreeItem {
return element;
}
getChildren(element?: ConnectionViewItem): Thenable<ConnectionViewItem[]> {
// TODO: 读取 configDir 下的所有文件,作为子节点
const connection = getWorkspaceConnectionConfig();
const sidebarItems = connection.items.map((item, index) => {
// 连接的名字
const itemName = `${item.name} (${item.type})`
return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server');
})
// 返回子节点
return Promise.resolve(sidebarItems);
}
// 添加 refresh 方法
public refresh(): void {
this._onDidChangeTreeData.fire();
}
}
// 在 registerSidebar 函数中注册 refresh 命令
export function registerSidebar(context: vscode.ExtensionContext) {
const workspaceConnectionProvider = new McpWorkspaceConnectProvider(context);
// 注册 refresh 命令
context.subscriptions.push(
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.refresh', () => {
workspaceConnectionProvider.refresh();
})
);
// 注册 MCP 连接的 sidebar 视图
context.subscriptions.push(
vscode.window.registerTreeDataProvider('openmcp.sidebar-view.workspace-connection', workspaceConnectionProvider)
);
// 注册 入门与帮助的 sidebar 视图
context.subscriptions.push(
vscode.window.registerTreeDataProvider('openmcp.sidebar.help', new HelpProvider(context))
);
}
class HelpProvider implements vscode.TreeDataProvider<SidebarItem> {
constructor(private context: vscode.ExtensionContext) {
}
// 实现 TreeDataProvider 接口
getTreeItem(element: SidebarItem): vscode.TreeItem {
return element;
}
getChildren(element?: SidebarItem): Thenable<SidebarItem[]> {
// 返回子节点
return Promise.resolve([
new SidebarItem('入门', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Open Guide',
arguments: [vscode.Uri.parse('https://zhuanlan.zhihu.com/p/1894785817186121106')]
}, 'book'),
new SidebarItem('阅读文档', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Open Documentation',
arguments: [vscode.Uri.parse('https://document.kirigaya.cn/blogs/openmcp/main.html')]
}, 'file-text'),
new SidebarItem('报告问题', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Report Issue',
arguments: [vscode.Uri.parse('https://github.com/LSTM-Kirigaya/openmcp-client/issues')]
}, 'bug'),
new SidebarItem('参与项目', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Join Project',
arguments: [vscode.Uri.parse('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')]
}, 'organization'),
new SidebarItem('评论插件', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Review Extension',
arguments: [vscode.Uri.parse('https://marketplace.visualstudio.com/items?itemName=kirigaya.openmcp&ssr=false#review-details')]
}, 'feedback')
]);
}
}
class SidebarItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
public readonly command?: vscode.Command,
public readonly icon?: string
) {
super(label, collapsibleState);
this.command = command;
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
}
}
export class ConnectionViewItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
public readonly item: IConnectionItem,
public readonly icon?: string
) {
super(label, collapsibleState);
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
}
}

27
src/sidebar/common.ts Normal file
View File

@ -0,0 +1,27 @@
import * as vscode from 'vscode';
import type { IConnectionItem } from '../global';
export class SidebarItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
public readonly command?: vscode.Command,
public readonly icon?: string
) {
super(label, collapsibleState);
this.command = command;
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
}
}
export class ConnectionViewItem extends vscode.TreeItem {
constructor(
public readonly label: string,
public readonly collapsibleState: vscode.TreeItemCollapsibleState,
public readonly item: IConnectionItem,
public readonly icon?: string
) {
super(label, collapsibleState);
this.iconPath = new vscode.ThemeIcon(icon || 'circle-outline');
}
}

0
src/sidebar/global@2.ts Normal file
View File

45
src/sidebar/help@3.ts Normal file
View File

@ -0,0 +1,45 @@
import * as vscode from 'vscode';
import { SidebarItem } from './common';
export class HelpProvider implements vscode.TreeDataProvider<SidebarItem> {
constructor(private context: vscode.ExtensionContext) {
}
// 实现 TreeDataProvider 接口
getTreeItem(element: SidebarItem): vscode.TreeItem {
return element;
}
getChildren(element?: SidebarItem): Thenable<SidebarItem[]> {
// 返回子节点
return Promise.resolve([
new SidebarItem('入门', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Open Guide',
arguments: [vscode.Uri.parse('https://zhuanlan.zhihu.com/p/1896301240826184013')]
}, 'book'),
new SidebarItem('阅读文档', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Open Documentation',
arguments: [vscode.Uri.parse('https://document.kirigaya.cn/blogs/openmcp/main.html')]
}, 'file-text'),
new SidebarItem('报告问题', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Report Issue',
arguments: [vscode.Uri.parse('https://github.com/LSTM-Kirigaya/openmcp-client/issues')]
}, 'bug'),
new SidebarItem('参与项目', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Join Project',
arguments: [vscode.Uri.parse('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')]
}, 'organization'),
new SidebarItem('评论插件', vscode.TreeItemCollapsibleState.None, {
command: 'vscode.open',
title: 'Review Extension',
arguments: [vscode.Uri.parse('https://marketplace.visualstudio.com/items?itemName=kirigaya.openmcp&ssr=false#review-details')]
}, 'feedback')
]);
}
}

29
src/sidebar/index.ts Normal file
View File

@ -0,0 +1,29 @@
import * as vscode from 'vscode';
import { McpWorkspaceConnectProvider } from './workspace@1';
import { HelpProvider } from './help@3';
// 在 registerSidebar 函数中注册 refresh 命令
export function registerSidebar(context: vscode.ExtensionContext) {
const workspaceConnectionProvider = new McpWorkspaceConnectProvider(context);
// 注册 refresh 命令
context.subscriptions.push(
vscode.commands.registerCommand('openmcp.sidebar.workspace-connection.refresh', () => {
workspaceConnectionProvider.refresh();
})
);
// 注册 MCP 连接的 sidebar 视图
context.subscriptions.push(
vscode.window.registerTreeDataProvider('openmcp.sidebar-view.workspace-connection', workspaceConnectionProvider)
);
// 注册 MCP 连接的 sidebar 视图
// 注册 入门与帮助的 sidebar 视图
context.subscriptions.push(
vscode.window.registerTreeDataProvider('openmcp.sidebar.help', new HelpProvider(context))
);
}

View File

@ -0,0 +1,69 @@
import * as vscode from 'vscode';
import { ConnectionViewItem } from './common';
import { getWorkspaceConnectionConfig, getWorkspacePath, panels, saveWorkspaceConnectionConfig } from '../global';
export class McpWorkspaceConnectProvider implements vscode.TreeDataProvider<ConnectionViewItem> {
private _onDidChangeTreeData: vscode.EventEmitter<ConnectionViewItem | undefined | null | void> = new vscode.EventEmitter<ConnectionViewItem | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<ConnectionViewItem | undefined | null | void> = this._onDidChangeTreeData.event;
constructor(private context: vscode.ExtensionContext) {
}
// 实现 TreeDataProvider 接口
getTreeItem(element: ConnectionViewItem): vscode.TreeItem {
return element;
}
getChildren(element?: ConnectionViewItem): Thenable<ConnectionViewItem[]> {
// TODO: 读取 configDir 下的所有文件,作为子节点
const connection = getWorkspaceConnectionConfig();
const sidebarItems = connection.items.map((item, index) => {
// 连接的名字
const itemName = `${item.name} (${item.type})`
return new ConnectionViewItem(itemName, vscode.TreeItemCollapsibleState.None, item, 'server');
})
// 返回子节点
return Promise.resolve(sidebarItems);
}
// 添加 refresh 方法
public refresh(): void {
this._onDidChangeTreeData.fire();
}
}
export async function deleteConnection(context: vscode.ExtensionContext, view: ConnectionViewItem) {
const workspaceConnectionConfig = getWorkspaceConnectionConfig();
const connectionItem = view.item;
// 弹出确认对话框
const confirm = await vscode.window.showWarningMessage(
`确定要删除连接 "${connectionItem.name}" 吗?`,
{ modal: true },
'确定'
);
if (confirm !== '确定') {
return; // 用户取消删除
}
// 从配置中移除该连接项
const index = workspaceConnectionConfig.items.indexOf(connectionItem);
if (index !== -1) {
workspaceConnectionConfig.items.splice(index, 1);
// 保存更新后的配置
const workspacePath = getWorkspacePath();
saveWorkspaceConnectionConfig(workspacePath);
// 刷新侧边栏视图
vscode.commands.executeCommand('openmcp.sidebar.workspace-connection.refresh');
// 如果该连接有对应的webview面板则关闭它
if (panels.has(connectionItem.filePath || connectionItem.name)) {
const panel = panels.get(connectionItem.filePath || connectionItem.name);
panel?.dispose();
}
}
}

View File

@ -1,7 +1,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as fs from 'fs'; import * as fs from 'fs';
import * as fspath from 'path'; import * as fspath from 'path';
import { IConnectionItem, ILaunchSigature, panels, updateWorkspaceConnectionConfig } from './global'; import { getWorkspaceConnectionConfig, getWorkspacePath, IConnectionItem, ILaunchSigature, panels, saveWorkspaceConnectionConfig, updateWorkspaceConnectionConfig } from './global';
import * as OpenMCPService from '../resources/service'; import * as OpenMCPService from '../resources/service';