protocol-proxy 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/index.html CHANGED
@@ -51,6 +51,16 @@
51
51
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>
52
52
  <span>系统日志</span>
53
53
  </a>
54
+ <a href="#" class="nav-item" data-page="skills">
55
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path></svg>
56
+ <span>技能管理</span>
57
+ <span class="nav-badge" id="nav-skill-count">0</span>
58
+ </a>
59
+ <a href="#" class="nav-item" data-page="mcp-servers">
60
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"></path><path d="M12 18a6 6 0 1 0 0-12 6 6 0 0 0 0 12z"></path><path d="M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></path></svg>
61
+ <span>MCP 服务</span>
62
+ <span class="nav-badge" id="nav-mcp-count">0</span>
63
+ </a>
54
64
  <a href="#" class="nav-item" data-page="settings">
55
65
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 5 15.34a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.6a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 20.39 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
56
66
  <span>设置</span>
@@ -61,7 +71,7 @@
61
71
  <span id="theme-icon">&#9790;</span>
62
72
  <span id="theme-label">深色</span>
63
73
  </button>
64
- <div class="version" id="app-version">v2.8.1</div>
74
+ <div class="version" id="app-version"></div>
65
75
  </div>
66
76
  </aside>
67
77
 
@@ -378,14 +388,36 @@
378
388
  </div>
379
389
  <button class="btn btn-sm context-compress-btn" id="context-compress-btn" onclick="compressAssistantContext()" style="display:none">压缩</button>
380
390
  </div>
381
- <div class="assistant-input-area">
382
- <textarea id="assistant-input" placeholder="输入问题,例如:帮我看看哪个供应商最慢,最近有什么异常?" rows="1"></textarea>
391
+ <div class="skill-panel" id="skill-panel" style="display:none">
392
+ <div class="skill-panel-header"><span>可用技能</span><button class="btn btn-sm" onclick="toggleSkillPanel()">收起</button></div>
393
+ <div class="skill-panel-list" id="skill-panel-list"></div>
394
+ </div>
395
+ <div class="assistant-input-area" style="position:relative">
396
+ <div class="skill-autocomplete" id="skill-autocomplete"></div>
397
+ <textarea id="assistant-input" placeholder="输入问题,例如:帮我看看哪个供应商最慢,最近有什么异常? 输入 / 触发技能" rows="1"></textarea>
398
+ <button class="btn" onclick="toggleSkillPanel()" title="查看可用技能" style="padding:0 10px;font-size:16px">⚡</button>
383
399
  <button class="btn btn-primary" id="assistant-send-btn" onclick="sendAssistantMessage()" disabled>发送</button>
384
400
  </div>
385
401
  </div>
386
402
  </div>
387
403
 
388
404
  <!-- ==================== Settings Page ==================== -->
405
+ <div class="page" id="page-skills">
406
+ <div class="page-header" style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
407
+ <h2 style="margin:0">技能管理</h2>
408
+ <button class="btn btn-primary" onclick="showSkillModal()">上传技能</button>
409
+ </div>
410
+ <div id="skills-container"></div>
411
+ </div>
412
+
413
+ <div class="page" id="page-mcp-servers">
414
+ <div class="page-header" style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
415
+ <h2 style="margin:0">MCP 服务管理</h2>
416
+ <button class="btn btn-primary" onclick="showMcpModal()">添加 MCP 服务</button>
417
+ </div>
418
+ <div id="mcp-servers-container"></div>
419
+ </div>
420
+
389
421
  <div class="page" id="page-settings">
390
422
  <div class="settings-grid">
391
423
  <div class="panel">
@@ -698,9 +730,158 @@
698
730
  </div>
699
731
  </div>
700
732
 
