Skip to content

Commit 56b4b64

Browse files
author
lu.jin
committed
feat: Add connection history management to the server URL input and bump version to 0.0.7.
1 parent 389cb14 commit 56b4b64

File tree

5 files changed

+288
-11
lines changed

5 files changed

+288
-11
lines changed

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-inspector-ui",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"author": "lujin",
55
"private": true,
66
"type": "module",

frontend/src/App.vue

Lines changed: 284 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,65 @@
3333
</svg>
3434
服务器地址
3535
</label>
36-
<input
37-
class="form-input"
38-
v-model="serverUrl"
39-
placeholder="http://localhost:8000/mcp"
40-
:disabled="connectionStatus === 'connected'"
41-
/>
36+
<div class="url-input-wrapper">
37+
<input
38+
class="form-input"
39+
v-model="serverUrl"
40+
placeholder="http://localhost:8000/mcp"
41+
:disabled="connectionStatus === 'connected'"
42+
/>
43+
<!-- History Button -->
44+
<div class="history-dropdown-container">
45+
<button
46+
class="btn-icon history-btn"
47+
@click="showHistoryDropdown = !showHistoryDropdown"
48+
:title="showHistoryDropdown ? '关闭历史记录' : '历史记录'"
49+
:disabled="connectionStatus === 'connected'"
50+
>
51+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
52+
<circle cx="12" cy="12" r="10"/>
53+
<polyline points="12 6 12 12 16 14"/>
54+
</svg>
55+
</button>
56+
<!-- Dropdown Menu -->
57+
<div v-if="showHistoryDropdown" class="history-dropdown animate-fadeIn">
58+
<div class="history-title">最近连接</div>
59+
<div v-if="connectionHistory.length === 0" class="history-empty">暂无历史记录</div>
60+
<div v-else class="history-list">
61+
<div
62+
v-for="(item, index) in connectionHistory"
63+
:key="item.timestamp"
64+
class="history-item"
65+
@click="selectHistory(item)"
66+
>
67+
<div class="history-item-content">
68+
<div class="history-url">{{ item.url }}</div>
69+
<div class="history-meta">
70+
<span v-if="item.headers.length" class="history-badge">{{ item.headers.length }} Headers</span>
71+
<span class="history-time">{{ formatHistoryTime(item.timestamp) }}</span>
72+
</div>
73+
</div>
74+
<button
75+
class="delete-history-btn"
76+
@click.stop="deleteHistoryItem(index)"
77+
title="删除此记录"
78+
>
79+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
80+
<line x1="18" y1="6" x2="6" y2="18"/>
81+
<line x1="6" y1="6" x2="18" y2="18"/>
82+
</svg>
83+
</button>
84+
</div>
85+
</div>
86+
</div>
87+
<!-- Overlay for closing -->
88+
<div
89+
v-if="showHistoryDropdown"
90+
class="dropdown-overlay"
91+
@click="showHistoryDropdown = false"
92+
></div>
93+
</div>
94+
</div>
4295
</div>
4396

4497
<!-- Headers -->
@@ -266,14 +319,20 @@
266319
</template>
267320

