@loop_ouroboros/mcp-hub-lite 1.1.0 → 1.2.0
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/CHANGELOG.md +141 -0
- package/README.md +74 -116
- package/dist/client/assets/{HomeView-Bu2joUvW.js → HomeView-BBwvy1oj.js} +1 -1
- package/dist/client/assets/{ResourceDetailView-BvrhDCD1.js → ResourceDetailView-CZ2aB73w.js} +1 -1
- package/dist/client/assets/{ResourcesView-LjqioF_s.js → ResourcesView-CN1NlhWs.js} +1 -1
- package/dist/client/assets/{ServerDashboard-FhHJFvUi.js → ServerDashboard-k652Vw4Z.js} +1 -1
- package/dist/client/assets/{ServerDetail-BKV-M4qT.js → ServerDetail-BLQ-a4cO.js} +1 -1
- package/dist/client/assets/{ServerListView-BXgtDyt3.js → ServerListView-BHrsFD5i.js} +4 -4
- package/dist/client/assets/{ServerStatusTags.vue_vue_type_script_setup_true_lang-D-ooYNdN.js → ServerStatusTags.vue_vue_type_script_setup_true_lang-BHhwEuGe.js} +1 -1
- package/dist/client/assets/{SettingsView-CMFG91Z4.js → SettingsView-CUOFNXrz.js} +1 -1
- package/dist/client/assets/{ToolCallDialog-Bf4Xe4gH.js → ToolCallDialog-BfPjLxfV.js} +1 -1
- package/dist/client/assets/ToolsView-BxgXvPC3.css +1 -0
- package/dist/client/assets/ToolsView-CyuhYAE2.js +1 -0
- package/dist/client/assets/{_baseClone-Bp9Rjwd7.js → _baseClone-DO5qfalW.js} +1 -1
- package/dist/client/assets/{el-form-item-DdSUWYsl.js → el-form-item-CcGsD2K_.js} +2 -2
- package/dist/client/assets/{el-input-99gMrutP.js → el-input-tYgeiaCT.js} +1 -1
- package/dist/client/assets/{el-loading-CIQ5pD5u.js → el-loading-Dwl9E_Vr.js} +1 -1
- package/dist/client/assets/{el-overlay-BVM6msGX.js → el-overlay-kqX_BABo.js} +1 -1
- package/dist/client/assets/{el-radio-group-DhXWy7ry.js → el-radio-group-D8aWBVOT.js} +1 -1
- package/dist/client/assets/el-skeleton-item-BRwIFspE.js +1 -0
- package/dist/client/assets/{el-switch-Bu8AQ5uM.js → el-switch-BF8c-xeU.js} +1 -1
- package/dist/client/assets/{el-tab-pane-BnGMaV56.js → el-tab-pane-C4Ep94cd.js} +1 -1
- package/dist/client/assets/{el-table-column-BMWOaLS_.js → el-table-column-Cog6uCh-.js} +1 -1
- package/dist/client/assets/{index-C2V-ZGji.js → index-ByNBhPAR.js} +1 -1
- package/dist/client/assets/index-CTB6oe-9.js +2 -0
- package/dist/client/assets/omit-CUnDT6sS.js +1 -0
- package/dist/client/assets/{raf-C2wXzaVU.js → raf-CmzeRPMd.js} +1 -1
- package/dist/client/assets/{vue-vendor-BLHLXXJK.js → vue-vendor-CbgVSHIh.js} +3 -3
- package/dist/client/index.html +2 -2
- package/dist/server/src/api/mcp/debug-response-wrapper.js +2 -2
- package/dist/server/src/api/mcp/gateway.d.ts.map +1 -1
- package/dist/server/src/api/mcp/gateway.js +17 -3
- package/dist/server/src/api/mcp/session-context-extractor.d.ts.map +1 -1
- package/dist/server/src/api/mcp/session-context-extractor.js +14 -5
- package/dist/server/src/cli/commands/mcp-tool-use.d.ts +62 -0
- package/dist/server/src/cli/commands/mcp-tool-use.d.ts.map +1 -0
- package/dist/server/src/cli/commands/mcp-tool-use.js +174 -0
- package/dist/server/src/cli/commands/server.d.ts +57 -0
- package/dist/server/src/cli/commands/server.d.ts.map +1 -0
- package/dist/server/src/cli/commands/server.js +169 -0
- package/dist/server/src/cli/commands/tool-use.d.ts +95 -0
- package/dist/server/src/cli/commands/tool-use.d.ts.map +1 -0
- package/dist/server/src/cli/commands/tool-use.js +255 -0
- package/dist/server/src/cli/index.d.ts +4 -2
- package/dist/server/src/cli/index.d.ts.map +1 -1
- package/dist/server/src/cli/index.js +35 -3
- package/dist/server/src/config/config-loader.js +1 -1
- package/dist/server/src/config/config-manager.js +1 -1
- package/dist/server/src/models/system-tools.constants.d.ts +2 -2
- package/dist/server/src/models/system-tools.constants.d.ts.map +1 -1
- package/dist/server/src/models/system-tools.constants.js +2 -2
- package/dist/server/src/services/connection/tool-cache.d.ts.map +1 -1
- package/dist/server/src/services/connection/tool-cache.js +3 -1
- package/dist/server/src/services/gateway/gateway.service.d.ts.map +1 -1
- package/dist/server/src/services/gateway/gateway.service.js +38 -4
- package/dist/server/src/services/gateway/global-transport.d.ts +14 -5
- package/dist/server/src/services/gateway/global-transport.d.ts.map +1 -1
- package/dist/server/src/services/gateway/global-transport.js +54 -30
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/initialize-handler.js +12 -1
- package/dist/server/src/services/gateway/request-handlers/system-tools-handler.js +2 -2
- package/dist/server/src/services/gateway/request-handlers/tools-handler.d.ts.map +1 -1
- package/dist/server/src/services/gateway/request-handlers/tools-handler.js +3 -4
- package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts +1 -0
- package/dist/server/src/services/hub-tools/system-tool-definitions.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools/system-tool-definitions.js +4 -3
- package/dist/server/src/services/hub-tools.service.d.ts +3 -2
- package/dist/server/src/services/hub-tools.service.d.ts.map +1 -1
- package/dist/server/src/services/hub-tools.service.js +36 -19
- package/dist/server/src/services/search/search-core.service.d.ts +5 -5
- package/dist/server/src/services/search/search-core.service.js +11 -11
- package/dist/server/src/services/session/session-manager.d.ts +256 -12
- package/dist/server/src/services/session/session-manager.d.ts.map +1 -1
- package/dist/server/src/services/session/session-manager.js +585 -23
- package/dist/server/src/services/session-tracker.service.d.ts +10 -2
- package/dist/server/src/services/session-tracker.service.d.ts.map +1 -1
- package/dist/server/src/services/session-tracker.service.js +53 -2
- package/dist/server/src/services/system-tool-handler.js +2 -2
- package/dist/server/src/utils/index.d.ts +1 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/server/src/utils/index.js +1 -0
- package/dist/server/src/utils/name-converter.d.ts +17 -0
- package/dist/server/src/utils/name-converter.d.ts.map +1 -0
- package/dist/server/src/utils/name-converter.js +27 -0
- package/dist/server/src/utils/request-context.d.ts +18 -0
- package/dist/server/src/utils/request-context.d.ts.map +1 -1
- package/dist/server/src/utils/request-context.js +20 -0
- package/dist/server/tests/evaluation/evaluation.test.js +9 -10
- package/dist/server/tests/integration/api/gateway.test.js +2 -2
- package/dist/server/tests/unit/services/hub-tools.service.test.js +1 -1
- package/dist/server/tests/unit/utils/name-converter.test.d.ts +2 -0
- package/dist/server/tests/unit/utils/name-converter.test.d.ts.map +1 -0
- package/dist/server/tests/unit/utils/name-converter.test.js +69 -0
- package/dist/server/tests/unit/utils/request-context.test.js +24 -5
- package/package.json +3 -1
- package/dist/client/assets/ToolsView-DFpha1z0.js +0 -1
- package/dist/client/assets/ToolsView-E3Ps9c7i.css +0 -1
- package/dist/client/assets/el-skeleton-item-DJz-Us12.js +0 -1
- package/dist/client/assets/index-vhkqgpmN.js +0 -2
- package/dist/client/assets/omit-CqPQN3XP.js +0 -1
|
@@ -47,6 +47,8 @@ declare class SessionTrackerService {
|
|
|
47
47
|
* @param context.clientName - Optional name of the client application
|
|
48
48
|
* @param context.clientVersion - Optional version of the client application
|
|
49
49
|
* @param context.protocolVersion - Optional MCP protocol version
|
|
50
|
+
* @param context.project - Optional project identifier
|
|
51
|
+
* @param context.cwd - Optional current working directory
|
|
50
52
|
* @param context.userAgent - Optional user agent string
|
|
51
53
|
* @param context.ip - Optional session IP address
|
|
52
54
|
*
|
|
@@ -54,7 +56,8 @@ declare class SessionTrackerService {
|
|
|
54
56
|
* sessionTrackerService.updateSession({
|
|
55
57
|
* sessionId: 'session-123',
|
|
56
58
|
* clientName: 'VS Code',
|
|
57
|
-
* clientVersion: '1.85.0'
|
|
59
|
+
* clientVersion: '1.85.0',
|
|
60
|
+
* cwd: '/home/user/project'
|
|
58
61
|
* });
|
|
59
62
|
*/
|
|
60
63
|
updateSession(context: SessionContext): void;
|
|
@@ -62,7 +65,12 @@ declare class SessionTrackerService {
|
|
|
62
65
|
* Updates the workspace roots for a specific session.
|
|
63
66
|
*
|
|
64
67
|
* This method is typically called when a session provides its workspace root
|
|
65
|
-
* directories.
|
|
68
|
+
* directories, which helps determine the session's working directory context.
|
|
69
|
+
* If the session doesn't have a current working directory (cwd) set, it will
|
|
70
|
+
* attempt to infer one from the first root URI in the list.
|
|
71
|
+
*
|
|
72
|
+
* For file:// URIs, it converts them to local file paths using Node.js's
|
|
73
|
+
* fileURLToPath utility. For other URI schemes, it uses the URI directly.
|
|
66
74
|
*
|
|
67
75
|
* @param sessionId - The unique session identifier for the session
|
|
68
76
|
* @param roots - Array of session root objects containing URI information
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-tracker.service.d.ts","sourceRoot":"","sources":["../../../../src/services/session-tracker.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,WAAW,EACZ,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"session-tracker.service.d.ts","sourceRoot":"","sources":["../../../../src/services/session-tracker.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,WAAW,EACZ,MAAM,wCAAwC,CAAC;AAOhD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAM,qBAAqB;IACzB,OAAO,CAAC,QAAQ,CAAuC;IAEvD,OAAO,KAAK,UAAU,GAErB;IAED;;;;;OAKG;;IAMH;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACI,aAAa,CAAC,OAAO,EAAE,cAAc;IA4B5C;;;;;;;;;;;;;;;;;;;OAmBG;IACI,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE;IAoDjE;;;;;;;;;;;;OAYG;IACI,WAAW,IAAI,WAAW,EAAE;IAInC;;;;;;;;;;;;;;OAcG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI7D;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,OAAO;CAkBhB;AAED,eAAO,MAAM,qBAAqB,uBAA8B,CAAC;AAEjE,YAAY,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { logger, LOG_MODULES } from '../utils/logger.js';
|
|
2
2
|
import { eventBus } from './event-bus.service.js';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import { configManager } from '../config/config-manager.js';
|
|
4
5
|
import { formatDuration } from '../utils/format-utils.js';
|
|
5
6
|
/**
|
|
@@ -56,6 +57,8 @@ class SessionTrackerService {
|
|
|
56
57
|
* @param context.clientName - Optional name of the client application
|
|
57
58
|
* @param context.clientVersion - Optional version of the client application
|
|
58
59
|
* @param context.protocolVersion - Optional MCP protocol version
|
|
60
|
+
* @param context.project - Optional project identifier
|
|
61
|
+
* @param context.cwd - Optional current working directory
|
|
59
62
|
* @param context.userAgent - Optional user agent string
|
|
60
63
|
* @param context.ip - Optional session IP address
|
|
61
64
|
*
|
|
@@ -63,7 +66,8 @@ class SessionTrackerService {
|
|
|
63
66
|
* sessionTrackerService.updateSession({
|
|
64
67
|
* sessionId: 'session-123',
|
|
65
68
|
* clientName: 'VS Code',
|
|
66
|
-
* clientVersion: '1.85.0'
|
|
69
|
+
* clientVersion: '1.85.0',
|
|
70
|
+
* cwd: '/home/user/project'
|
|
67
71
|
* });
|
|
68
72
|
*/
|
|
69
73
|
updateSession(context) {
|
|
@@ -75,6 +79,8 @@ class SessionTrackerService {
|
|
|
75
79
|
clientVersion: context.clientVersion || existing?.clientVersion,
|
|
76
80
|
protocolVersion: context.protocolVersion || existing?.protocolVersion,
|
|
77
81
|
capabilities: context.capabilities || existing?.capabilities,
|
|
82
|
+
project: context.project || existing?.project,
|
|
83
|
+
cwd: context.cwd || existing?.cwd, // Preserve CWD if not provided in new request (e.g. inferred from roots)
|
|
78
84
|
userAgent: context.userAgent || existing?.userAgent,
|
|
79
85
|
ip: context.ip || existing?.ip,
|
|
80
86
|
lastSeen: Date.now(),
|
|
@@ -93,7 +99,12 @@ class SessionTrackerService {
|
|
|
93
99
|
* Updates the workspace roots for a specific session.
|
|
94
100
|
*
|
|
95
101
|
* This method is typically called when a session provides its workspace root
|
|
96
|
-
* directories.
|
|
102
|
+
* directories, which helps determine the session's working directory context.
|
|
103
|
+
* If the session doesn't have a current working directory (cwd) set, it will
|
|
104
|
+
* attempt to infer one from the first root URI in the list.
|
|
105
|
+
*
|
|
106
|
+
* For file:// URIs, it converts them to local file paths using Node.js's
|
|
107
|
+
* fileURLToPath utility. For other URI schemes, it uses the URI directly.
|
|
97
108
|
*
|
|
98
109
|
* @param sessionId - The unique session identifier for the session
|
|
99
110
|
* @param roots - Array of session root objects containing URI information
|
|
@@ -109,6 +120,46 @@ class SessionTrackerService {
|
|
|
109
120
|
if (session) {
|
|
110
121
|
session.roots = roots;
|
|
111
122
|
session.lastSeen = Date.now();
|
|
123
|
+
// If CWD is missing, try to infer from roots
|
|
124
|
+
if (!session.cwd && roots.length > 0) {
|
|
125
|
+
// Convert file:// uri to path if possible, or just use URI
|
|
126
|
+
const root = roots[0];
|
|
127
|
+
if (root.uri.startsWith('file://')) {
|
|
128
|
+
try {
|
|
129
|
+
session.cwd = fileURLToPath(root.uri);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
session.cwd = root.uri;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
session.cwd = root.uri;
|
|
137
|
+
}
|
|
138
|
+
logger.debug(`Inferred CWD for session ${sessionId} from roots: ${session.cwd}`, LOG_MODULES.SESSION_TRACKER);
|
|
139
|
+
}
|
|
140
|
+
// If project is missing, try to infer from roots (use name or last path segment)
|
|
141
|
+
if (!session.project && roots.length > 0) {
|
|
142
|
+
const root = roots[0];
|
|
143
|
+
if (root.name) {
|
|
144
|
+
session.project = root.name;
|
|
145
|
+
}
|
|
146
|
+
else if (root.uri.startsWith('file://')) {
|
|
147
|
+
try {
|
|
148
|
+
const localPath = fileURLToPath(root.uri);
|
|
149
|
+
const pathSegments = localPath.split(/[/\\]/);
|
|
150
|
+
const lastSegment = pathSegments.filter(Boolean).pop();
|
|
151
|
+
if (lastSegment) {
|
|
152
|
+
session.project = lastSegment;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// If path parsing fails, don't set project
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (session.project) {
|
|
160
|
+
logger.debug(`Inferred project for session ${sessionId} from roots: ${session.project}`, LOG_MODULES.SESSION_TRACKER);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
112
163
|
}
|
|
113
164
|
}
|
|
114
165
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hubToolsService } from './hub-tools.service.js';
|
|
2
2
|
import { McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { logger, LOG_MODULES } from '../utils/logger.js';
|
|
4
|
-
import { LIST_SERVERS_TOOL,
|
|
4
|
+
import { LIST_SERVERS_TOOL, LIST_TOOLS_TOOL, GET_TOOL_TOOL, CALL_TOOL_TOOL, UPDATE_SERVER_DESCRIPTION_TOOL, MCP_HUB_LITE_SERVER } from '../models/system-tools.constants.js';
|
|
5
5
|
import { stringifyForLogging } from '../utils/json-utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* Unified system tool call handler
|
|
@@ -18,7 +18,7 @@ export class SystemToolHandler {
|
|
|
18
18
|
case LIST_SERVERS_TOOL:
|
|
19
19
|
result = await hubToolsService.listServers();
|
|
20
20
|
break;
|
|
21
|
-
case
|
|
21
|
+
case LIST_TOOLS_TOOL: {
|
|
22
22
|
const listToolsArgs = toolArgs;
|
|
23
23
|
result = await hubToolsService.listToolsInServer(listToolsArgs);
|
|
24
24
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a tool name to a standard format for comparison.
|
|
3
|
+
*
|
|
4
|
+
* This function converts various naming conventions (snake_case, kebab-case,
|
|
5
|
+
* camelCase, space-separated, or uppercase) into a normalized lowercase
|
|
6
|
+
* underscore format for consistent matching.
|
|
7
|
+
*
|
|
8
|
+
* @param toolName - The tool name to normalize
|
|
9
|
+
* @returns Normalized tool name in lowercase underscore format
|
|
10
|
+
* @example
|
|
11
|
+
* normalizeToolName('list-servers') // returns 'list_servers'
|
|
12
|
+
* normalizeToolName('LIST_SERVERS') // returns 'list_servers'
|
|
13
|
+
* normalizeToolName('chatCompletions') // returns 'chat_completions'
|
|
14
|
+
* normalizeToolName('chat_completions') // returns 'chat_completions'
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeToolName(toolName: string): string;
|
|
17
|
+
//# sourceMappingURL=name-converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-converter.d.ts","sourceRoot":"","sources":["../../../../src/utils/name-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAa1D"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a tool name to a standard format for comparison.
|
|
3
|
+
*
|
|
4
|
+
* This function converts various naming conventions (snake_case, kebab-case,
|
|
5
|
+
* camelCase, space-separated, or uppercase) into a normalized lowercase
|
|
6
|
+
* underscore format for consistent matching.
|
|
7
|
+
*
|
|
8
|
+
* @param toolName - The tool name to normalize
|
|
9
|
+
* @returns Normalized tool name in lowercase underscore format
|
|
10
|
+
* @example
|
|
11
|
+
* normalizeToolName('list-servers') // returns 'list_servers'
|
|
12
|
+
* normalizeToolName('LIST_SERVERS') // returns 'list_servers'
|
|
13
|
+
* normalizeToolName('chatCompletions') // returns 'chat_completions'
|
|
14
|
+
* normalizeToolName('chat_completions') // returns 'chat_completions'
|
|
15
|
+
*/
|
|
16
|
+
export function normalizeToolName(toolName) {
|
|
17
|
+
return (toolName
|
|
18
|
+
// Insert underscore before uppercase letters (for camelCase handling)
|
|
19
|
+
// e.g., 'chatCompletions' -> 'chat_Completions'
|
|
20
|
+
.replace(/([a-z])([A-Z])/g, '$1_$2')
|
|
21
|
+
// Convert to lowercase
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
// Replace hyphens, underscores, and spaces with single underscore
|
|
24
|
+
.replace(/[-_\s]+/g, '_')
|
|
25
|
+
// Remove leading and trailing underscores
|
|
26
|
+
.replace(/^_+|_+$/g, ''));
|
|
27
|
+
}
|
|
@@ -50,4 +50,22 @@ export declare const requestContext: AsyncLocalStorage<SessionContext>;
|
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
52
|
export declare function getSessionContext(): SessionContext | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Retrieves the current request's working directory (cwd).
|
|
55
|
+
*
|
|
56
|
+
* This is a convenience function that extracts the cwd property from the
|
|
57
|
+
* current request's session context. It's commonly used in file operations
|
|
58
|
+
* that need to respect the session's current working directory.
|
|
59
|
+
*
|
|
60
|
+
* @returns {string | undefined} The current request's working directory, or undefined if not available
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const cwd = getSessionCwd();
|
|
65
|
+
* if (cwd) {
|
|
66
|
+
* const fullPath = path.join(cwd, relativePath);
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function getSessionCwd(): string | undefined;
|
|
53
71
|
//# sourceMappingURL=request-context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/utils/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAE7E;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,mCAA0C,CAAC;AAEtE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D"}
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../../../src/utils/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wCAAwC,CAAC;AAE7E;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,mCAA0C,CAAC;AAEtE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD"}
|
|
@@ -51,3 +51,23 @@ export const requestContext = new AsyncLocalStorage();
|
|
|
51
51
|
export function getSessionContext() {
|
|
52
52
|
return requestContext.getStore();
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Retrieves the current request's working directory (cwd).
|
|
56
|
+
*
|
|
57
|
+
* This is a convenience function that extracts the cwd property from the
|
|
58
|
+
* current request's session context. It's commonly used in file operations
|
|
59
|
+
* that need to respect the session's current working directory.
|
|
60
|
+
*
|
|
61
|
+
* @returns {string | undefined} The current request's working directory, or undefined if not available
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const cwd = getSessionCwd();
|
|
66
|
+
* if (cwd) {
|
|
67
|
+
* const fullPath = path.join(cwd, relativePath);
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function getSessionCwd() {
|
|
72
|
+
return requestContext.getStore()?.cwd;
|
|
73
|
+
}
|
|
@@ -84,20 +84,19 @@ describe('MCP Evaluation Tests', () => {
|
|
|
84
84
|
expect(hasDestructiveIndicator, `Answer ${index + 1} may contain destructive operations: "${answer}"`).toBe(false);
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
|
-
it('should reference valid
|
|
87
|
+
it('should reference valid tools', () => {
|
|
88
88
|
const validTools = [
|
|
89
|
-
'
|
|
90
|
-
'
|
|
91
|
-
'
|
|
92
|
-
'
|
|
93
|
-
'
|
|
94
|
-
'
|
|
95
|
-
'
|
|
89
|
+
'list-servers',
|
|
90
|
+
'find-servers',
|
|
91
|
+
'list-all-tools-in-server',
|
|
92
|
+
'find-tools-in-server',
|
|
93
|
+
'get-tool',
|
|
94
|
+
'call-tool',
|
|
95
|
+
'find-tools'
|
|
96
96
|
];
|
|
97
97
|
const content = fs.readFileSync(evaluationFile, 'utf-8');
|
|
98
|
-
const normalizedContent = content.replace(/\b[a-z]+(?:-[a-z]+)+\b/g, (match) => match.replace(/-/g, '_'));
|
|
99
98
|
validTools.forEach((tool) => {
|
|
100
|
-
expect(
|
|
99
|
+
expect(content).toContain(tool);
|
|
101
100
|
});
|
|
102
101
|
});
|
|
103
102
|
});
|
|
@@ -127,7 +127,7 @@ describe('GatewayService', () => {
|
|
|
127
127
|
vi.mocked(mocks.getServerById).mockReturnValue({
|
|
128
128
|
name: 'Test Server',
|
|
129
129
|
id: 'server1',
|
|
130
|
-
config: {
|
|
130
|
+
config: { allowedTools: ['testTool'] },
|
|
131
131
|
instance: { id: 'server1', timestamp: Date.now(), hash: 'abc123' }
|
|
132
132
|
});
|
|
133
133
|
// Populate toolCache for the test
|
|
@@ -170,7 +170,7 @@ describe('GatewayService', () => {
|
|
|
170
170
|
vi.mocked(mocks.getServerById).mockReturnValue({
|
|
171
171
|
name: 'Test Server',
|
|
172
172
|
id: 'server1',
|
|
173
|
-
config: {
|
|
173
|
+
config: { allowedTools: ['testTool'] },
|
|
174
174
|
instance: { id: 'server1', timestamp: Date.now(), hash: 'abc123' }
|
|
175
175
|
});
|
|
176
176
|
// Find list tools handler to populate tool map
|
|
@@ -613,7 +613,7 @@ describe('HubToolsService', () => {
|
|
|
613
613
|
// Assert system tools - should have 5 tools now
|
|
614
614
|
const systemToolNames = allTools['mcp-hub-lite'].tools.map((t) => t.name);
|
|
615
615
|
expect(systemToolNames).toContain('list_servers');
|
|
616
|
-
expect(systemToolNames).toContain('
|
|
616
|
+
expect(systemToolNames).toContain('list_tools');
|
|
617
617
|
expect(systemToolNames).toContain('get_tool');
|
|
618
618
|
expect(systemToolNames).toContain('call_tool');
|
|
619
619
|
expect(systemToolNames).toContain('update_server_description');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-converter.test.d.ts","sourceRoot":"","sources":["../../../../../tests/unit/utils/name-converter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { normalizeToolName } from '../../../src/utils/name-converter.js';
|
|
3
|
+
describe('name-converter', () => {
|
|
4
|
+
describe('normalizeToolName', () => {
|
|
5
|
+
it('should convert kebab-case to snake_case', () => {
|
|
6
|
+
expect(normalizeToolName('list-servers')).toBe('list_servers');
|
|
7
|
+
expect(normalizeToolName('get-tool')).toBe('get_tool');
|
|
8
|
+
expect(normalizeToolName('call-tool')).toBe('call_tool');
|
|
9
|
+
});
|
|
10
|
+
it('should convert uppercase to lowercase', () => {
|
|
11
|
+
expect(normalizeToolName('LIST_SERVERS')).toBe('list_servers');
|
|
12
|
+
expect(normalizeToolName('GET_TOOL')).toBe('get_tool');
|
|
13
|
+
expect(normalizeToolName('LIST_SERVERS_TOOL')).toBe('list_servers_tool');
|
|
14
|
+
});
|
|
15
|
+
it('should convert mixed case to lowercase with underscores', () => {
|
|
16
|
+
expect(normalizeToolName('ListServers')).toBe('list_servers');
|
|
17
|
+
expect(normalizeToolName('GetTool')).toBe('get_tool');
|
|
18
|
+
expect(normalizeToolName('chatCompletions')).toBe('chat_completions');
|
|
19
|
+
});
|
|
20
|
+
it('should convert space-separated to underscores', () => {
|
|
21
|
+
expect(normalizeToolName('list servers')).toBe('list_servers');
|
|
22
|
+
expect(normalizeToolName('get tool info')).toBe('get_tool_info');
|
|
23
|
+
});
|
|
24
|
+
it('should handle already normalized names', () => {
|
|
25
|
+
expect(normalizeToolName('list_servers')).toBe('list_servers');
|
|
26
|
+
expect(normalizeToolName('get_tool')).toBe('get_tool');
|
|
27
|
+
expect(normalizeToolName('chat_completions')).toBe('chat_completions');
|
|
28
|
+
});
|
|
29
|
+
it('should remove leading and trailing underscores', () => {
|
|
30
|
+
expect(normalizeToolName('_list_servers_')).toBe('list_servers');
|
|
31
|
+
expect(normalizeToolName('__get_tool__')).toBe('get_tool');
|
|
32
|
+
});
|
|
33
|
+
it('should handle multiple consecutive separators', () => {
|
|
34
|
+
expect(normalizeToolName('list--servers')).toBe('list_servers');
|
|
35
|
+
expect(normalizeToolName('list__servers')).toBe('list_servers');
|
|
36
|
+
expect(normalizeToolName('list servers')).toBe('list_servers');
|
|
37
|
+
expect(normalizeToolName('list-_-servers')).toBe('list_servers');
|
|
38
|
+
});
|
|
39
|
+
it('should handle empty string', () => {
|
|
40
|
+
expect(normalizeToolName('')).toBe('');
|
|
41
|
+
});
|
|
42
|
+
it('should handle single character', () => {
|
|
43
|
+
expect(normalizeToolName('a')).toBe('a');
|
|
44
|
+
expect(normalizeToolName('A')).toBe('a');
|
|
45
|
+
});
|
|
46
|
+
it('should handle names with numbers', () => {
|
|
47
|
+
expect(normalizeToolName('tool123')).toBe('tool123');
|
|
48
|
+
expect(normalizeToolName('tool_123')).toBe('tool_123');
|
|
49
|
+
expect(normalizeToolName('tool-123')).toBe('tool_123');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('normalization consistency', () => {
|
|
53
|
+
it('should normalize different formats to the same value for same base name', () => {
|
|
54
|
+
// All these should normalize to the same value
|
|
55
|
+
const normalized = normalizeToolName('list_servers');
|
|
56
|
+
expect(normalizeToolName('list-servers')).toBe(normalized);
|
|
57
|
+
expect(normalizeToolName('LIST_SERVERS')).toBe(normalized);
|
|
58
|
+
expect(normalizeToolName('list_servers')).toBe(normalized);
|
|
59
|
+
expect(normalizeToolName('List_Servers')).toBe(normalized);
|
|
60
|
+
});
|
|
61
|
+
it('should convert camelCase to snake_case', () => {
|
|
62
|
+
// Note: camelCase normalization properly handles uppercase boundaries
|
|
63
|
+
// e.g., 'chatCompletions' -> 'chat_Completions' -> 'chat_completions'
|
|
64
|
+
expect(normalizeToolName('chatCompletions')).toBe('chat_completions');
|
|
65
|
+
expect(normalizeToolName('getTool')).toBe('get_tool');
|
|
66
|
+
expect(normalizeToolName('listServers')).toBe('list_servers');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { requestContext, getSessionContext } from '../../../src/utils/request-context.js';
|
|
2
|
+
import { requestContext, getSessionContext, getSessionCwd } from '../../../src/utils/request-context.js';
|
|
3
3
|
describe('Request Context', () => {
|
|
4
4
|
beforeEach(() => {
|
|
5
5
|
// Clean up any existing context
|
|
@@ -11,11 +11,14 @@ describe('Request Context', () => {
|
|
|
11
11
|
});
|
|
12
12
|
it('should return undefined when no context is set', () => {
|
|
13
13
|
expect(getSessionContext()).toBeUndefined();
|
|
14
|
+
expect(getSessionCwd()).toBeUndefined();
|
|
14
15
|
});
|
|
15
16
|
it('should store and retrieve session context correctly', async () => {
|
|
16
17
|
const testContext = {
|
|
17
18
|
sessionId: 'test-session',
|
|
18
19
|
clientName: 'Test Client',
|
|
20
|
+
cwd: '/test/cwd',
|
|
21
|
+
project: 'test-project',
|
|
19
22
|
ip: '127.0.0.1',
|
|
20
23
|
userAgent: 'test-agent',
|
|
21
24
|
timestamp: Date.now()
|
|
@@ -23,6 +26,8 @@ describe('Request Context', () => {
|
|
|
23
26
|
await requestContext.run(testContext, () => {
|
|
24
27
|
const context = getSessionContext();
|
|
25
28
|
expect(context).toEqual(testContext);
|
|
29
|
+
const cwd = getSessionCwd();
|
|
30
|
+
expect(cwd).toBe('/test/cwd');
|
|
26
31
|
});
|
|
27
32
|
});
|
|
28
33
|
it('should handle partial context correctly', async () => {
|
|
@@ -33,15 +38,19 @@ describe('Request Context', () => {
|
|
|
33
38
|
await requestContext.run(partialContext, () => {
|
|
34
39
|
const context = getSessionContext();
|
|
35
40
|
expect(context).toEqual(partialContext);
|
|
41
|
+
const cwd = getSessionCwd();
|
|
42
|
+
expect(cwd).toBeUndefined();
|
|
36
43
|
});
|
|
37
44
|
});
|
|
38
45
|
it('should maintain context isolation between async operations', async () => {
|
|
39
46
|
const context1 = {
|
|
40
47
|
sessionId: 'session-1',
|
|
48
|
+
cwd: '/path/1',
|
|
41
49
|
timestamp: Date.now()
|
|
42
50
|
};
|
|
43
51
|
const context2 = {
|
|
44
52
|
sessionId: 'session-2',
|
|
53
|
+
cwd: '/path/2',
|
|
45
54
|
timestamp: Date.now()
|
|
46
55
|
};
|
|
47
56
|
let result1;
|
|
@@ -49,15 +58,25 @@ describe('Request Context', () => {
|
|
|
49
58
|
const operation1 = requestContext.run(context1, async () => {
|
|
50
59
|
// Simulate async operation
|
|
51
60
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
52
|
-
result1 =
|
|
61
|
+
result1 = getSessionCwd();
|
|
53
62
|
});
|
|
54
63
|
const operation2 = requestContext.run(context2, async () => {
|
|
55
64
|
// Simulate async operation
|
|
56
65
|
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
57
|
-
result2 =
|
|
66
|
+
result2 = getSessionCwd();
|
|
58
67
|
});
|
|
59
68
|
await Promise.all([operation1, operation2]);
|
|
60
|
-
expect(result1).
|
|
61
|
-
expect(result2).
|
|
69
|
+
expect(result1).toBe('/path/1');
|
|
70
|
+
expect(result2).toBe('/path/2');
|
|
71
|
+
});
|
|
72
|
+
it('should return undefined for getSessionCwd when cwd is not set', async () => {
|
|
73
|
+
const contextWithoutCwd = {
|
|
74
|
+
sessionId: 'no-cwd-session',
|
|
75
|
+
timestamp: Date.now()
|
|
76
|
+
};
|
|
77
|
+
await requestContext.run(contextWithoutCwd, () => {
|
|
78
|
+
const cwd = getSessionCwd();
|
|
79
|
+
expect(cwd).toBeUndefined();
|
|
80
|
+
});
|
|
62
81
|
});
|
|
63
82
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loop_ouroboros/mcp-hub-lite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "A lightweight MCP management platform designed for independent developers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "loop_ouroboros",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"status": "node dist/server/src/cli/index.js status",
|
|
42
42
|
"list": "node dist/server/src/cli/index.js list",
|
|
43
43
|
"ui": "node dist/server/src/cli/index.js ui",
|
|
44
|
+
"tool-use": "node dist/server/src/cli/index.js tool-use",
|
|
44
45
|
"dev": "run-p dev:client dev:server",
|
|
45
46
|
"dev:client": "vite",
|
|
46
47
|
"dev:server": "tsx src/server/dev-server.ts",
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
"fastify": "^5.6.2",
|
|
74
75
|
"open": "^11.0.0",
|
|
75
76
|
"pinia": "^3.0.4",
|
|
77
|
+
"undici": "^8.1.0",
|
|
76
78
|
"vue": "^3.5.26",
|
|
77
79
|
"vue-i18n": "^11.2.7",
|
|
78
80
|
"vue-router": "^4.6.4",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as H,R as J,E as M,k as B,h as Q,S as K,U as z,s as W,V as X}from"./index-vhkqgpmN.js";import{E as Y}from"./el-skeleton-item-DJz-Us12.js";import{E as Z}from"./el-input-99gMrutP.js";import{t as O,A as i,C as t,U as P,J as E,$ as n,y as a,a6 as ee,r as m,c as te,o as se,x as T,O as l,G as y,u as g,H as F,a9 as R,L as j,P as S,af as V}from"./vue-vendor-BLHLXXJK.js";import{T as oe}from"./ToolCallDialog-Bf4Xe4gH.js";import{_ as ae}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./typescript-Bp3YSIOJ.js";import"./event-BB_Ol6Sd.js";import"./el-overlay-BVM6msGX.js";import"./index-C2V-ZGji.js";const le={class:"min-w-0 mb-3"},ne={class:"flex items-center gap-2 mb-2"},re=["title"],ie=["title"],L=O({__name:"ToolCard",props:{title:{},description:{},tagName:{},tagClass:{}},emits:["call"],setup(c){return(f,v)=>(a(),i("div",{class:"bg-white dark:bg-[#1e293b] border border-gray-200 dark:border-gray-700 rounded-lg p-4 flex flex-col justify-between shadow-sm hover:shadow-md transition-shadow h-full cursor-pointer",onClick:v[0]||(v[0]=_=>f.$emit("call"))},[t("div",le,[t("div",ne,[c.tagName?(a(),i("span",{key:0,class:E(["shrink-0 px-2 py-0.5 rounded-full text-xs font-medium whitespace-nowrap",c.tagClass||"bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300"])},n(c.tagName),3)):P("",!0),t("span",{class:"font-bold text-gray-900 dark:text-gray-100 font-mono text-base break-all",title:c.title},n(c.title),9,re)]),t("p",{class:"text-sm text-gray-600 dark:text-gray-400 line-clamp-2",title:c.description},n(c.description||f.$t("tools.noDescription")),9,ie)])]))}}),ce={class:"tools-view py-6 px-4 sm:px-6 lg:px-8 max-w-7xl mx-auto w-full h-full flex flex-col overflow-hidden bg-gray-50 dark:bg-[#0f172a] transition-colors duration-300"},de={class:"mb-6 shrink-0"},ue={class:"text-2xl font-semibold text-gray-900 dark:text-white mb-4"},me={class:"relative"},ve={class:"flex-1 overflow-y-auto custom-scrollbar space-y-8 pr-2"},pe={class:"text-lg font-bold text-gray-900 dark:text-white"},ge={class:"text-sm font-normal text-gray-500 ml-2"},fe={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-8 transition-all duration-300"},he={class:"flex items-center gap-2 mb-4"},xe={class:"text-lg font-bold text-gray-900 dark:text-white"},ye={class:"text-sm font-normal text-gray-500 ml-2"},_e={key:0,class:"space-y-4"},be={key:1,class:"text-center py-8 text-gray-500"},ke={key:2,class:"space-y-6"},we=["onClick"],Ce={class:"text-xs bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded-full"},$e={class:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 transition-all duration-300"},Ne=O({__name:"ToolsView",setup(c){const{t:f}=ee(),v=m(""),_=m(!1),D=m([]),k=H(),w=m([]),C=m(!1),p=m(null),h=m(new Set),b=m(!1);function q(e){h.value.has(e)?h.value.delete(e):h.value.add(e)}async function A(){try{const e=await B.get("/web/hub-tools/system");w.value=e.map(s=>({...s,serverName:"mcp-hub-lite"})).sort((s,d)=>s.name.localeCompare(d.name))}catch(e){console.error("Failed to fetch system tools:",e)}}function I(e){p.value={...e,serverName:e.serverName},C.value=!0}async function U(){_.value=!0;try{const e=await B.get(`/web/search?q=${encodeURIComponent(v.value)}`);D.value=e.results||[]}catch(e){console.error("Failed to fetch tools:",e)}finally{_.value=!1}}function G(){U()}const $=te(()=>{const e={};return D.value.forEach(s=>{const x=k.servers.find(N=>N.name===s.tool.serverName)?.status==="online"?f("tools.online"):f("tools.offline"),r=s.tool.serverName?`${s.tool.serverName} (${x})`:"Unknown";e[r]||(e[r]=[]),e[r].push(s)}),Object.entries(e).map(([s,d])=>({serverName:s,tools:d.sort((x,r)=>x.tool.name.localeCompare(r.tool.name))})).sort((s,d)=>s.serverName.localeCompare(d.serverName))});return se(()=>{A(),U(),k.servers.length===0&&k.fetchServers()}),(e,s)=>{const d=Q,x=Z,r=M,N=Y;return a(),i("div",ce,[t("div",de,[t("h2",ue,n(e.$t("tools.title")),1),t("div",me,[l(x,{modelValue:v.value,"onUpdate:modelValue":s[0]||(s[0]=o=>v.value=o),placeholder:e.$t("tools.searchPlaceholder"),class:"w-full",size:"large","prefix-icon":g(J),onInput:G},{append:y(()=>[l(d,{icon:g(K)},null,8,["icon"])]),_:1},8,["modelValue","placeholder","prefix-icon"])])]),t("div",ve,[t("section",null,[t("div",{class:"flex items-center gap-2 mb-4 cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200 transition-colors",onClick:s[1]||(s[1]=o=>b.value=!b.value)},[l(r,{class:E(["transition-transform duration-200",{"-rotate-90":b.value}])},{default:y(()=>[l(g(z))]),_:1},8,["class"]),l(r,{class:"text-gray-900 dark:text-white",size:20},{default:y(()=>[l(g(W))]),_:1}),t("h3",pe,[R(n(e.$t("tools.systemTools"))+" ",1),t("span",ge,"("+n(w.value.length)+")",1)])]),F(t("div",fe,[(a(!0),i(S,null,V(w.value,o=>(a(),T(L,{key:o.name,title:o.name,description:o.description,"tag-name":e.$t("tools.systemTag"),"tag-class":"bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300",onCall:u=>I(o)},null,8,["title","description","tag-name","onCall"]))),128))],512),[[j,!b.value]])]),t("section",null,[t("div",he,[l(r,{class:"text-gray-900 dark:text-white",size:20},{default:y(()=>[l(g(X))]),_:1}),t("h3",xe,[R(n(e.$t("tools.aggregatedTools"))+" ",1),t("span",ye,"("+n($.value.reduce((o,u)=>o+u.tools.length,0))+")",1)])]),_.value?(a(),i("div",_e,[l(N,{animated:"",count:3})])):$.value.length===0?(a(),i("div",be,n(e.$t("tools.noToolsFound")),1)):(a(),i("div",ke,[(a(!0),i(S,null,V($.value,o=>(a(),i("div",{key:o.serverName,class:"space-y-3"},[t("div",{class:"flex items-center gap-2 text-sm font-medium text-gray-500 dark:text-gray-400 px-1 cursor-pointer select-none hover:text-gray-700 dark:hover:text-gray-200 transition-colors",onClick:u=>q(o.serverName)},[l(r,{class:E(["transition-transform duration-200",{"-rotate-90":h.value.has(o.serverName)}])},{default:y(()=>[l(g(z))]),_:1},8,["class"]),t("span",null,n(o.serverName),1),t("span",Ce,n(o.tools.length),1)],8,we),F(t("div",$e,[(a(!0),i(S,null,V(o.tools,u=>(a(),T(L,{key:u.tool.name,title:u.tool.name,description:u.tool.description,onCall:Te=>I(u.tool)},null,8,["title","description","onCall"]))),128))],512),[[j,!h.value.has(o.serverName)]])]))),128))]))])]),p.value?(a(),T(oe,{key:0,modelValue:C.value,"onUpdate:modelValue":s[2]||(s[2]=o=>C.value=o),"server-name":p.value.serverName,"tool-name":p.value.name,description:p.value.description,"input-schema":p.value.inputSchema},null,8,["modelValue","server-name","tool-name","description","input-schema"])):P("",!0)])}}}),je=ae(Ne,[["__scopeId","data-v-465acdb9"]]);export{je as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.custom-scrollbar[data-v-465acdb9]::-webkit-scrollbar{width:6px}.custom-scrollbar[data-v-465acdb9]::-webkit-scrollbar-track{background:transparent}.custom-scrollbar[data-v-465acdb9]::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}.dark .custom-scrollbar[data-v-465acdb9]::-webkit-scrollbar-thumb{background:#475569}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as _,d as B,_ as b,f as h,W as P,X as E,G as I,g as T,Y as $}from"./index-vhkqgpmN.js";import{t as w,A as u,y as i,x as N,U as S,u as t,J as d,d as k,r as V,o as C,w as O,D as j,v,P as m,af as g,B as y,a2 as z,O as L}from"./vue-vendor-BLHLXXJK.js";const R=_({animated:Boolean,count:{type:Number,default:1},rows:{type:Number,default:3},loading:{type:Boolean,default:!0},throttle:{type:B([Number,Object])}}),U=_({variant:{type:String,values:["circle","rect","h1","h3","text","caption","p","image","button"],default:"text"}}),A=w({name:"ElSkeletonItem",__name:"skeleton-item",props:U,setup(l){const e=h("skeleton");return(o,a)=>(i(),u("div",{class:d([t(e).e("item"),t(e).e(o.variant)])},[o.variant==="image"?(i(),N(t(P),{key:0})):S("v-if",!0)],2))}});var p=b(A,[["__file","/home/runner/work/element-plus/element-plus/packages/components/skeleton/src/skeleton-item.vue"]]);const D=(l,e=0)=>{if(e===0)return l;const o=k(e)&&!!e.initVal,a=V(o);let r=null;const s=n=>{if(I(n)){a.value=l.value;return}r&&clearTimeout(r),r=setTimeout(()=>{a.value=l.value},n)},c=n=>{n==="leading"?E(e)?s(e):s(e.leading):k(e)?s(e.trailing):a.value=!1};return C(()=>c("leading")),O(()=>l.value,n=>{c(n?"leading":"trailing")}),a},F=w({name:"ElSkeleton",__name:"skeleton",props:R,setup(l,{expose:e}){const o=l,a=h("skeleton"),r=D(j(o,"loading"),o.throttle);return e({uiLoading:r}),(s,c)=>t(r)?(i(),u("div",y({key:0,class:[t(a).b(),t(a).is("animated",s.animated)]},s.$attrs),[(i(!0),u(m,null,g(s.count,n=>(i(),u(m,{key:n},[t(r)?v(s.$slots,"template",{key:n},()=>[L(p,{class:d(t(a).is("first")),variant:"p"},null,8,["class"]),(i(!0),u(m,null,g(s.rows,f=>(i(),N(p,{key:f,class:d([t(a).e("paragraph"),t(a).is("last",f===s.rows&&s.rows>1)]),variant:"p"},null,8,["class"]))),128))]):S("v-if",!0)],64))),128))],16)):v(s.$slots,"default",z(y({key:1},s.$attrs)))}});var G=b(F,[["__file","/home/runner/work/element-plus/element-plus/packages/components/skeleton/src/skeleton.vue"]]);const M=T(G,{SkeletonItem:p}),W=$(p);export{M as E,W as a};
|