733
+ <!-- Skill Modal -->
734
+ <div class="modal-overlay" id="skill-modal">
735
+ <div class="modal" style="max-width:600px">
736
+ <div class="modal-header">
737
+ <h3 id="skill-modal-title">新建技能</h3>
738
+ <button class="modal-close" onclick="closeSkillModal()">&times;</button>
739
+ </div>
740
+ <div class="modal-body">
741
+ <!-- 上传新技能 -->
742
+ <div id="skill-upload-section">
743
+ <div class="form-group">
744
+ <label>选择技能文件夹 <span style="color:var(--text-muted)">(包含 SKILL.md)</span></label>
745
+ <input type="file" id="skill-file-input" webkitdirectory>
746
+ <div id="skill-file-preview" style="margin-top:12px"></div>
747
+ </div>
748
+ </div>
749
+ <!-- 编辑已有技能 -->
750
+ <div id="skill-edit-section" style="display:none">
751
+ <div class="form-group">
752
+ <label>名称 <span style="color:var(--text-muted)">(英文、数字、连字符)</span></label>
753
+ <input type="text" id="skill-name" placeholder="my-skill" pattern="[a-zA-Z0-9_-]+">
754
+ </div>
755
+ <div class="form-group">
756
+ <label>描述</label>
757
+ <input type="text" id="skill-description" placeholder="简短描述这个技能的用途">
758
+ </div>
759
+ <div class="form-group">
760
+ <label>指令内容 <span style="color:var(--text-muted)">(Markdown)</span></label>
761
+ <textarea id="skill-content" rows="10" placeholder="# 技能标题&#10;&#10;在此编写技能指令..."></textarea>
762
+ </div>
763
+ <div class="form-group" id="skill-files-section">
764
+ <label>附属文件</label>
765
+ <div class="skill-file-upload-row">
766
+ <select id="skill-upload-dir"><option value="scripts">scripts/</option><option value="reference">reference/</option></select>
767
+ <input type="file" id="skill-upload-input" multiple>
768
+ <button class="btn btn-sm" onclick="uploadSkillFiles()">上传</button>
769
+ </div>
770
+ <div id="skill-existing-files" style="margin-top:8px;font-size:12px"></div>
771
+ </div>
772
+ </div>
773
+ </div>
774
+ <div class="modal-footer">
775
+ <button class="btn" onclick="closeSkillModal()">取消</button>
776
+ <button class="btn btn-primary" id="skill-save-btn" onclick="saveSkill()">保存</button>
777
+ </div>
778
+ </div>
779
+ </div>
780
+
781
+ <!-- Skill View Modal -->
782
+ <div class="modal-overlay" id="skill-view-modal">
783
+ <div class="modal" style="max-width:700px;max-height:80vh;display:flex;flex-direction:column">
784
+ <div class="modal-header">
785
+ <h3 id="skill-view-title">查看技能</h3>
786
+ <button class="modal-close" onclick="closeSkillViewModal()">&times;</button>
787
+ </div>
788
+ <div class="modal-body" style="overflow-y:auto;flex:1">
789
+ <div style="margin-bottom:12px">
790
+ <span class="skill-badge" id="skill-view-badge" style="font-size:12px;padding:2px 8px;border-radius:4px"></span>
791
+ <span style="color:var(--text-muted);font-size:13px;margin-left:8px" id="skill-view-desc"></span>
792
+ </div>
793
+ <div id="skill-view-files" style="margin-bottom:12px"></div>
794
+ <div class="skill-view-content" id="skill-view-content"></div>
795
+ </div>
796
+ <div class="modal-footer">
797
+ <button class="btn" onclick="closeSkillViewModal()">关闭</button>
798
+ </div>
799
+ </div>
800
+ </div>
801
+
802
+ <!-- MCP Server Modal -->
803
+ <div class="modal-overlay" id="mcp-modal">
804
+ <div class="modal" style="max-width:550px">
805
+ <div class="modal-header">
806
+ <h3 id="mcp-modal-title">添加 MCP 服务</h3>
807
+ <button class="modal-close" onclick="closeMcpModal()">&times;</button>
808
+ </div>
809
+ <div class="modal-body">
810
+ <div class="form-group">
811
+ <label>服务名称 <span style="color:var(--text-muted)">(英文、数字、连字符)</span></label>
812
+ <input type="text" id="mcp-name" placeholder="my-mcp-server" pattern="[a-zA-Z0-9_-]+">
813
+ </div>
814
+ <div class="form-group">
815
+ <label>传输方式</label>
816
+ <div style="display:flex;gap:16px;margin-top:4px">
817
+ <label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:13px">
818
+ <input type="radio" name="mcp-transport" value="stdio" checked onchange="toggleMcpTransport()"> 本地进程 (stdio)
819
+ </label>
820
+ <label style="display:flex;align-items:center;gap:6px;cursor:pointer;font-size:13px">
821
+ <input type="radio" name="mcp-transport" value="http" onchange="toggleMcpTransport()"> 远程 HTTP
822
+ </label>
823
+ </div>
824
+ </div>
825
+ <div id="mcp-stdio-fields">
826
+ <div class="form-group">
827
+ <label>命令</label>
828
+ <input type="text" id="mcp-command" placeholder="npx">
829
+ </div>
830
+ <div class="form-group">
831
+ <label>参数 <span style="color:var(--text-muted)">(空格分隔)</span></label>
832
+ <input type="text" id="mcp-args" placeholder="-y @modelcontextprotocol/server-filesystem /tmp">
833
+ </div>
834
+ <div class="form-group">
835
+ <label>环境变量 <span style="color:var(--text-muted)">(可选)</span></label>
836
+ <div id="mcp-env-editor"></div>
837
+ <button class="btn btn-sm" style="margin-top:6px" onclick="addMcpEnvRow()">+ 添加</button>
838
+ </div>
839
+ </div>
840
+ <div id="mcp-http-fields" style="display:none">
841
+ <div class="form-group">
842
+ <label>URL</label>
843
+ <input type="text" id="mcp-url" placeholder="https://example.com/mcp">
844
+ </div>
845
+ <div class="form-group">
846
+ <label>请求头 <span style="color:var(--text-muted)">(可选)</span></label>
847
+ <div id="mcp-headers-editor"></div>
848
+ <button class="btn btn-sm" style="margin-top:6px" onclick="addMcpHeaderRow()">+ 添加</button>
849
+ </div>
850
+ </div>
851
+ <div class="form-group">
852
+ <label style="display:flex;align-items:center;gap:8px;cursor:pointer">
853
+ <input type="checkbox" id="mcp-enabled" checked> 启用
854
+ </label>
855
+ </div>
856
+ </div>
857
+ <div class="modal-footer">
858
+ <button class="btn" onclick="closeMcpModal()">取消</button>
859
+ <button class="btn btn-primary" onclick="saveMcpServer()">保存</button>
860
+ </div>
861
+ </div>
862
+ </div>
863
+
864
+ <!-- MCP Tools Modal -->
865
+ <div class="modal-overlay" id="mcp-tools-modal">
866
+ <div class="modal" style="max-width:600px;max-height:70vh;display:flex;flex-direction:column">
867
+ <div class="modal-header">
868
+ <h3 id="mcp-tools-title">MCP 工具列表</h3>
869
+ <button class="modal-close" onclick="closeMcpToolsModal()">&times;</button>
870
+ </div>
871
+ <div class="modal-body" style="overflow-y:auto;flex:1">
872
+ <div id="mcp-tools-list"></div>
873
+ </div>
874
+ <div class="modal-footer">
875
+ <button class="btn" onclick="closeMcpToolsModal()">关闭</button>
876
+ </div>
877
+ </div>
878
+ </div>
879
+
701
880
  <!-- Toast -->
