Compare commits
10 Commits
64df3b93bf
...
a107dc04ff
Author | SHA1 | Date | |
---|---|---|---|
a107dc04ff | |||
c8a9951be6 | |||
c964f79c99 | |||
3404c88d0e | |||
14afb06ee5 | |||
5a5730da74 | |||
76a6e07756 | |||
f1b3f6fbad | |||
b1515e9ac3 | |||
be9fc5f2f9 |
@ -17,4 +17,5 @@ service/**
|
|||||||
test/**
|
test/**
|
||||||
servers/**
|
servers/**
|
||||||
scripts/**
|
scripts/**
|
||||||
*.sh
|
*.sh
|
||||||
|
*.ps1
|
@ -1,6 +1,9 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
## [dev] 0.0.1
|
## [main] 0.0.1
|
||||||
|
|
||||||
- finish basic dev
|
- 完成 openmcp 的基础 inspector 功能
|
||||||
- finish backend for testing
|
- 完成配置加载,保存,大模型设置
|
||||||
|
- 完成标签页自动保存
|
||||||
|
- 完成大模型对话窗口和工具调用
|
||||||
|
- 完成对 vscode 和 trae 的支持
|
200
LICENSE
Normal file
200
LICENSE
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law or agreed to in writing, shall
|
||||||
|
any Contributor be liable to You for damages, including any direct,
|
||||||
|
indirect, special, incidental, or consequential damages of any character
|
||||||
|
arising as a result of this License or out of the use or inability to use
|
||||||
|
the Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting any such obligations, You may act
|
||||||
|
only on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, any Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [2024] [Kirigaya]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
@ -1,6 +1,6 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
<img src="./renderer/public/images/openmcp.svg" height="200px"/>
|
<img src="./icons/openmcp.png" height="200px"/>
|
||||||
|
|
||||||
<h3>OpenMCP: 一体化 MCP Server 调试器</h3>
|
<h3>OpenMCP: 一体化 MCP Server 调试器</h3>
|
||||||
|
|
||||||
@ -30,6 +30,7 @@
|
|||||||
- [ ] 支持 completion/complete 协议字段
|
- [ ] 支持 completion/complete 协议字段
|
||||||
- [x] 支持 对用户对应服务器的调试工作内容进行保存
|
- [x] 支持 对用户对应服务器的调试工作内容进行保存
|
||||||
- [ ] 高危操作权限确认
|
- [ ] 高危操作权限确认
|
||||||
|
- [ ] 对于连接的 mcp server 进行热更新
|
||||||
|
|
||||||
|
|
||||||
## Dev
|
## Dev
|
||||||
|
@ -20,4 +20,4 @@ Wait-Job -Job $jobs | Out-Null
|
|||||||
Receive-Job -Job $jobs
|
Receive-Job -Job $jobs
|
||||||
Remove-Job -Job $jobs
|
Remove-Job -Job $jobs
|
||||||
|
|
||||||
Write-Host "构建完成,dist文件已移动到resources目录"
|
Write-Host "finish building services in ./resources"
|
||||||
|
@ -4,4 +4,4 @@ mkdir -p ./resources
|
|||||||
(cd ./renderer && npm run build && mv ./dist ../resources/renderer) &
|
(cd ./renderer && npm run build && mv ./dist ../resources/renderer) &
|
||||||
(cd ./service && npm run build && mv ./dist ../resources/service) &
|
(cd ./service && npm run build && mv ./dist ../resources/service) &
|
||||||
wait
|
wait
|
||||||
echo "构建完成,dist文件已移动到resources目录"
|
echo "finish building services in ./resources"
|
||||||
|
BIN
icons/openmcp.png
Normal file
BIN
icons/openmcp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -1,9 +1,22 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<svg viewBox="0 0 824 834" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<svg t="1742640634061" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
<defs>
|
||||||
xmlns="http://www.w3.org/2000/svg" p-id="1503" data-darkreader-inline-fill=""
|
<path id="path_1" d="M300 0C465.708 0 600 134.292 600 300L600 300C600 465.708 465.708 600 300 600L300 600C134.292 600 0 465.708 0 300L0 300C0 134.292 134.292 0 300 0Z" />
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
|
<linearGradient id="gradient_2" gradientUnits="userSpaceOnUse" x1="300" y1="0" x2="300" y2="600">
|
||||||
<path
|
<stop offset="0" stop-color="#A1A7F6" />
|
||||||
d="M768 854.016h-170.016L768 170.016h170.016L768 854.016zM682.016 170.016H512l-170.016 684H512l170.016-684zM86.016 704q0 44 31.008 75.008t75.008 31.008 75.008-31.008T298.048 704t-31.008-75.008-75.008-31.008-75.008 31.008T86.016 704z m0-297.984q0 44 31.008 75.008t75.008 31.008 75.008-31.008 31.008-75.008-31.008-76-75.008-32-75.008 32-31.008 76z"
|
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0.2" />
|
||||||
p-id="1504" fill="#CB81DA"></path>
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<g>
|
||||||
|
<g transform="translate(186 116)">
|
||||||
|
<use p4:href="#path_1" fill="#5A00FF" xmlns:p4="http://www.w3.org/1999/xlink" />
|
||||||
|
<use p4:href="#path_1" fill="url(#gradient_2)" xmlns:p4="http://www.w3.org/1999/xlink" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<path d="M300 0C465.708 0 600 134.292 600 300L600 300C600 465.708 465.708 600 300 600L300 600C134.292 600 0 465.708 0 300L0 300C0 134.292 134.292 0 300 0Z" />
|
||||||
|
<path d="M0 110.5C0 49.4725 49.4725 0 110.5 0C171.527 0 221 49.4725 221 110.5C221 171.527 171.527 221 110.5 221C49.4725 221 0 171.527 0 110.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(445 458)" />
|
||||||
|
<path d="M0 55.5C0 24.8482 24.8482 0 55.5 0C86.1518 0 111 24.8482 111 55.5C111 86.1518 86.1518 111 55.5 111C24.8482 111 0 86.1518 0 55.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(199 386)" />
|
||||||
|
<path d="M0 182.5C0 81.708 81.708 0 182.5 0C283.292 0 365 81.708 365 182.5C365 283.292 283.292 365 182.5 365C81.708 365 0 283.292 0 182.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.424" transform="translate(339 156)" />
|
||||||
|
<path d="M0 57C0 25.5198 25.5198 0 57 0C88.4802 0 114 25.5198 114 57C114 88.4802 88.4802 114 57 114C25.5198 114 0 88.4802 0 57Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(521 188)" />
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 759 B After Width: | Height: | Size: 1.8 KiB |
1411
package-lock.json
generated
1411
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -1,8 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"displayName": "openmcp",
|
"displayName": "OpenMCP",
|
||||||
"description": "A MCP Client for MCP/OpenMCP",
|
"description": "An all in one MCP Client/TestTool",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
"publisher": "kirigaya",
|
||||||
|
"author": {
|
||||||
|
"name": "kirigaya",
|
||||||
|
"email": "1193466151@qq.com"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"url": "https://github.com/LSTM-Kirigaya/openmcp-client",
|
||||||
|
"type": "git"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.95.0"
|
"vscode": "^1.95.0"
|
||||||
},
|
},
|
||||||
@ -11,6 +20,7 @@
|
|||||||
],
|
],
|
||||||
"activationEvents": [],
|
"activationEvents": [],
|
||||||
"main": "./dist/extension.js",
|
"main": "./dist/extension.js",
|
||||||
|
"icon": "icons/openmcp.png",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
@ -72,6 +82,10 @@
|
|||||||
"@types/node": "16.x",
|
"@types/node": "16.x",
|
||||||
"@types/pako": "^2.0.3",
|
"@types/pako": "^2.0.3",
|
||||||
"@types/showdown": "^2.0.0",
|
"@types/showdown": "^2.0.0",
|
||||||
"@types/vscode": "^1.72.0"
|
"@types/vscode": "^1.72.0",
|
||||||
|
"ts-loader": "^9.5.1",
|
||||||
|
"typescript": "^5.4.2",
|
||||||
|
"webpack": "^5.88.2",
|
||||||
|
"webpack-cli": "^5.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 4870215 */
|
font-family: "iconfont"; /* Project id 4870215 */
|
||||||
src: url('iconfont.woff2?t=1744289078529') format('woff2'),
|
src: url('iconfont.woff2?t=1744476757936') format('woff2'),
|
||||||
url('iconfont.woff?t=1744289078529') format('woff'),
|
url('iconfont.woff?t=1744476757936') format('woff'),
|
||||||
url('iconfont.ttf?t=1744289078529') format('truetype');
|
url('iconfont.ttf?t=1744476757936') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,10 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-connect:before {
|
||||||
|
content: "\ecda";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-openmcp:before {
|
.icon-openmcp:before {
|
||||||
content: "\e666";
|
content: "\e666";
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
BIN
renderer/public/images/openmcp.png
Normal file
BIN
renderer/public/images/openmcp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -12,6 +12,8 @@
|
|||||||
<use p4:href="#path_1" fill="#5A00FF" xmlns:p4="http://www.w3.org/1999/xlink" />
|
<use p4:href="#path_1" fill="#5A00FF" xmlns:p4="http://www.w3.org/1999/xlink" />
|
||||||
<use p4:href="#path_1" fill="url(#gradient_2)" xmlns:p4="http://www.w3.org/1999/xlink" />
|
<use p4:href="#path_1" fill="url(#gradient_2)" xmlns:p4="http://www.w3.org/1999/xlink" />
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
|
<path d="M300 0C465.708 0 600 134.292 600 300L600 300C600 465.708 465.708 600 300 600L300 600C134.292 600 0 465.708 0 300L0 300C0 134.292 134.292 0 300 0Z" />
|
||||||
<path d="M0 110.5C0 49.4725 49.4725 0 110.5 0C171.527 0 221 49.4725 221 110.5C221 171.527 171.527 221 110.5 221C49.4725 221 0 171.527 0 110.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(445 458)" />
|
<path d="M0 110.5C0 49.4725 49.4725 0 110.5 0C171.527 0 221 49.4725 221 110.5C221 171.527 171.527 221 110.5 221C49.4725 221 0 171.527 0 110.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(445 458)" />
|
||||||
<path d="M0 55.5C0 24.8482 24.8482 0 55.5 0C86.1518 0 111 24.8482 111 55.5C111 86.1518 86.1518 111 55.5 111C24.8482 111 0 86.1518 0 55.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(199 386)" />
|
<path d="M0 55.5C0 24.8482 24.8482 0 55.5 0C86.1518 0 111 24.8482 111 55.5C111 86.1518 86.1518 111 55.5 111C24.8482 111 0 86.1518 0 55.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(199 386)" />
|
||||||
<path d="M0 182.5C0 81.708 81.708 0 182.5 0C283.292 0 365 81.708 365 182.5C365 283.292 283.292 365 182.5 365C81.708 365 0 283.292 0 182.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.424" transform="translate(339 156)" />
|
<path d="M0 182.5C0 81.708 81.708 0 182.5 0C283.292 0 365 81.708 365 182.5C365 283.292 283.292 365 182.5 365C81.708 365 0 283.292 0 182.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.424" transform="translate(339 156)" />
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
@ -123,12 +123,20 @@ a {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openmcp-code-block pre code {
|
||||||
|
background-color: none;
|
||||||
|
}
|
||||||
|
|
||||||
.openmcp-code-block pre code::-webkit-scrollbar {
|
.openmcp-code-block pre code::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tool-arguments .openmcp-code-block pre code {
|
||||||
|
background: var(--el-fill-color-light);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
.openmcp-code-block pre code::-webkit-scrollbar-track {
|
.openmcp-code-block pre code::-webkit-scrollbar-track {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
/* 浅紫色背景 */
|
/* 浅紫色背景 */
|
||||||
|
@ -14,7 +14,7 @@ import MainPanel from '@/components/main-panel/index.vue';
|
|||||||
import { setDefaultCss } from './hook/css';
|
import { setDefaultCss } from './hook/css';
|
||||||
import { pinkLog } from './views/setting/util';
|
import { pinkLog } from './views/setting/util';
|
||||||
import { acquireVsCodeApi, useMessageBridge } from './api/message-bridge';
|
import { acquireVsCodeApi, useMessageBridge } from './api/message-bridge';
|
||||||
import { connectionArgs, connectionMethods, connectionResult, doConnect } from './views/connect/connection';
|
import { connectionArgs, connectionMethods, connectionResult, doConnect, getServerVersion, launchConnect } from './views/connect/connection';
|
||||||
import { loadSetting } from './hook/setting';
|
import { loadSetting } from './hook/setting';
|
||||||
import { loadPanels } from './hook/panel';
|
import { loadPanels } from './hook/panel';
|
||||||
|
|
||||||
@ -26,16 +26,24 @@ bridge.addCommandListener('hello', data => {
|
|||||||
pinkLog(`version: ${data.version}`);
|
pinkLog(`version: ${data.version}`);
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
|
// 监听 connect
|
||||||
|
bridge.addCommandListener('connect', async data => {
|
||||||
|
const { code, msg } = data;
|
||||||
|
connectionResult.success = (code === 200);
|
||||||
|
connectionResult.logString = msg;
|
||||||
|
|
||||||
|
const res = await getServerVersion() as { name: string, version: string };
|
||||||
|
connectionResult.serverInfo.name = res.name || '';
|
||||||
|
connectionResult.serverInfo.version = res.version || '';
|
||||||
|
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function initDebug() {
|
function initDebug() {
|
||||||
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
|
|
||||||
bridge.addCommandListener('connect', data => {
|
|
||||||
const { code, msg } = data;
|
|
||||||
connectionResult.success = (code === 200);
|
|
||||||
connectionResult.logString = msg;
|
|
||||||
}, { once: true });
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 初始化 设置
|
// 初始化 设置
|
||||||
loadSetting();
|
loadSetting();
|
||||||
@ -56,18 +64,13 @@ function initProduce() {
|
|||||||
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
connectionArgs.commandString = 'mcp run ../servers/main.py';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
|
|
||||||
bridge.addCommandListener('connect', data => {
|
|
||||||
const { code, msg } = data;
|
|
||||||
connectionResult.success = (code === 200);
|
|
||||||
connectionResult.logString = msg;
|
|
||||||
}, { once: true });
|
|
||||||
|
|
||||||
// 初始化 设置
|
// 初始化 设置
|
||||||
loadSetting();
|
loadSetting();
|
||||||
|
|
||||||
// 初始化 tab
|
// 初始化 tab
|
||||||
loadPanels();
|
loadPanels();
|
||||||
|
|
||||||
|
launchConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
padding: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vscode-dark pre[class*=language-]>code {
|
.vscode-dark pre[class*=language-]>code {
|
||||||
@ -238,7 +237,6 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
padding: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vscode-light pre[class*=language-]>code {
|
.vscode-light pre[class*=language-]>code {
|
||||||
|
@ -116,7 +116,7 @@ export class TaskLoop {
|
|||||||
|
|
||||||
this.bridge.postMessage({
|
this.bridge.postMessage({
|
||||||
command: 'llm/chat/completions',
|
command: 'llm/chat/completions',
|
||||||
data: chatData
|
data: JSON.parse(JSON.stringify(chatData)),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { addNewTab, tabs, setActiveTab, closeTab } from './panel';
|
import { addNewTab, tabs, closeTab } from './panel';
|
||||||
|
|
||||||
defineComponent({ name: 'main-panel' });
|
defineComponent({ name: 'main-panel' });
|
||||||
|
|
||||||
@ -51,7 +51,17 @@ function pageAddNewTab() {
|
|||||||
|
|
||||||
// 如果当前不在 debug 路由,则切换到 debug 路由
|
// 如果当前不在 debug 路由,则切换到 debug 路由
|
||||||
if (route.name !== 'debug') {
|
if (route.name !== 'debug') {
|
||||||
router.push('/debug');
|
router.replace('/debug');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveTab(index: number) {
|
||||||
|
if (index >= 0 && index < tabs.content.length) {
|
||||||
|
tabs.activeIndex = index;
|
||||||
|
// 如果不在 debug 路由,则进入
|
||||||
|
if (route.name !== 'debug') {
|
||||||
|
router.replace('/debug');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,14 +34,7 @@ export const tabs = reactive<{
|
|||||||
],
|
],
|
||||||
activeIndex: 0,
|
activeIndex: 0,
|
||||||
get activeTab() {
|
get activeTab() {
|
||||||
return this.content[this.activeIndex] || {
|
return this.content[this.activeIndex];
|
||||||
name: 'blank',
|
|
||||||
icon: 'icon-blank',
|
|
||||||
type: 'blank',
|
|
||||||
component: undefined,
|
|
||||||
componentIndex: -1,
|
|
||||||
storage: {},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,11 +77,6 @@ export function addNewTab() {
|
|||||||
tabs.activeIndex = tabs.content.length - 1;
|
tabs.activeIndex = tabs.content.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setActiveTab(index: number) {
|
|
||||||
if (index >= 0 && index < tabs.content.length) {
|
|
||||||
tabs.activeIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeTab(index: number) {
|
export function closeTab(index: number) {
|
||||||
if (tabs.content.length <= 1) return; // 至少保留一个标签页
|
if (tabs.content.length <= 1) return; // 至少保留一个标签页
|
||||||
|
@ -7,10 +7,14 @@
|
|||||||
<el-form-item v-for="param in currentPrompt?.params" :key="param.name"
|
<el-form-item v-for="param in currentPrompt?.params" :key="param.name"
|
||||||
:label="param.name" :prop="param.name">
|
:label="param.name" :prop="param.name">
|
||||||
<el-input v-if="param.type === 'string'" v-model="formData[param.name]"
|
<el-input v-if="param.type === 'string'" v-model="formData[param.name]"
|
||||||
:placeholder="param.placeholder || `请输入${param.name}`" />
|
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||||
|
@keydown.enter.prevent="handleSubmit"
|
||||||
|
/>
|
||||||
|
|
||||||
<el-input-number v-else-if="param.type === 'number'" v-model="formData[param.name]"
|
<el-input-number v-else-if="param.type === 'number'" v-model="formData[param.name]"
|
||||||
:placeholder="param.placeholder || `请输入${param.name}`" />
|
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||||
|
@keydown.enter.prevent="handleSubmit"
|
||||||
|
/>
|
||||||
|
|
||||||
<el-switch v-else-if="param.type === 'boolean'" v-model="formData[param.name]" />
|
<el-switch v-else-if="param.type === 'boolean'" v-model="formData[param.name]" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -51,6 +55,7 @@ const tab = tabs.content[props.tabId];
|
|||||||
const tabStorage = tab.storage as PromptStorage;
|
const tabStorage = tab.storage as PromptStorage;
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
// TODO: 将 formData 装入 tabStorage
|
||||||
const formData = ref<Record<string, any>>({});
|
const formData = ref<Record<string, any>>({});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const responseData = ref<PromptsGetResponse>();
|
const responseData = ref<PromptsGetResponse>();
|
||||||
@ -109,7 +114,7 @@ function handleSubmit() {
|
|||||||
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
command: 'prompts/get',
|
command: 'prompts/get',
|
||||||
data: { promptId: currentPrompt.value.name, args: formData.value }
|
data: { promptId: currentPrompt.value.name, args: JSON.parse(JSON.stringify(formData.value)) }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,13 @@
|
|||||||
:label="param.name" :prop="param.name">
|
:label="param.name" :prop="param.name">
|
||||||
<!-- 根据不同类型渲染不同输入组件 -->
|
<!-- 根据不同类型渲染不同输入组件 -->
|
||||||
<el-input v-if="param.type === 'string'" v-model="formData[param.name]"
|
<el-input v-if="param.type === 'string'" v-model="formData[param.name]"
|
||||||
:placeholder="param.placeholder || `请输入${param.name}`" />
|
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||||
|
@keydown.enter.prevent="handleSubmit" />
|
||||||
|
|
||||||
<el-input-number v-else-if="param.type === 'number'" v-model="formData[param.name]"
|
<el-input-number v-else-if="param.type === 'number'" v-model="formData[param.name]"
|
||||||
:placeholder="param.placeholder || `请输入${param.name}`" />
|
:placeholder="param.placeholder || `请输入${param.name}`"
|
||||||
|
@keydown.enter.prevent="handleSubmit" />
|
||||||
|
|
||||||
<el-switch v-else-if="param.type === 'boolean'" v-model="formData[param.name]" />
|
<el-switch v-else-if="param.type === 'boolean'" v-model="formData[param.name]" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
@ -16,19 +16,21 @@
|
|||||||
<el-input
|
<el-input
|
||||||
v-if="property.type === 'string'"
|
v-if="property.type === 'string'"
|
||||||
v-model="formData[name]"
|
v-model="formData[name]"
|
||||||
:placeholder="t('enter') + ' ' + (property.title || name)"
|
:placeholder="t('enter') + ' ' + (property.title || name)"
|
||||||
|
@keydown.enter.prevent="handleExecute"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<el-input-number
|
<el-input-number
|
||||||
v-else-if="property.type === 'number' || property.type === 'integer'"
|
v-else-if="property.type === 'number' || property.type === 'integer'"
|
||||||
v-model="formData[name]"
|
v-model="formData[name]"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
:placeholder="t('enter') + ' ' + (property.title || name)"
|
:placeholder="t('enter') + ' ' + (property.title || name)"
|
||||||
|
@keydown.enter.prevent="handleExecute"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<el-switch
|
<el-switch
|
||||||
v-else-if="property.type === 'boolean'"
|
v-else-if="property.type === 'boolean'"
|
||||||
v-model="formData[name]"
|
v-model="formData[name]"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<el-scrollbar height="350px">
|
<el-scrollbar height="300px">
|
||||||
<div
|
<div
|
||||||
class="output-content"
|
class="output-content"
|
||||||
contenteditable="false"
|
contenteditable="false"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useMessageBridge } from '@/api/message-bridge';
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
import { ToolsListResponse, ToolCallResponse, CasualRestAPI } from '@/hook/type';
|
import { ToolsListResponse, ToolCallResponse, CasualRestAPI } from '@/hook/type';
|
||||||
|
import { pinkLog } from '@/views/setting/util';
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
export const toolsManager = reactive<{
|
export const toolsManager = reactive<{
|
||||||
@ -26,10 +27,16 @@ export function callTool(toolName: string, toolArgs: Record<string, any>) {
|
|||||||
resolve(data.msg);
|
resolve(data.msg);
|
||||||
}
|
}
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
|
pinkLog('callTool');
|
||||||
|
console.log(toolArgs);
|
||||||
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
command: 'tools/call',
|
command: 'tools/call',
|
||||||
data: { toolName, toolArgs }
|
data: {
|
||||||
|
toolName,
|
||||||
|
toolArgs: JSON.parse(JSON.stringify(toolArgs))
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -2,12 +2,24 @@
|
|||||||
<div class="connected-status-container"
|
<div class="connected-status-container"
|
||||||
@click.stop="toggleConnectionPanel()"
|
@click.stop="toggleConnectionPanel()"
|
||||||
>
|
>
|
||||||
<span
|
<span class="mcp-server-info">
|
||||||
class="status-circle"
|
<el-tooltip
|
||||||
:class="statusColorStyle"
|
class="extra-connect-container"
|
||||||
|
effect="dark"
|
||||||
|
placement="right"
|
||||||
|
:content="fullDisplayServerName"
|
||||||
>
|
>
|
||||||
|
<span class="name">{{ displayServerName }}</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
<span class="connect-status">
|
||||||
|
<span
|
||||||
|
class="status-circle"
|
||||||
|
:class="statusColorStyle"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span class="status-string">{{ statusString }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="status-string">{{ statusString }}</span>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -38,7 +50,17 @@ const statusColorStyle = computed(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const fullDisplayServerName = computed(() => {
|
||||||
|
return connectionResult.serverInfo.name + '/' + connectionResult.serverInfo.version;
|
||||||
|
});
|
||||||
|
|
||||||
|
const displayServerName = computed(() => {
|
||||||
|
if (connectionResult.serverInfo.name.length > 20) {
|
||||||
|
return connectionResult.serverInfo.name.substring(0, 20);
|
||||||
|
} else {
|
||||||
|
return connectionResult.serverInfo.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function toggleConnectionPanel() {
|
function toggleConnectionPanel() {
|
||||||
Connection.showPanel = true;
|
Connection.showPanel = true;
|
||||||
@ -59,27 +81,65 @@ function toggleConnectionPanel() {
|
|||||||
.status-circle {
|
.status-circle {
|
||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
margin-right: 10px;
|
margin-right: 8px;
|
||||||
border-radius: 99%;
|
border-radius: 99%;
|
||||||
|
box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.extra-connect-container {
|
.extra-connect-container {
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connected-status-container {
|
.connected-status-container {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: auto;
|
||||||
justify-content: center;
|
padding: 8px 0;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connected-status-container:hover .status-string {
|
.connected-status-container .connect-status {
|
||||||
color: var(--main-color);
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connected-status-container:hover {
|
||||||
|
background-color: var(--sidebar-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.status-string {
|
||||||
|
color: var(--foreground);
|
||||||
transition: var(--animation-3s);
|
transition: var(--animation-3s);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-server-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-server-info .name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
max-width: 60px;
|
||||||
|
white-space: wrap;
|
||||||
|
background-color: #f39a6d;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: .5em;
|
||||||
|
color: #1e1e1e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mcp-server-info .version {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -2,8 +2,6 @@
|
|||||||
<div class="sidebar-container">
|
<div class="sidebar-container">
|
||||||
<div>
|
<div>
|
||||||
<McpTitle></McpTitle>
|
<McpTitle></McpTitle>
|
||||||
<hr>
|
|
||||||
<br>
|
|
||||||
<SidebarItemContainer></SidebarItemContainer>
|
<SidebarItemContainer></SidebarItemContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -15,7 +13,6 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { sidebarItems } from './sidebar';
|
|
||||||
|
|
||||||
import McpTitle from './mcp-title.vue';
|
import McpTitle from './mcp-title.vue';
|
||||||
import SidebarItemContainer from './sidebar-item-container.vue';
|
import SidebarItemContainer from './sidebar-item-container.vue';
|
||||||
@ -27,7 +24,7 @@ defineComponent({ name: 'sidebar' });
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
width: 300px;
|
width: fit-content;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mcp-title">
|
<div class="mcp-title">
|
||||||
<div class="openmcp-logo" style="width: 48px; height: 48px; margin-right: 10px;"></div>
|
<div class="openmcp-logo" style="width: 48px; height: 48px; margin-top: 10px; margin-bottom: 15px; margin-right: 10px;"></div>
|
||||||
<div>OpenMCP</div>
|
<!-- <div>OpenMCP</div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sidebar-item-container">
|
<div class="sidebar-item-container">
|
||||||
<div
|
<div v-for="(item, index) of sidebarItems" :key="index">
|
||||||
class="sidebar-option-item"
|
<el-tooltip :content="t(item.ident)" placement="right">
|
||||||
:class="{'active': isActive(item.ident)}"
|
<div class="sidebar-option-item" :class="{ 'active': isActive(item.ident) }"
|
||||||
v-for="(item, index) of sidebarItems"
|
@click="gotoOption(item.ident)">
|
||||||
:key="index"
|
<span :class="`iconfont ${item.icon}`"></span>
|
||||||
@click="gotoOption(item.ident)"
|
</div>
|
||||||
>
|
</el-tooltip>
|
||||||
<span :class="`iconfont ${item.icon}`"></span>
|
|
||||||
<span>{{ t(item.ident) }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -25,11 +23,11 @@ const route = useRoute();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
function isActive(name: string) {
|
function isActive(name: string) {
|
||||||
return route.name === name;
|
return route.name === name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gotoOption(ident: string) {
|
function gotoOption(ident: string) {
|
||||||
router.push('/' + ident);
|
router.push('/' + ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +41,7 @@ function gotoOption(ident: string) {
|
|||||||
.sidebar-option-item {
|
.sidebar-option-item {
|
||||||
margin: 7px;
|
margin: 7px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
width: fit-content;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px 12px;
|
padding: 5px 12px;
|
||||||
@ -58,8 +57,11 @@ function gotoOption(ident: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-option-item .iconfont {
|
.sidebar-option-item .iconfont {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
|
width: 13px;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,5 +69,4 @@ function gotoOption(ident: string) {
|
|||||||
background-color: var(--main-light-color);
|
background-color: var(--main-light-color);
|
||||||
transition: var(--animation-3s);
|
transition: var(--animation-3s);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -6,7 +6,7 @@ export const sidebarItems = reactive([
|
|||||||
ident: 'debug'
|
ident: 'debug'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon-plugin',
|
icon: 'icon-connect',
|
||||||
ident: 'connect'
|
ident: 'connect'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { pinkLog } from "@/views/setting/util";
|
||||||
|
|
||||||
interface RgbColor {
|
interface RgbColor {
|
||||||
r: number;
|
r: number;
|
||||||
g: number;
|
g: number;
|
||||||
@ -170,6 +172,14 @@ export class MacroColor {
|
|||||||
} else {
|
} else {
|
||||||
this.theme = 'light'; // 默认主题
|
this.theme = 'light'; // 默认主题
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 额外支持 trae 的默认主题
|
||||||
|
const sidebarColorString = this.rootStyles.getPropertyValue('--sidebar');
|
||||||
|
if (sidebarColorString === backgroundColorString) {
|
||||||
|
const newSidebarColor = this.theme === 'dark' ? '#252a38' : '#edeff2';
|
||||||
|
document.documentElement.style.setProperty('--sidebar', newSidebarColor);
|
||||||
|
pinkLog('修改 sidebar 颜色为' + newSidebarColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -224,4 +234,6 @@ export class MacroColor {
|
|||||||
|
|
||||||
return toRgbCssString(mixedColor);
|
return toRgbCssString(mixedColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const macroColor = new MacroColor();
|
@ -3,7 +3,7 @@ import { llmManager, llms } from "@/views/setting/llm";
|
|||||||
import { pinkLog } from "@/views/setting/util";
|
import { pinkLog } from "@/views/setting/util";
|
||||||
import I18n from '@/i18n/index';
|
import I18n from '@/i18n/index';
|
||||||
import { debugModes, tabs } from "@/components/main-panel/panel";
|
import { debugModes, tabs } from "@/components/main-panel/panel";
|
||||||
import { markRaw } from "vue";
|
import { markRaw, ref } from "vue";
|
||||||
|
|
||||||
interface SaveTabItem {
|
interface SaveTabItem {
|
||||||
name: string;
|
name: string;
|
||||||
@ -18,6 +18,8 @@ interface SaveTab {
|
|||||||
currentIndex: number
|
currentIndex: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const panelLoaded = ref(false);
|
||||||
|
|
||||||
export function loadPanels() {
|
export function loadPanels() {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
@ -53,6 +55,7 @@ export function loadPanels() {
|
|||||||
tabs.activeIndex = persistTab.currentIndex;
|
tabs.activeIndex = persistTab.currentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
panelLoaded.value = true;
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
bridge.postMessage({
|
bridge.postMessage({
|
||||||
|
@ -6,7 +6,7 @@ import I18n from '@/i18n/index';
|
|||||||
export function loadSetting() {
|
export function loadSetting() {
|
||||||
const bridge = useMessageBridge();
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
bridge.addCommandListener('setting/load', data => {
|
bridge.addCommandListener('setting/load', data => {
|
||||||
if (data.code !== 200) {
|
if (data.code !== 200) {
|
||||||
pinkLog('配置加载失败');
|
pinkLog('配置加载失败');
|
||||||
console.log(data.msg);
|
console.log(data.msg);
|
||||||
|
@ -1,40 +1,41 @@
|
|||||||
import { useMessageBridge } from '@/api/message-bridge';
|
import { useMessageBridge } from '@/api/message-bridge';
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
|
import { pinkLog } from '../setting/util';
|
||||||
|
|
||||||
export const connectionMethods = reactive({
|
export const connectionMethods = reactive({
|
||||||
current: 'STDIO',
|
current: 'STDIO',
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
value: 'STDIO',
|
value: 'STDIO',
|
||||||
label: 'STDIO'
|
label: 'STDIO'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'SSE',
|
value: 'SSE',
|
||||||
label: 'SSE'
|
label: 'SSE'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
export const connectionArgs = reactive({
|
export const connectionArgs = reactive({
|
||||||
commandString: '',
|
commandString: '',
|
||||||
urlString: ''
|
urlString: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface EnvItem {
|
export interface EnvItem {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IConnectionEnv {
|
export interface IConnectionEnv {
|
||||||
data: EnvItem[]
|
data: EnvItem[]
|
||||||
newKey: string
|
newKey: string
|
||||||
newValue: string
|
newValue: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const connectionEnv = reactive<IConnectionEnv>({
|
export const connectionEnv = reactive<IConnectionEnv>({
|
||||||
data: [],
|
data: [],
|
||||||
newKey: '',
|
newKey: '',
|
||||||
newValue: ''
|
newValue: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ export function doConnect() {
|
|||||||
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||||
const command = commandComponents[0];
|
const command = commandComponents[0];
|
||||||
commandComponents.shift();
|
commandComponents.shift();
|
||||||
|
|
||||||
connectOption = {
|
connectOption = {
|
||||||
connectionType: 'STDIO',
|
connectionType: 'STDIO',
|
||||||
command: command,
|
command: command,
|
||||||
@ -97,6 +98,63 @@ export function doConnect() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description vscode 中初始化启动
|
||||||
|
*/
|
||||||
|
export async function launchConnect() {
|
||||||
|
// 本地开发只用 IPC 进行启动
|
||||||
|
// 后续需要考虑到不同的连接方式
|
||||||
|
|
||||||
|
connectionMethods.current = 'STDIO';
|
||||||
|
|
||||||
|
pinkLog('请求启动参数');
|
||||||
|
const { commandString, cwd } = await getLaunchCommand();
|
||||||
|
|
||||||
|
connectionArgs.commandString = commandString;
|
||||||
|
|
||||||
|
if (connectionArgs.commandString.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandComponents = connectionArgs.commandString.split(/\s+/g);
|
||||||
|
const command = commandComponents[0];
|
||||||
|
commandComponents.shift();
|
||||||
|
|
||||||
|
const connectOption = {
|
||||||
|
connectionType: 'STDIO',
|
||||||
|
command: command,
|
||||||
|
args: commandComponents,
|
||||||
|
cwd: cwd,
|
||||||
|
clientName: 'openmcp.connect.stdio.' + command,
|
||||||
|
clientVersion: '0.0.1'
|
||||||
|
};
|
||||||
|
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'connect',
|
||||||
|
data: connectOption
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getLaunchCommand() {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
// 与 vscode 进行同步
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
|
||||||
|
bridge.addCommandListener('vscode/launch-command', data => {
|
||||||
|
pinkLog('收到启动参数');
|
||||||
|
resolve(data.msg);
|
||||||
|
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'vscode/launch-command',
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function doReconnect() {
|
export function doReconnect() {
|
||||||
// TODO: finish this
|
// TODO: finish this
|
||||||
console.log();
|
console.log();
|
||||||
@ -104,5 +162,26 @@ export function doReconnect() {
|
|||||||
|
|
||||||
export const connectionResult = reactive({
|
export const connectionResult = reactive({
|
||||||
success: false,
|
success: false,
|
||||||
logString: ''
|
logString: '',
|
||||||
});
|
serverInfo: {
|
||||||
|
name: '',
|
||||||
|
version: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export function getServerVersion() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const bridge = useMessageBridge();
|
||||||
|
bridge.addCommandListener('server/version', data => {
|
||||||
|
if (data.code === 200) {
|
||||||
|
resolve(data.msg);
|
||||||
|
} else {
|
||||||
|
reject(data.msg);
|
||||||
|
}
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
bridge.postMessage({
|
||||||
|
command: 'server/version',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="height: 100%;">
|
<div style="height: 100%;">
|
||||||
<Welcome v-show="!tabs.activeTab.component"></Welcome>
|
<Welcome v-show="!haveActiveTab"></Welcome>
|
||||||
|
|
||||||
<!-- 如果存在激活标签页,则根据标签页进行渲染 -->
|
<!-- 如果存在激活标签页,则根据标签页进行渲染 -->
|
||||||
<div v-show="tabs.activeTab.component" style="height: 100%;">
|
<div v-show="haveActiveTab" style="height: 100%;">
|
||||||
|
<!-- vscode/trae 中,下面存在初始化问题 -->
|
||||||
<component
|
<component
|
||||||
v-show="tab === tabs.activeTab"
|
v-show="tab === tabs.content[tabs.activeIndex]"
|
||||||
v-for="(tab, index) of tabs.content"
|
v-for="(tab, index) of tabs.content"
|
||||||
:key="index"
|
:key="index"
|
||||||
:is="tab.component"
|
:is="tab.component"
|
||||||
@ -20,8 +21,18 @@ import { defineComponent, computed } from 'vue';
|
|||||||
|
|
||||||
import Welcome from './welcome.vue';
|
import Welcome from './welcome.vue';
|
||||||
import { tabs } from '@/components/main-panel/panel';
|
import { tabs } from '@/components/main-panel/panel';
|
||||||
|
import { panelLoaded } from '@/hook/panel';
|
||||||
|
|
||||||
defineComponent({ name: 'debug' });
|
defineComponent({ name: 'debug' });
|
||||||
|
|
||||||
|
const haveActiveTab = computed(() => {
|
||||||
|
const activeTab = tabs.activeTab;
|
||||||
|
if (activeTab && activeTab.component) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
4
service/package-lock.json
generated
4
service/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "openmcp-test-backend",
|
"name": "openmcp-test-backend",
|
||||||
"version": "1.0.0",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "openmcp-test-backend",
|
"name": "openmcp-test-backend",
|
||||||
"version": "1.0.0",
|
"version": "0.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.8.0",
|
"@modelcontextprotocol/sdk": "^1.8.0",
|
||||||
|
@ -69,12 +69,17 @@ export class MCPClient {
|
|||||||
|
|
||||||
// 建立连接
|
// 建立连接
|
||||||
await this.client.connect(this.transport);
|
await this.client.connect(this.transport);
|
||||||
console.log(`Connected to MCP server via ${this.options.connectionType}`);
|
console.log(`Connected to MCP server via ${this.options.connectionType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getServerVersion() {
|
||||||
|
return this.client.getServerVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 断开连接
|
// 断开连接
|
||||||
public async disconnect(): Promise<void> {
|
public async disconnect(): Promise<void> {
|
||||||
await this.client.close();
|
await this.client.close();
|
||||||
|
|
||||||
console.log('Disconnected from MCP server');
|
console.log('Disconnected from MCP server');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,3 +253,32 @@ export async function callTool(
|
|||||||
webview.postMessage({ command: 'tools/call', data: result });
|
webview.postMessage({ command: 'tools/call', data: result });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getServerVersion(
|
||||||
|
client: MCPClient | undefined,
|
||||||
|
webview: PostMessageble
|
||||||
|
) {
|
||||||
|
if (!client) {
|
||||||
|
const connectResult = {
|
||||||
|
code: 501,
|
||||||
|
msg:'mcp client 尚未连接'
|
||||||
|
};
|
||||||
|
webview.postMessage({ command: 'server/version', data: connectResult });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const version = client.getServerVersion();
|
||||||
|
const result = {
|
||||||
|
code: 200,
|
||||||
|
msg: version
|
||||||
|
};
|
||||||
|
webview.postMessage({ command:'server/version', data: result });
|
||||||
|
} catch (error) {
|
||||||
|
const result = {
|
||||||
|
code: 500,
|
||||||
|
msg: (error as any).toString()
|
||||||
|
};
|
||||||
|
webview.postMessage({ command:'server/version', data: result });
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { PostMessageble } from '../adapter';
|
import { PostMessageble } from '../adapter';
|
||||||
import { connect, MCPClient, type MCPOptions } from './connect';
|
import { connect, MCPClient, type MCPOptions } from './connect';
|
||||||
import { callTool, getPrompt, listPrompts, listResources, listResourceTemplates, listTools, readResource } from './handler';
|
import { callTool, getPrompt, getServerVersion, listPrompts, listResources, listResourceTemplates, listTools, readResource } from './handler';
|
||||||
import { chatCompletionHandler } from './llm';
|
import { chatCompletionHandler } from './llm';
|
||||||
import { panelLoadHandler, panelSaveHandler } from './panel';
|
import { panelLoadHandler, panelSaveHandler } from './panel';
|
||||||
import { settingLoadHandler, settingSaveHandler } from './setting';
|
import { settingLoadHandler, settingSaveHandler } from './setting';
|
||||||
@ -13,6 +13,8 @@ let client: MCPClient | undefined = undefined;
|
|||||||
|
|
||||||
async function connectHandler(option: MCPOptions, webview: PostMessageble) {
|
async function connectHandler(option: MCPOptions, webview: PostMessageble) {
|
||||||
try {
|
try {
|
||||||
|
console.log('ready to connect', option);
|
||||||
|
|
||||||
client = await connect(option);
|
client = await connect(option);
|
||||||
const connectResult = {
|
const connectResult = {
|
||||||
code: 200,
|
code: 200,
|
||||||
@ -39,6 +41,10 @@ export function messageController(command: string, data: any, webview: PostMessa
|
|||||||
case 'connect':
|
case 'connect':
|
||||||
connectHandler(data, webview);
|
connectHandler(data, webview);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'server/version':
|
||||||
|
getServerVersion(client, webview);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'prompts/list':
|
case 'prompts/list':
|
||||||
listPrompts(client, webview);
|
listPrompts(client, webview);
|
||||||
|
@ -2,49 +2,21 @@
|
|||||||
"currentIndex": 2,
|
"currentIndex": 2,
|
||||||
"tabs": [
|
"tabs": [
|
||||||
{
|
{
|
||||||
"name": "交互测试",
|
"name": "工具",
|
||||||
"icon": "icon-robot",
|
"icon": "icon-tool",
|
||||||
"type": "blank",
|
"type": "blank",
|
||||||
"componentIndex": 3,
|
"componentIndex": 2,
|
||||||
"storage": {
|
"storage": {
|
||||||
"messages": [
|
"currentToolName": "add"
|
||||||
{
|
}
|
||||||
"role": "user",
|
},
|
||||||
"content": "hello"
|
{
|
||||||
},
|
"name": "资源",
|
||||||
{
|
"icon": "icon-file",
|
||||||
"role": "assistant",
|
"type": "blank",
|
||||||
"content": "Hello! How can I assist you today?"
|
"componentIndex": 0,
|
||||||
},
|
"storage": {
|
||||||
{
|
"currentResourceName": "greeting"
|
||||||
"role": "user",
|
|
||||||
"content": "请问什么是聚类算法"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "聚类算法(Clustering Algorithm)是一种**无监督学习**(Unsupervised Learning)方法,用于将数据集中的样本划分为若干个组(称为“簇”或“类”),使得同一组内的样本彼此相似,而不同组的样本差异较大。聚类算法的目标是通过数据的内在结构,发现数据中的潜在模式或分组。\n\n### 聚类算法的核心思想\n1. **相似性度量**:通过距离(如欧氏距离、曼哈顿距离)或相似性(如余弦相似度)来衡量样本之间的相似程度。\n2. **簇内紧凑性**:同一簇内的样本应尽可能相似。\n3. **簇间分离性**:不同簇的样本应尽可能不相似。\n\n---\n\n### 常见的聚类算法\n1. **K-Means** \n - 将数据划分为K个簇,每个簇的中心由簇内样本的平均值表示。\n - 适用于数值型数据,计算高效,但对初始中心点敏感,且需要预先指定K值。\n\n2. **层次聚类(Hierarchical Clustering)** \n - 通过自底向上(凝聚法)或自顶向下(分裂法)的方式构建树状图(Dendrogram)。\n - 不需要预先指定簇的数量,但计算复杂度较高。\n\n3. **DBSCAN(Density-Based Spatial Clustering of Applications with Noise)** \n - 基于密度的聚类,能够发现任意形状的簇,并能识别噪声点。\n - 不需要预先指定簇的数量,但对参数(如邻域半径和最小样本数)敏感。\n\n4. **高斯混合模型(GMM, Gaussian Mixture Model)** \n - 假设数据由多个高斯分布混合生成,通过概率模型进行聚类。\n - 适用于数据分布复杂的情况,但计算复杂度较高。\n\n5. **谱聚类(Spectral Clustering)** \n - 基于图论的聚类方法,利用数据的相似性矩阵进行降维和聚类。\n - 适用于非凸形状的簇,但对相似性矩阵的计算要求较高。\n\n---\n\n### 聚类算法的应用场景\n1. **客户分群**:根据消费行为将用户划分为不同群体,便于精准营销。\n2. **图像分割**:将图像中的像素聚类为不同的区域。\n3. **异常检测**:通过聚类识别离群点(如金融欺诈检测)。\n4. **文本挖掘**:对文档或词汇进行聚类,发现主题或类别。\n5. **生物信息学**:基因表达数据的聚类分析。\n\n---\n\n### 聚类算法的评估指标\n1. **轮廓系数(Silhouette Coefficient)**:衡量样本与同簇和其他簇的相似性,值越接近1表示聚类效果越好。\n2. **Calinski-Harabasz指数**:基于簇内离散度和簇间离散度的比值,值越大表示聚类效果越好。\n3. **Davies-Bouldin指数**:衡量簇内距离与簇间距离的比值,值越小表示聚类效果越好。\n\n---\n\n如果你有具体的数据或场景需要聚类分析,可以告诉我,我可以帮助你选择合适的算法或工具!"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "请帮我计算 add 1 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "错误: 工具调用失败: Unexpected token '}', \"}\" is not valid JSON"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "看起来在调用工具时出现了问题。让我手动帮你计算 `1 + 2` 的结果:\n\n\\[\n1 + 2 = 3\n\\]\n\n结果是 **3**!如果你有其他计算需求,也可以告诉我哦!"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"modelIndex": 0,
|
|
||||||
"enableTools": [],
|
|
||||||
"enableWebSearch": false,
|
|
||||||
"temperature": 0.7,
|
|
||||||
"contextLength": 10,
|
|
||||||
"systemPrompt": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -53,101 +25,31 @@
|
|||||||
"type": "blank",
|
"type": "blank",
|
||||||
"componentIndex": 3,
|
"componentIndex": 3,
|
||||||
"storage": {
|
"storage": {
|
||||||
"messages": [
|
"messages": [],
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "计算 add 1 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "",
|
|
||||||
"tool_calls": [
|
|
||||||
{
|
|
||||||
"id": "call_0_12c5b219-bb79-46db-b1ea-876d708415f5",
|
|
||||||
"index": 0,
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "add",
|
|
||||||
"arguments": "{\"a\":1,\"b\":2}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "tool",
|
|
||||||
"tool_call_id": "call_0_12c5b219-bb79-46db-b1ea-876d708415f5",
|
|
||||||
"content": "[{\"type\":\"text\",\"text\":\"3\"}]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "1 + 2 = 3"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {
|
"settings": {
|
||||||
"modelIndex": 0,
|
"modelIndex": 0,
|
||||||
"enableTools": [],
|
"enableTools": [
|
||||||
"enableWebSearch": false,
|
{
|
||||||
"temperature": 0.7,
|
"name": "add",
|
||||||
"contextLength": 10,
|
"description": "对两个数字进行实数域的加法",
|
||||||
"systemPrompt": ""
|
"enabled": true
|
||||||
}
|
},
|
||||||
}
|
{
|
||||||
},
|
"name": "multiply",
|
||||||
{
|
"description": "对两个数字进行实数域的乘法运算",
|
||||||
"name": "交互测试",
|
"enabled": true
|
||||||
"icon": "icon-robot",
|
},
|
||||||
"type": "blank",
|
{
|
||||||
"componentIndex": 3,
|
"name": "is_even",
|
||||||
"storage": {
|
"description": "判断一个整数是否为偶数",
|
||||||
"messages": [
|
"enabled": true
|
||||||
{
|
},
|
||||||
"role": "user",
|
{
|
||||||
"content": "什么是斐波那契数列?"
|
"name": "capitalize",
|
||||||
},
|
"description": "将字符串首字母大写",
|
||||||
{
|
"enabled": true
|
||||||
"role": "assistant",
|
}
|
||||||
"content": "斐波那契数列(Fibonacci sequence)是以意大利数学家**列昂纳多·斐波那契**(Leonardo Fibonacci)命名的一个经典数列。其定义如下:\n\n### **定义**\n- **前两项**: \n \\( F_0 = 0 \\), \\( F_1 = 1 \\)(部分定义从 \\( F_1 = 1 \\), \\( F_2 = 1 \\) 开始)。\n- **递推关系**: \n 从第三项开始,每一项等于前两项之和: \n \\( F_n = F_{n-1} + F_{n-2} \\) (\\( n \\geq 2 \\))。\n\n### **数列示例**\n前几项为: \n0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...\n\n### **关键特性**\n1. **黄金分割**: \n 当 \\( n \\) 趋近于无穷大时,相邻两项的比值 \\( \\frac{F_{n+1}}{F_n} \\) 趋近于**黄金比例** \\( \\phi \\approx 1.618 \\)。\n\n2. **通项公式(比奈公式)**: \n \\[\n F_n = \\frac{\\phi^n - (-\\phi)^{-n}}{\\sqrt{5}}, \\quad \\phi = \\frac{1+\\sqrt{5}}{2}\n \\]\n 该公式通过无理数精确计算整数项。\n\n3. **应用领域**: \n - 自然界:如花瓣排列、松果螺旋、鹦鹉螺壳的生长模式。 \n - 计算机科学:动态规划、递归算法(需注意重复计算的优化)。 \n - 金融:斐波那契回调线用于技术分析。\n\n### **扩展知识**\n- **负数项**:递推关系可反向延伸,如 \\( F_{-n} = (-1)^{n+1}F_n \\)。\n- **变体**:卢卡斯数列(Lucas sequence)以 \\( L_0=2 \\), \\( L_1=1 \\) 开始,同样满足递推关系。\n\n斐波那契数列因其简洁的递推定义与广泛的自然关联性,成为数学和科学中的经典研究对象。"
|
],
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "add 1 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "",
|
|
||||||
"tool_calls": [
|
|
||||||
{
|
|
||||||
"id": "call_0_4eeb1c2f-8345-4b75-b002-af252af0728f",
|
|
||||||
"index": 0,
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "add",
|
|
||||||
"arguments": "{\"a\":1,\"b\":2}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "tool",
|
|
||||||
"tool_call_id": "call_0_4eeb1c2f-8345-4b75-b002-af252af0728f",
|
|
||||||
"content": "[{\"type\":\"text\",\"text\":\"3\"}]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "1 + 2 = 3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": "nihao"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "assistant",
|
|
||||||
"content": "你好!有什么可以帮您的吗?😊"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"settings": {
|
|
||||||
"modelIndex": 0,
|
|
||||||
"enableTools": [],
|
|
||||||
"enableWebSearch": false,
|
"enableWebSearch": false,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
"contextLength": 10,
|
"contextLength": 10,
|
||||||
|
@ -43,6 +43,11 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const cwd = getLaunchCWD(context, uri);
|
const cwd = getLaunchCWD(context, uri);
|
||||||
|
// 获取 uri 相对于 cwd 的路径
|
||||||
|
const relativePath = fspath.relative(cwd, uri.fsPath);
|
||||||
|
|
||||||
|
console.log('current file' + uri.fsPath);
|
||||||
|
console.log(`relativePath: ${relativePath}`);
|
||||||
|
|
||||||
// 设置HTML内容
|
// 设置HTML内容
|
||||||
const html = getWebviewContent(context, panel);
|
const html = getWebviewContent(context, panel);
|
||||||
@ -55,15 +60,28 @@ export function activate(context: vscode.ExtensionContext) {
|
|||||||
|
|
||||||
// 拦截消息,注入额外信息
|
// 拦截消息,注入额外信息
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'connect':
|
case 'vscode/launch-command':
|
||||||
data.cwd = cwd;
|
const commandString = 'uv run mcp run ' + relativePath;
|
||||||
|
const launchResult = {
|
||||||
|
code: 200,
|
||||||
|
msg: {
|
||||||
|
commandString: commandString,
|
||||||
|
cwd: cwd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.webview.postMessage({
|
||||||
|
command: 'vscode/launch-command',
|
||||||
|
data: launchResult
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
OpenMCPService.messageController(command, data, panel.webview);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenMCPService.messageController(command, data, panel.webview as any);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
panel.onDidDispose(() => {
|
panel.onDidDispose(() => {
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
# Welcome to your VS Code Extension
|
|
||||||
|
|
||||||
## What's in the folder
|
|
||||||
|
|
||||||
* This folder contains all of the files necessary for your extension.
|
|
||||||
* `package.json` - this is the manifest file in which you declare your extension and command.
|
|
||||||
* The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin.
|
|
||||||
* `src/extension.ts` - this is the main file where you will provide the implementation of your command.
|
|
||||||
* The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`.
|
|
||||||
* We pass the function containing the implementation of the command as the second parameter to `registerCommand`.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
* install the recommended extensions (amodio.tsl-problem-matcher, ms-vscode.extension-test-runner, and dbaeumer.vscode-eslint)
|
|
||||||
|
|
||||||
|
|
||||||
## Get up and running straight away
|
|
||||||
|
|
||||||
* Press `F5` to open a new window with your extension loaded.
|
|
||||||
* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`.
|
|
||||||
* Set breakpoints in your code inside `src/extension.ts` to debug your extension.
|
|
||||||
* Find output from your extension in the debug console.
|
|
||||||
|
|
||||||
## Make changes
|
|
||||||
|
|
||||||
* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`.
|
|
||||||
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
|
||||||
|
|
||||||
|
|
||||||
## Explore the API
|
|
||||||
|
|
||||||
* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`.
|
|
||||||
|
|
||||||
## Run tests
|
|
||||||
|
|
||||||
* Install the [Extension Test Runner](https://marketplace.visualstudio.com/items?itemName=ms-vscode.extension-test-runner)
|
|
||||||
* Run the "watch" task via the **Tasks: Run Task** command. Make sure this is running, or tests might not be discovered.
|
|
||||||
* Open the Testing view from the activity bar and click the Run Test" button, or use the hotkey `Ctrl/Cmd + ; A`
|
|
||||||
* See the output of the test result in the Test Results view.
|
|
||||||
* Make changes to `src/test/extension.test.ts` or create new test files inside the `test` folder.
|
|
||||||
* The provided test runner will only consider files matching the name pattern `**.test.ts`.
|
|
||||||
* You can create folders inside the `test` folder to structure your tests any way you want.
|
|
||||||
|
|
||||||
## Go further
|
|
||||||
|
|
||||||
* Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
|
|
||||||
* [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VS Code extension marketplace.
|
|
||||||
* Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).
|
|
Loading…
x
Reference in New Issue
Block a user