268321
<script setup lang="ts">
269-
import { ref, computed } from 'vue';
322+
import { ref, computed, onMounted } from 'vue';
270323
import HeaderBar from './components/HeaderBar.vue';
271324
import ToolList from './components/ToolList.vue';
272325
import ResourcePanel from './components/ResourcePanel.vue';
273326
import PromptPanel from './components/PromptPanel.vue';
274327
import type { Tool, Resource, Prompt, HeaderPair, ConnectResult, ToolCallPayload } from '@/types';
275328
import { mcpApi, isRunningInTauri } from '@/services/mcpApi';
276329
330+
interface ConnectionConfig {
331+
url: string;
332+
headers: HeaderPair[];
333+
timestamp: number;
334+
}
335+
277336
278337
// Theme initialization removed as we are now single-theme
279338
const serverUrl = ref('http://localhost:8000/mcp');
@@ -290,6 +349,82 @@ const HISTORY_SUMMARY_LENGTH = 100;
290349
const historyExpanded = ref(false);
291350
const runningInTauri = ref(isRunningInTauri());
292351
352+
// Connection History
353+
const connectionHistory = ref<ConnectionConfig[]>([]);
354+
const showHistoryDropdown = ref(false);
355+
356+
onMounted(() => {
357+
loadHistory();
358+
});
359+
360+
function loadHistory() {
361+
const saved = localStorage.getItem('mcp-connection-history');
362+
if (saved) {
363+
try {
364+
connectionHistory.value = JSON.parse(saved);
365+
// Auto-fill from latest history if available
366+
if (connectionHistory.value.length > 0) {
367+
const latest = connectionHistory.value[0];
368+
serverUrl.value = latest.url;
369+
if (latest.headers && latest.headers.length > 0) {
370+
headerInputs.value = JSON.parse(JSON.stringify(latest.headers));
371+
}
372+
} else {
373+
// Default fallback if history array is empty
374+
serverUrl.value = 'http://localhost:8080/mcp';
375+
}
376+
} catch {
377+
connectionHistory.value = [];
378+
serverUrl.value = 'http://localhost:8080/mcp';
379+
}
380+
} else {
381+
// No history saved at all
382+
serverUrl.value = 'http://localhost:8080/mcp';
383+
}
384+
}
385+
386+
function saveHistory(url: string, headers: HeaderPair[]) {
387+
const newConfig: ConnectionConfig = {
388+
url,
389+
headers,
390+
timestamp: Date.now()
391+
};
392+
393+
// Remove duplicate (same URL) to update its position/info
394+
const existingIndex = connectionHistory.value.findIndex(c => c.url === url);
395+
if (existingIndex !== -1) {
396+
connectionHistory.value.splice(existingIndex, 1);
397+
}
398+
399+
// Add to top
400+
connectionHistory.value.unshift(newConfig);
401+
402+
// Keep top 10
403+
if (connectionHistory.value.length > 10) {
404+
connectionHistory.value.pop();
405+
}
406+
407+
localStorage.setItem('mcp-connection-history', JSON.stringify(connectionHistory.value));
408+
}
409+
410+
function selectHistory(config: ConnectionConfig) {
411+
serverUrl.value = config.url;
412+
// Deep copy headers to avoid reference issues
413+
headerInputs.value = config.headers.length > 0
414+
? JSON.parse(JSON.stringify(config.headers))
415+
: [{ name: '', value: '' }];
416+
showHistoryDropdown.value = false;
417+
}
418+
419+
function deleteHistoryItem(index: number) {
420+
connectionHistory.value.splice(index, 1);
421+
localStorage.setItem('mcp-connection-history', JSON.stringify(connectionHistory.value));
422+
}
423+
424+
function formatHistoryTime(timestamp: number) {
425+
return new Date(timestamp).toLocaleString();
426+
}
427+
293428
type InspectorTab = 'tools' | 'resources' | 'prompts';
294429
295430
interface ToolResultEntry {
@@ -434,6 +569,11 @@ async function connectToServer() {
434569
} finally {
435570
isConnecting.value = false;
436571
}
572+
573+
// Save history on success
574+
if (connectionStatus.value === 'connected') {
575+
saveHistory(serverUrl.value, preparedHeaders);
576+
}
437577
}
438578
439579
async function disconnect() {
@@ -628,6 +768,143 @@ async function handleCallTool(payload: ToolCallPayload) {
628768
transition: all var(--transition-fast);
629769
}
630770
771+
.url-input-wrapper {
772+
position: relative;
773+
display: flex;
774+
gap: 8px;
775+
align-items: center;
776+
}
777+
778+
.history-btn {
779+
flex-shrink: 0;
780+
width: 42px;
781+
height: 42px;
782+
border-radius: var(--radius-md);
783+
border-color: var(--border-light);
784+
}
785+
786+
.history-dropdown-container {
787+
position: relative;
788+
}
789+
790+
.history-dropdown {
791+
position: absolute;
792+
top: 100%;
793+
right: 0;
794+
margin-top: 8px;
795+
width: 320px;
796+
background: var(--bg-card);
797+
border: 1px solid var(--border-subtle);
798+
border-radius: var(--radius-lg);
799+
box-shadow: var(--shadow-lg);
800+
z-index: 100;
801+
padding: 8px 0;
802+
backdrop-filter: blur(20px);
803+
}
804+
805+
.history-title {
806+
padding: 8px 16px;
807+
font-size: 0.8rem;
808+
font-weight: 600;
809+
color: var(--text-muted);
810+
border-bottom: 1px solid var(--border-subtle);
811+
margin-bottom: 4px;
812+
}
813+
814+
.history-empty {
815+
padding: 24px;
816+
text-align: center;
817+
color: var(--text-dim);
818+
font-size: 0.85rem;
819+
}
820+
821+
.history-list {
822+
max-height: 240px;
823+
overflow-y: auto;
824+
}
825+
826+
.history-item {
827+
padding: 10px 16px;
828+
display: flex;
829+
align-items: center;
830+
justify-content: space-between;
831+
cursor: pointer;
832+
transition: background var(--transition-fast);
833+
gap: 12px;
834+
}
835+
836+
.history-item:hover {
837+
background: var(--bg-tertiary);
838+
}
839+
840+
.history-item-content {
841+
flex: 1;
842+
min-width: 0;
843+
}
844+
845+
.history-url {
846+
font-size: 0.88rem;
847+
color: var(--text-primary);
848+
white-space: nowrap;
849+
overflow: hidden;
850+
text-overflow: ellipsis;
851+
margin-bottom: 4px;
852+
font-family: var(--font-mono);
853+
}
854+
855+
.history-meta {
856+
display: flex;
857+
align-items: center;
858+
gap: 8px;
859+
}
860+
861+
.history-badge {
862+
font-size: 0.7rem;
863+
padding: 1px 6px;
864+
background: var(--badge-bg);
865+
border-radius: var(--radius-full);
866+
color: var(--text-secondary);
867+
}
868+
869+
.history-time {
870+
font-size: 0.72rem;
871+
color: var(--text-dim);
872+
}
873+
874+
.delete-history-btn {
875+
width: 24px;
876+
height: 24px;
877+
border: none;
878+
background: transparent;
879+
color: var(--text-dim);
880+
border-radius: var(--radius-full);
881+
display: flex;
882+
align-items: center;
883+
justify-content: center;
884+
cursor: pointer;
885+
opacity: 0;
886+
transition: all var(--transition-fast);
887+
}
888+
889+
.history-item:hover .delete-history-btn {
890+
opacity: 1;
891+
}
892+
893+
.delete-history-btn:hover {
894+
background: var(--error-bg);
895+
color: var(--error);
896+
}
897+
898+
.dropdown-overlay {
899+
position: fixed;
900+
top: 0;
901+
left: 0;
902+
right: 0;
903+
bottom: 0;
904+
z-index: 90;
905+
cursor: default;
906+
}
907+
631908
.form-input:focus {
632909
outline: none;
633910
border-color: var(--border-focus);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-inspector",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"private": true,
55
"scripts": {
66
"dev": "npm run dev --prefix frontend",

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcp_inspector"
3-
version = "0.0.6"
3+
version = "0.0.7"
44
edition = "2021"
55
description = "Tauri backend for the MCP Inspector"
66
authors = ["lujin <lujin@example.com>"]

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "mcp-inspector",
4-
"version": "0.0.6",
4+
"version": "0.0.7",
55
"identifier": "com.lujin.mcpinspector",
66
"build": {
77
"frontendDist": "../frontend/dist",

0 commit comments

Comments
 (0)