702
881
  <div class="toast" id="toast" style="display:none"></div>
703
882
 
883
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
884
+ <script src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"></script>
704
885
  <script src="app.js"></script>
705
886
  </body>
706
887
  </html>
package/public/style.css CHANGED
@@ -1781,8 +1781,8 @@ body {
1781
1781
 
1782
1782
  /* ---------- Selection ---------- */
1783
1783
  ::selection {
1784
- background: var(--accent-subtle);
1785
- color: var(--accent);
1784
+ background: var(--accent);
1785
+ color: var(--text-inverse);
1786
1786
  }
1787
1787
 
1788
1788
  /* ---------- Assistant Page ---------- */
@@ -2129,6 +2129,9 @@ body {
2129
2129
  align-items: flex-end;
2130
2130
  flex-shrink: 0;
2131
2131
  }
2132
+ .assistant-input-area .btn {
2133
+ height: 44px;
2134
+ }
2132
2135
 
2133
2136
  .assistant-input-area textarea {
2134
2137
  flex: 1;
@@ -2298,3 +2301,268 @@ body {
2298
2301
  word-break: break-all;
2299
2302
  color: var(--text-secondary);
2300
2303
  }
2304
+
2305
+ /* ========== 技能管理 ========== */
2306
+ .skill-group {
2307
+ margin-bottom: 24px;
2308
+ }
2309
+ .skills-grid {
2310
+ display: grid;
2311
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
2312
+ gap: 12px;
2313
+ }
2314
+ .skill-card {
2315
+ background: var(--bg-elevated);
2316
+ border: 1px solid var(--border-default);
2317
+ border-radius: var(--radius-md);
2318
+ padding: 14px;
2319
+ display: flex;
2320
+ flex-direction: column;
2321
+ gap: 8px;
2322
+ }
2323
+ .skill-card-header {
2324
+ font-size: 14px;
2325
+ color: var(--text-primary);
2326
+ }
2327
+ .skill-card-desc {
2328
+ font-size: 12px;
2329
+ color: var(--text-muted);
2330
+ line-height: 1.4;
2331
+ flex: 1;
2332
+ }
2333
+ .skill-card-actions {
2334
+ display: flex;
2335
+ gap: 6px;
2336
+ margin-top: 4px;
2337
+ }
2338
+ .skill-panel {
2339
+ border: 1px solid var(--border-default);
2340
+ border-radius: var(--radius-md);
2341
+ background: var(--bg-elevated);
2342
+ margin-bottom: 8px;
2343
+ max-height: 200px;
2344
+ overflow-y: auto;
2345
+ }
2346
+ .skill-panel-header {
2347
+ display: flex;
2348
+ align-items: center;
2349
+ justify-content: space-between;
2350
+ padding: 8px 12px;
2351
+ font-size: 12px;
2352
+ font-weight: 600;
2353
+ color: var(--text-secondary);
2354
+ border-bottom: 1px solid var(--border-subtle);
2355
+ position: sticky;
2356
+ top: 0;
2357
+ background: var(--bg-elevated);
2358
+ }
2359
+ .skill-panel-list {
2360
+ padding: 4px;
2361
+ }
2362
+ .skill-panel-item {
2363
+ display: flex;
2364
+ align-items: center;
2365
+ gap: 8px;
2366
+ padding: 6px 8px;
2367
+ cursor: pointer;
2368
+ border-radius: var(--radius-md);
2369
+ font-size: 13px;
2370
+ }
2371
+ .skill-panel-item:hover {
2372
+ background: var(--bg-hover);
2373
+ }
2374
+ .skill-panel-badge {
2375
+ font-size: 10px;
2376
+ color: #fff;
2377
+ padding: 1px 5px;
2378
+ border-radius: 3px;
2379
+ flex-shrink: 0;
2380
+ }
2381
+ .skill-panel-item strong {
2382
+ color: var(--accent);
2383
+ white-space: nowrap;
2384
+ }
2385
+ .skill-panel-desc {
2386
+ color: var(--text-muted);
2387
+ font-size: 12px;
2388
+ overflow: hidden;
2389
+ text-overflow: ellipsis;
2390
+ white-space: nowrap;
2391
+ flex: 1;
2392
+ }
2393
+ .skill-autocomplete {
2394
+ display: none;
2395
+ position: absolute;
2396
+ bottom: 100%;
2397
+ left: 0;
2398
+ right: 0;
2399
+ max-height: 200px;
2400
+ overflow-y: auto;
2401
+ background: var(--bg-elevated);
2402
+ border: 1px solid var(--border-default);
2403
+ border-radius: var(--radius-md);
2404
+ box-shadow: 0 -4px 12px rgba(0,0,0,0.15);
2405
+ margin-bottom: 4px;
2406
+ z-index: 10;
2407
+ }
2408
+ .skill-ac-item {
2409
+ padding: 8px 12px;
2410
+ cursor: pointer;
2411
+ display: flex;
2412
+ gap: 8px;
2413
+ align-items: baseline;
2414
+ font-size: 13px;
2415
+ }
2416
+ .skill-ac-item:hover {
2417
+ background: var(--bg-hover);
2418
+ }
2419
+ .skill-ac-item strong {
2420
+ color: var(--accent);
2421
+ white-space: nowrap;
2422
+ }
2423
+ .skill-ac-desc {
2424
+ color: var(--text-muted);
2425
+ overflow: hidden;
2426
+ text-overflow: ellipsis;
2427
+ white-space: nowrap;
2428
+ font-size: 12px;
2429
+ }
2430
+ .skill-file-upload-row {
2431
+ display: flex;
2432
+ align-items: center;
2433
+ gap: 8px;
2434
+ }
2435
+ .skill-file-upload-row select {
2436
+ height: 30px;
2437
+ padding: 0 8px;
2438
+ background: var(--bg-elevated);
2439
+ border: 1px solid var(--border-default);
2440
+ border-radius: var(--radius-md);
2441
+ color: var(--text-primary);
2442
+ font-size: 12px;
2443
+ }
2444
+ .skill-file-upload-row input[type="file"] {
2445
+ font-size: 12px;
2446
+ flex: 1;
2447
+ }
2448
+ .skill-tree-dir {
2449
+ display: flex;
2450
+ align-items: center;
2451
+ gap: 4px;
2452
+ padding: 2px 0;
2453
+ cursor: pointer;
2454
+ user-select: none;
2455
+ }
2456
+ .skill-tree-dir:hover { color: var(--accent); }
2457
+ .skill-tree-arrow {
2458
+ font-size: 10px;
2459
+ transition: transform 0.15s;
2460
+ display: inline-block;
2461
+ width: 12px;
2462
+ text-align: center;
2463
+ }
2464
+ .skill-tree-file {
2465
+ display: flex;
2466
+ align-items: center;
2467
+ gap: 6px;
2468
+ padding: 1px 0;
2469
+ }
2470
+ .skill-view-content {
2471
+ font-size: 13px;
2472
+ line-height: 1.7;
2473
+ color: var(--text-primary);
2474
+ }
2475
+ .skill-view-content h1 { font-size: 20px; margin: 20px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border-subtle); }
2476
+ .skill-view-content h2 { font-size: 17px; margin: 18px 0 8px; }
2477
+ .skill-view-content h3 { font-size: 15px; margin: 14px 0 6px; }
2478
+ .skill-view-content p { margin: 8px 0; }
2479
+ .skill-view-content ul, .skill-view-content ol { margin: 8px 0; padding-left: 24px; }
2480
+ .skill-view-content li { margin: 4px 0; }
2481
+ .skill-view-content pre {
2482
+ background: var(--bg-base);
2483
+ padding: 12px;
2484
+ border-radius: var(--radius-md);
2485
+ overflow-x: auto;
2486
+ font-size: 12px;
2487
+ border: 1px solid var(--border-subtle);
2488
+ margin: 10px 0;
2489
+ }
2490
+ .skill-view-content code {
2491
+ background: var(--bg-base);
2492
+ padding: 1px 5px;
2493
+ border-radius: 3px;
2494
+ font-size: 12px;
2495
+ font-family: var(--font-mono, monospace);
2496
+ }
2497
+ .skill-view-content pre code {
2498
+ background: none;
2499
+ padding: 0;
2500
+ border: none;
2501
+ }
2502
+ .skill-view-content table {
2503
+ width: 100%;
2504
+ border-collapse: collapse;
2505
+ margin: 10px 0;
2506
+ font-size: 12px;
2507
+ }
2508
+ .skill-view-content th, .skill-view-content td {
2509
+ border: 1px solid var(--border-subtle);
2510
+ padding: 6px 10px;
2511
+ text-align: left;
2512
+ }
2513
+ .skill-view-content th {
2514
+ background: var(--bg-base);
2515
+ font-weight: 600;
2516
+ }
2517
+ .skill-view-content blockquote {
2518
+ border-left: 3px solid var(--accent);
2519
+ margin: 10px 0;
2520
+ padding: 6px 12px;
2521
+ color: var(--text-secondary);
2522
+ background: var(--bg-base);
2523
+ }
2524
+ .skill-view-content hr {
2525
+ border: none;
2526
+ border-top: 1px solid var(--border-subtle);
2527
+ margin: 16px 0;
2528
+ }
2529
+ .skill-view-content a {
2530
+ color: var(--accent);
2531
+ text-decoration: none;
2532
+ }
2533
+ .skill-view-content a:hover {
2534
+ text-decoration: underline;
2535
+ }
2536
+
2537
+ /* ==================== MCP 服务管理 ==================== */
2538
+
2539
+ #mcp-servers-container .skill-card {
2540
+ border-left: 3px solid var(--border);
2541
+ transition: border-color 0.2s;
2542
+ }
2543
+ #mcp-servers-container .skill-card:hover {
2544
+ border-left-color: var(--accent);
2545
+ }
2546
+
2547
+ /* MCP key-value editor rows */
2548
+ #mcp-env-editor input,
2549
+ #mcp-headers-editor input {
2550
+ background: var(--bg-inset);
2551
+ border: 1px solid var(--border);
2552
+ border-radius: 4px;
2553
+ color: var(--text);
2554
+ outline: none;
2555
+ transition: border-color 0.15s;
2556
+ }
2557
+ #mcp-env-editor input:focus,
2558
+ #mcp-headers-editor input:focus {
2559
+ border-color: var(--accent);
2560
+ }
2561
+
2562
+ /* MCP tools list in modal */
2563
+ #mcp-tools-list > div {
2564
+ transition: background 0.15s;
2565
+ }
2566
+ #mcp-tools-list > div:hover {
2567
+ background: var(--bg-hover);
2568
+ }