@atlisp/mcp 1.8.12 → 1.8.14
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/dist/html/api-docs.html +66 -0
- package/dist/html/debug.html +75 -0
- package/dist/html/playground.html +347 -0
- package/package.json +2 -2
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>@lisp MCP Server API Docs</title>
|
|
5
|
+
<style>
|
|
6
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 900px; margin: 0 auto; padding: 20px; }
|
|
7
|
+
h1 { color: #333; }
|
|
8
|
+
h2 { color: #666; margin-top: 30px; }
|
|
9
|
+
.endpoint { background: #f5f5f5; padding: 15px; margin: 10px 0; border-radius: 5px; }
|
|
10
|
+
.method { display: inline-block; padding: 3px 8px; border-radius: 3px; font-weight: bold; font-size: 12px; }
|
|
11
|
+
.get { background: #61affe; color: white; }
|
|
12
|
+
.post { background: #49cc90; color: white; }
|
|
13
|
+
code { background: #eee; padding: 2px 5px; border-radius: 3px; }
|
|
14
|
+
.info { background: #f0f0f0; padding: 10px; margin: 10px 0; }
|
|
15
|
+
</style>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<h1>@lisp MCP Server API</h1>
|
|
19
|
+
<div class="info">
|
|
20
|
+
<strong>Version:</strong> __VERSION__ |
|
|
21
|
+
<strong>Tools:</strong> __TOOLS_COUNT__ |
|
|
22
|
+
<strong>Resources:</strong> 11
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<h2>Endpoints</h2>
|
|
26
|
+
|
|
27
|
+
<div class="endpoint">
|
|
28
|
+
<span class="method get">GET</span> <code>/health</code> - Health check
|
|
29
|
+
</div>
|
|
30
|
+
<div class="endpoint">
|
|
31
|
+
<span class="method get">GET</span> <code>/metrics</code> - Prometheus metrics
|
|
32
|
+
</div>
|
|
33
|
+
<div class="endpoint">
|
|
34
|
+
<span class="method post">POST</span> <code>/mcp</code> - MCP JSON-RPC endpoint
|
|
35
|
+
</div>
|
|
36
|
+
<div class="endpoint">
|
|
37
|
+
<span class="method get">GET</span> <code>/sse</code> - Server-Sent Events
|
|
38
|
+
</div>
|
|
39
|
+
<div class="endpoint">
|
|
40
|
+
<span class="method post">POST</span> <code>/message</code> - SSE message
|
|
41
|
+
</div>
|
|
42
|
+
<div class="endpoint">
|
|
43
|
+
<span class="method get">GET</span> <code>/debug</code> - Debug panel
|
|
44
|
+
</div>
|
|
45
|
+
<div class="endpoint">
|
|
46
|
+
<span class="method post">POST</span> <code>/config/reload</code> - Reload configuration
|
|
47
|
+
</div>
|
|
48
|
+
<div class="endpoint">
|
|
49
|
+
<span class="method get">GET</span> <code>/rate-limit/status</code> - Rate limit status
|
|
50
|
+
</div>
|
|
51
|
+
<div class="endpoint">
|
|
52
|
+
<span class="method post">POST</span> <code>/rate-limit/reset</code> - Reset rate limit
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<h2>Quick Start</h2>
|
|
56
|
+
<pre>
|
|
57
|
+
# Health check
|
|
58
|
+
curl http://localhost:8110/health
|
|
59
|
+
|
|
60
|
+
# Call MCP tool
|
|
61
|
+
curl -X POST http://localhost:8110/mcp \
|
|
62
|
+
-H "Content-Type: application/json" \
|
|
63
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_cad_info","arguments":{}}}'
|
|
64
|
+
</pre>
|
|
65
|
+
</body>
|
|
66
|
+
</html>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>@lisp MCP Debug Panel</title>
|
|
5
|
+
<style>
|
|
6
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #1a1a2e; color: #eee; }
|
|
7
|
+
h1 { color: #00d4ff; }
|
|
8
|
+
h2 { color: #00d4ff; border-bottom: 1px solid #333; padding-bottom: 10px; }
|
|
9
|
+
.card { background: #16213e; padding: 20px; margin: 10px 0; border-radius: 8px; }
|
|
10
|
+
.stat { display: inline-block; margin: 10px 20px; }
|
|
11
|
+
.stat-label { color: #888; font-size: 12px; }
|
|
12
|
+
.stat-value { font-size: 24px; color: #00d4ff; }
|
|
13
|
+
.status-ok { color: #49cc90; }
|
|
14
|
+
.status-error { color: #f93e3e; }
|
|
15
|
+
table { width: 100%; border-collapse: collapse; }
|
|
16
|
+
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #333; }
|
|
17
|
+
th { color: #888; }
|
|
18
|
+
code { background: #0f0f23; padding: 3px 8px; border-radius: 3px; color: #00d4ff; }
|
|
19
|
+
.refresh { background: #00d4ff; color: #1a1a2e; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; margin: 10px 0; }
|
|
20
|
+
</style>
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<h1>🛠️ @lisp MCP Debug Panel</h1>
|
|
24
|
+
<button class="refresh" onclick="location.reload()">🔄 Refresh</button>
|
|
25
|
+
|
|
26
|
+
<h2>System</h2>
|
|
27
|
+
<div class="card">
|
|
28
|
+
<div class="stat">
|
|
29
|
+
<div class="stat-label">Uptime</div>
|
|
30
|
+
<div class="stat-value">__UPTIME_MIN__m</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="stat">
|
|
33
|
+
<div class="stat-label">Memory RSS</div>
|
|
34
|
+
<div class="stat-value">__MEMORY_RSS_MB__ MB</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="stat">
|
|
37
|
+
<div class="stat-label">Heap Used</div>
|
|
38
|
+
<div class="stat-value">__HEAP_USED_MB__ MB</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="stat">
|
|
41
|
+
<div class="stat-label">MCP Sessions</div>
|
|
42
|
+
<div class="stat-value">__SESSIONS_COUNT__</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<h2>CAD Status</h2>
|
|
47
|
+
<div class="card">
|
|
48
|
+
<span class="__CAD_STATUS_CLASS__">
|
|
49
|
+
__CAD_STATUS_TEXT__
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<h2>Endpoints</h2>
|
|
54
|
+
<div class="card">
|
|
55
|
+
<table>
|
|
56
|
+
<tr><th>Endpoint</th><th>Method</th><th>Description</th></tr>
|
|
57
|
+
<tr><td><code>/health</code></td><td>GET</td><td>Health check</td></tr>
|
|
58
|
+
<tr><td><code>/metrics</code></td><td>GET</td><td>Prometheus metrics</td></tr>
|
|
59
|
+
<tr><td><code>/mcp</code></td><td>POST</td><td>MCP JSON-RPC</td></tr>
|
|
60
|
+
<tr><td><code>/sse</code></td><td>GET</td><td>Server-Sent Events</td></tr>
|
|
61
|
+
<tr><td><code>/debug</code></td><td>GET</td><td>This panel</td></tr>
|
|
62
|
+
<tr><td><code>/api/docs</code></td><td>GET</td><td>API Documentation</td></tr>
|
|
63
|
+
</table>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<h2>Tools (__TOOLS_COUNT__)</h2>
|
|
67
|
+
<div class="card">
|
|
68
|
+
<p>Use <code>tools/list</code> MCP method to get full tool list.</p>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<script>
|
|
72
|
+
setTimeout(() => location.reload(), 30000);
|
|
73
|
+
</script>
|
|
74
|
+
</body>
|
|
75
|
+
</html>
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>@lisp MCP Tool Playground</title>
|
|
5
|
+
<style>
|
|
6
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
7
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #eee; padding: 20px; }
|
|
8
|
+
h1 { color: #00d4ff; margin-bottom: 20px; font-size: 24px; }
|
|
9
|
+
.header { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; margin-bottom: 20px; }
|
|
10
|
+
.search-box { flex: 1; min-width: 200px; background: #16213e; border: 1px solid #333; color: #eee; padding: 10px 14px; border-radius: 6px; font-size: 14px; outline: none; }
|
|
11
|
+
.search-box:focus { border-color: #00d4ff; }
|
|
12
|
+
.category-filter { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 20px; }
|
|
13
|
+
.cat-btn { background: #16213e; border: 1px solid #333; color: #888; padding: 6px 14px; border-radius: 16px; cursor: pointer; font-size: 13px; transition: all .15s; }
|
|
14
|
+
.cat-btn:hover { border-color: #00d4ff; color: #eee; }
|
|
15
|
+
.cat-btn.active { background: #00d4ff; color: #1a1a2e; border-color: #00d4ff; }
|
|
16
|
+
.tool-count { color: #888; font-size: 13px; margin-bottom: 12px; }
|
|
17
|
+
.category-group { margin-bottom: 24px; }
|
|
18
|
+
.category-title { color: #00d4ff; font-size: 16px; font-weight: 600; padding: 10px 0 8px; border-bottom: 1px solid #333; margin-bottom: 8px; cursor: pointer; display: flex; align-items: center; gap: 8px; }
|
|
19
|
+
.category-title .arrow { color: #555; transition: transform .15s; font-size: 12px; }
|
|
20
|
+
.category-title.collapsed .arrow { transform: rotate(-90deg); }
|
|
21
|
+
.category-title .count { color: #888; font-size: 12px; font-weight: 400; }
|
|
22
|
+
.tool-card { background: #16213e; border: 1px solid #333; border-radius: 6px; padding: 12px 16px; margin-bottom: 6px; cursor: pointer; transition: border-color .15s; }
|
|
23
|
+
.tool-card:hover { border-color: #00d4ff44; }
|
|
24
|
+
.tool-card.expanded { border-color: #00d4ff; }
|
|
25
|
+
.tool-name { color: #49cc90; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; font-size: 14px; }
|
|
26
|
+
.tool-desc { color: #999; font-size: 13px; margin-top: 4px; line-height: 1.4; }
|
|
27
|
+
.tool-meta { display: flex; gap: 12px; margin-top: 6px; font-size: 12px; color: #666; }
|
|
28
|
+
.tool-meta span { background: #0f0f23; padding: 2px 8px; border-radius: 3px; }
|
|
29
|
+
.tool-details { display: none; margin-top: 12px; padding-top: 12px; border-top: 1px solid #333; }
|
|
30
|
+
.tool-card.expanded .tool-details { display: block; }
|
|
31
|
+
.params-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-bottom: 12px; }
|
|
32
|
+
.params-table th { color: #888; text-align: left; padding: 6px 8px; border-bottom: 1px solid #333; font-weight: 500; }
|
|
33
|
+
.params-table td { padding: 6px 8px; border-bottom: 1px solid #222; color: #ccc; }
|
|
34
|
+
.params-table .required { color: #f93e3e; margin-left: 4px; }
|
|
35
|
+
.param-input { width: 100%; background: #0f0f23; border: 1px solid #333; color: #eee; padding: 6px 10px; border-radius: 4px; font-size: 13px; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; }
|
|
36
|
+
.param-input:focus { border-color: #00d4ff; outline: none; }
|
|
37
|
+
.param-input.array-input { min-height: 60px; resize: vertical; }
|
|
38
|
+
.btn { background: #00d4ff; color: #1a1a2e; border: none; padding: 8px 18px; border-radius: 5px; cursor: pointer; font-size: 13px; font-weight: 600; transition: opacity .15s; }
|
|
39
|
+
.btn:hover { opacity: .85; }
|
|
40
|
+
.btn:disabled { opacity: .4; cursor: not-allowed; }
|
|
41
|
+
.btn.execute { background: #49cc90; }
|
|
42
|
+
.btn.execute.running { background: #888; }
|
|
43
|
+
.response-area { display: none; margin-top: 12px; }
|
|
44
|
+
.response-area.visible { display: block; }
|
|
45
|
+
.response-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
|
|
46
|
+
.response-header label { color: #888; font-size: 12px; font-weight: 500; }
|
|
47
|
+
.response-status { font-size: 12px; padding: 2px 8px; border-radius: 3px; }
|
|
48
|
+
.response-status.ok { background: #49cc9033; color: #49cc90; }
|
|
49
|
+
.response-status.err { background: #f93e3e33; color: #f93e3e; }
|
|
50
|
+
.response-json { background: #0f0f23; border: 1px solid #333; border-radius: 4px; padding: 12px; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; font-size: 12px; color: #00d4ff; white-space: pre-wrap; word-break: break-all; max-height: 400px; overflow: auto; }
|
|
51
|
+
.no-results { color: #666; text-align: center; padding: 40px; font-size: 14px; }
|
|
52
|
+
.toolbar { display: flex; gap: 8px; align-items: center; }
|
|
53
|
+
.expand-all-btn { background: none; border: 1px solid #333; color: #888; padding: 6px 14px; border-radius: 5px; cursor: pointer; font-size: 12px; }
|
|
54
|
+
.expand-all-btn:hover { border-color: #00d4ff44; color: #eee; }
|
|
55
|
+
.scroll-top { position: fixed; bottom: 20px; right: 20px; width: 40px; height: 40px; background: #16213e; border: 1px solid #333; border-radius: 50%; color: #00d4ff; font-size: 18px; cursor: pointer; display: none; align-items: center; justify-content: center; }
|
|
56
|
+
.scroll-top.visible { display: flex; }
|
|
57
|
+
.scroll-top:hover { border-color: #00d4ff; }
|
|
58
|
+
::-webkit-scrollbar { width: 6px; }
|
|
59
|
+
::-webkit-scrollbar-track { background: #0f0f23; }
|
|
60
|
+
::-webkit-scrollbar-thumb { background: #333; border-radius: 3px; }
|
|
61
|
+
::-webkit-scrollbar-thumb:hover { background: #555; }
|
|
62
|
+
@media (max-width: 600px) {
|
|
63
|
+
body { padding: 10px; }
|
|
64
|
+
.header { flex-direction: column; }
|
|
65
|
+
.search-box { width: 100%; }
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
68
|
+
</head>
|
|
69
|
+
<body>
|
|
70
|
+
<h1>🧰 @lisp MCP Tool Playground</h1>
|
|
71
|
+
<div class="header">
|
|
72
|
+
<input class="search-box" id="search" placeholder="Search tools by name or description..." oninput="filterTools()">
|
|
73
|
+
<div class="toolbar">
|
|
74
|
+
<button class="expand-all-btn" onclick="expandAll()">Expand All</button>
|
|
75
|
+
<button class="expand-all-btn" onclick="collapseAll()">Collapse All</button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="category-filter" id="categoryFilter"></div>
|
|
79
|
+
<div class="tool-count" id="toolCount"></div>
|
|
80
|
+
<div id="toolList"></div>
|
|
81
|
+
<button class="scroll-top" id="scrollTop" onclick="window.scrollTo({top:0,behavior:'smooth'})">↑</button>
|
|
82
|
+
|
|
83
|
+
<script>
|
|
84
|
+
var TOOLS = __TOOLS_JSON__;
|
|
85
|
+
var activeCategory = null;
|
|
86
|
+
var searchQuery = '';
|
|
87
|
+
|
|
88
|
+
function categorize(name) {
|
|
89
|
+
if (/^batch_/.test(name)) return 'Batch';
|
|
90
|
+
if (/^boolean_/.test(name)) return 'Boolean';
|
|
91
|
+
if (/^(create_3d_|create_box|create_cone|create_cylinder|create_sphere|create_torus|create_wedge|extrude_|revolve_|slice_|thicken_|offset_surface|create_loft_|get_3d_)/.test(name)) return '3D';
|
|
92
|
+
if (/xdata/i.test(name)) return 'Xdata';
|
|
93
|
+
if (/sheet/i.test(name)) return 'Sheet Set';
|
|
94
|
+
if (/pdf/i.test(name)) return 'PDF';
|
|
95
|
+
if (/^(xref|dgn|dwf)/i.test(name)) return 'Xref';
|
|
96
|
+
if (/constraint/i.test(name)) return 'Constraint';
|
|
97
|
+
if (/parametric/i.test(name)) return 'Parametric';
|
|
98
|
+
if (/pipeline/i.test(name)) return 'Pipeline';
|
|
99
|
+
if (/trigger/i.test(name)) return 'Trigger';
|
|
100
|
+
if (/repl/i.test(name)) return 'REPL';
|
|
101
|
+
if (/^(plot_|publish_|save_pdf_layout)/.test(name)) return 'Plot';
|
|
102
|
+
if (/^(connect_cad|eval_lisp|install_|init_|get_cad_info|get_platform_info|at_command|new_document|bring_to_front|get_system_status)/.test(name)) return 'System';
|
|
103
|
+
if (/^(list_|search_|measure_|import_funlib)/.test(name)) return 'Query';
|
|
104
|
+
if (/^(import_|export_)/.test(name)) return 'Import/Export';
|
|
105
|
+
if (/^(create_layer|delete_layer|set_layer|set_current_layer)/.test(name)) return 'Layer';
|
|
106
|
+
if (/^(create_block|insert_block|explode_block|get_block|set_block)/.test(name)) return 'Block';
|
|
107
|
+
if (/^(create_dim|list_dim|set_dim|create_hatch|set_hatch)/.test(name)) return 'Dimension & Hatch';
|
|
108
|
+
if (/^(create_ucs|set_ucs|delete_ucs|list_ucs|get_current_ucs|create_layout|delete_layout|rename_layout|set_layout|list_layouts|get_current_layout|create_named_view|list_named_views|restore_named_view)/.test(name)) return 'UCS & Layout';
|
|
109
|
+
if (/^(open_dwg|save_dwg|close_dwg)/.test(name)) return 'Drawing';
|
|
110
|
+
if (/^(create_text|list_text|create_mleader|list_mleader|set_mleader|create_linetype|list_linetypes|load_linetype)/.test(name)) return 'Style';
|
|
111
|
+
if (/^(attach_|detach_)/.test(name)) return 'Underlay';
|
|
112
|
+
if (/^(create_group|delete_group|list_groups|get_group)/.test(name)) return 'Group';
|
|
113
|
+
if (/^(create_entity|delete_entity|get_entity|set_entity|select_entities)/.test(name)) return 'Entity';
|
|
114
|
+
return 'Other';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getCategories() {
|
|
118
|
+
var cats = {};
|
|
119
|
+
TOOLS.forEach(function(t) {
|
|
120
|
+
var c = categorize(t.name);
|
|
121
|
+
if (!cats[c]) cats[c] = [];
|
|
122
|
+
cats[c].push(t);
|
|
123
|
+
});
|
|
124
|
+
var order = ['System','Query','Entity','Layer','Block','Drawing','Dimension & Hatch','UCS & Layout','3D','Batch','Boolean','Group','Style','Xdata','Sheet Set','PDF','Xref','Underlay','Import/Export','Constraint','Parametric','Plot','Pipeline','Trigger','REPL','Other'];
|
|
125
|
+
var sorted = {};
|
|
126
|
+
order.forEach(function(c) { if (cats[c]) sorted[c] = cats[c]; });
|
|
127
|
+
Object.keys(cats).filter(function(c) { return !order.includes(c); }).forEach(function(c) { sorted[c] = cats[c]; });
|
|
128
|
+
return sorted;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function escapeHtml(s) {
|
|
132
|
+
var d = document.createElement('div');
|
|
133
|
+
d.textContent = s;
|
|
134
|
+
return d.innerHTML;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function buildForm(inputSchema) {
|
|
138
|
+
var props = inputSchema.properties || {};
|
|
139
|
+
var required = inputSchema.required || [];
|
|
140
|
+
var keys = Object.keys(props);
|
|
141
|
+
if (keys.length === 0) return '<p style="color:#666;font-size:13px;padding:6px 0">No parameters required.</p>';
|
|
142
|
+
var html = '<table class="params-table"><tr><th>Parameter</th><th>Type</th><th>Description</th><th>Value</th></tr>';
|
|
143
|
+
keys.forEach(function(k) {
|
|
144
|
+
var p = props[k];
|
|
145
|
+
var isReq = required.includes(k);
|
|
146
|
+
var typeLabel = p.type || 'string';
|
|
147
|
+
var inputHtml = '';
|
|
148
|
+
if (p.enum) {
|
|
149
|
+
inputHtml = '<select class="param-input" data-param="' + k + '" data-type="string"><option value="">-- select --</option>';
|
|
150
|
+
p.enum.forEach(function(v) {
|
|
151
|
+
inputHtml += '<option value="' + escapeHtml(v) + '">' + escapeHtml(v) + '</option>';
|
|
152
|
+
});
|
|
153
|
+
inputHtml += '</select>';
|
|
154
|
+
} else if (p.type === 'boolean') {
|
|
155
|
+
inputHtml = '<select class="param-input" data-param="' + k + '" data-type="boolean"><option value="">-- select --</option><option value="true">true</option><option value="false">false</option></select>';
|
|
156
|
+
} else if (p.type === 'integer' || p.type === 'number') {
|
|
157
|
+
inputHtml = '<input class="param-input" data-param="' + k + '" data-type="' + p.type + '" placeholder="' + typeLabel + '" step="any">';
|
|
158
|
+
} else if (p.type === 'array' || (p.type === 'object' && !p.properties)) {
|
|
159
|
+
inputHtml = '<textarea class="param-input array-input" data-param="' + k + '" data-type="json" placeholder=\'JSON array/object, e.g. ["a","b"] or {"key":"val"}\' rows="2"></textarea>';
|
|
160
|
+
} else if (p.type === 'object' && p.properties) {
|
|
161
|
+
inputHtml = '<textarea class="param-input array-input" data-param="' + k + '" data-type="json" placeholder=\'JSON object\' rows="2"></textarea>';
|
|
162
|
+
} else {
|
|
163
|
+
inputHtml = '<input class="param-input" data-param="' + k + '" data-type="string" placeholder="' + escapeHtml(p.description || '') + '">';
|
|
164
|
+
}
|
|
165
|
+
html += '<tr><td><code>' + escapeHtml(k) + '</code>' + (isReq ? '<span class="required">*</span>' : '') + '</td><td style="color:#888">' + typeLabel + '</td><td>' + escapeHtml(p.description || '-') + '</td><td>' + inputHtml + '</td></tr>';
|
|
166
|
+
});
|
|
167
|
+
html += '</table>';
|
|
168
|
+
return html;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function collectParams(card) {
|
|
172
|
+
var params = {};
|
|
173
|
+
card.querySelectorAll('.param-input').forEach(function(el) {
|
|
174
|
+
var key = el.dataset.param;
|
|
175
|
+
var val = el.value.trim();
|
|
176
|
+
if (val === '') return;
|
|
177
|
+
var type = el.dataset.type;
|
|
178
|
+
if (type === 'number' || type === 'integer') val = Number(val);
|
|
179
|
+
else if (type === 'boolean') val = val === 'true';
|
|
180
|
+
else if (type === 'json') { try { val = JSON.parse(val); } catch(e) { return; } }
|
|
181
|
+
params[key] = val;
|
|
182
|
+
});
|
|
183
|
+
return params;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function renderTools() {
|
|
187
|
+
var categories = getCategories();
|
|
188
|
+
var container = document.getElementById('toolList');
|
|
189
|
+
var filterEl = document.getElementById('categoryFilter');
|
|
190
|
+
container.innerHTML = '';
|
|
191
|
+
filterEl.innerHTML = '<button class="cat-btn active" data-cat="" onclick="setCategory(this,\'\')">All</button>';
|
|
192
|
+
|
|
193
|
+
var totalCount = 0;
|
|
194
|
+
var catKeys = Object.keys(categories);
|
|
195
|
+
catKeys.forEach(function(c) {
|
|
196
|
+
var count = categories[c].length;
|
|
197
|
+
if (activeCategory && activeCategory !== c) count = 0;
|
|
198
|
+
else if (searchQuery) {
|
|
199
|
+
var q = searchQuery.toLowerCase();
|
|
200
|
+
count = categories[c].filter(function(t) { return t.name.toLowerCase().includes(q) || (t.description && t.description.toLowerCase().includes(q)); }).length;
|
|
201
|
+
}
|
|
202
|
+
totalCount += count;
|
|
203
|
+
filterEl.innerHTML += '<button class="cat-btn' + (activeCategory === c ? ' active' : '') + '" data-cat="' + c + '" onclick="setCategory(this,\'' + c + '\')">' + c + '</button>';
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
var countText = totalCount + ' tool' + (totalCount !== 1 ? 's' : '');
|
|
207
|
+
if (searchQuery) countText += ' matching "' + searchQuery + '"';
|
|
208
|
+
document.getElementById('toolCount').textContent = countText;
|
|
209
|
+
|
|
210
|
+
var hasResults = false;
|
|
211
|
+
catKeys.forEach(function(c) {
|
|
212
|
+
var tools = categories[c];
|
|
213
|
+
if (searchQuery) {
|
|
214
|
+
var q = searchQuery.toLowerCase();
|
|
215
|
+
tools = tools.filter(function(t) { return t.name.toLowerCase().includes(q) || (t.description && t.description.toLowerCase().includes(q)); });
|
|
216
|
+
}
|
|
217
|
+
if (activeCategory && activeCategory !== c) tools = [];
|
|
218
|
+
if (tools.length === 0) return;
|
|
219
|
+
hasResults = true;
|
|
220
|
+
|
|
221
|
+
var groupHtml = '<div class="category-group"><div class="category-title collapsed" onclick="toggleCategory(this)"><span class="arrow">▼</span> ' + c + ' <span class="count">(' + tools.length + ')</span></div>';
|
|
222
|
+
tools.forEach(function(t) {
|
|
223
|
+
var hasParams = t.inputSchema && t.inputSchema.properties && Object.keys(t.inputSchema.properties).length > 0;
|
|
224
|
+
var paramsCount = hasParams ? Object.keys(t.inputSchema.properties).length + ' params' : 'no params';
|
|
225
|
+
var reqCount = (t.inputSchema.required && t.inputSchema.required.length) ? '<span>' + t.inputSchema.required.length + ' required</span>' : '';
|
|
226
|
+
groupHtml += '<div class="tool-card" id="tool-' + t.name + '" onclick="toggleCard(this)">';
|
|
227
|
+
groupHtml += '<div class="tool-name">' + escapeHtml(t.name) + '</div>';
|
|
228
|
+
groupHtml += '<div class="tool-desc">' + escapeHtml(t.description || '') + '</div>';
|
|
229
|
+
groupHtml += '<div class="tool-meta"><span>' + paramsCount + '</span>' + reqCount + '</div>';
|
|
230
|
+
groupHtml += '<div class="tool-details">';
|
|
231
|
+
if (hasParams) {
|
|
232
|
+
groupHtml += buildForm(t.inputSchema);
|
|
233
|
+
} else {
|
|
234
|
+
groupHtml += '<p style="color:#666;font-size:13px;padding:6px 0">No parameters required.</p>';
|
|
235
|
+
}
|
|
236
|
+
groupHtml += '<button class="btn execute" onclick="event.stopPropagation();executeTool(this,\'' + t.name + '\')">▶ Execute</button>';
|
|
237
|
+
groupHtml += '<div class="response-area" id="response-' + t.name + '">';
|
|
238
|
+
groupHtml += '<div class="response-header"><label>Response</label><span class="response-status" id="status-' + t.name + '"></span></div>';
|
|
239
|
+
groupHtml += '<div class="response-json" id="result-' + t.name + '"></div>';
|
|
240
|
+
groupHtml += '</div></div></div>';
|
|
241
|
+
});
|
|
242
|
+
groupHtml += '</div>';
|
|
243
|
+
container.innerHTML += groupHtml;
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
if (!hasResults) {
|
|
247
|
+
container.innerHTML = '<div class="no-results">No tools found matching your search.</div>';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (searchQuery) {
|
|
251
|
+
container.querySelectorAll('.category-group').forEach(function(g) {
|
|
252
|
+
var visibleCards = g.querySelectorAll('.tool-card');
|
|
253
|
+
if (visibleCards.length <= 3) {
|
|
254
|
+
var title = g.querySelector('.category-title');
|
|
255
|
+
if (title) title.classList.remove('collapsed');
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function toggleCategory(el) {
|
|
262
|
+
el.classList.toggle('collapsed');
|
|
263
|
+
var group = el.parentElement;
|
|
264
|
+
var cards = group.querySelectorAll('.tool-card');
|
|
265
|
+
cards.forEach(function(c) { c.style.display = el.classList.contains('collapsed') ? 'none' : ''; });
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function toggleCard(el) {
|
|
269
|
+
if (event && (event.target.closest('.param-input') || event.target.closest('.btn') || event.target.closest('.response-area'))) return;
|
|
270
|
+
el.classList.toggle('expanded');
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async function executeTool(btn, toolName) {
|
|
274
|
+
if (btn.disabled) return;
|
|
275
|
+
var card = btn.closest('.tool-card');
|
|
276
|
+
var responseArea = document.getElementById('response-' + toolName);
|
|
277
|
+
var statusEl = document.getElementById('status-' + toolName);
|
|
278
|
+
var resultEl = document.getElementById('result-' + toolName);
|
|
279
|
+
|
|
280
|
+
btn.disabled = true;
|
|
281
|
+
btn.textContent = '⏳ Running...';
|
|
282
|
+
btn.classList.add('running');
|
|
283
|
+
responseArea.classList.remove('visible');
|
|
284
|
+
statusEl.textContent = '';
|
|
285
|
+
statusEl.className = 'response-status';
|
|
286
|
+
resultEl.textContent = '';
|
|
287
|
+
|
|
288
|
+
var arguments = collectParams(card);
|
|
289
|
+
var body = { jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: toolName, arguments: arguments } };
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
var res = await fetch('/mcp', {
|
|
293
|
+
method: 'POST',
|
|
294
|
+
headers: { 'Content-Type': 'application/json' },
|
|
295
|
+
body: JSON.stringify(body)
|
|
296
|
+
});
|
|
297
|
+
var data = await res.json();
|
|
298
|
+
responseArea.classList.add('visible');
|
|
299
|
+
if (res.ok) {
|
|
300
|
+
statusEl.textContent = res.status + ' OK';
|
|
301
|
+
statusEl.className = 'response-status ok';
|
|
302
|
+
} else {
|
|
303
|
+
statusEl.textContent = res.status + ' Error';
|
|
304
|
+
statusEl.className = 'response-status err';
|
|
305
|
+
}
|
|
306
|
+
resultEl.textContent = JSON.stringify(data, null, 2);
|
|
307
|
+
} catch (err) {
|
|
308
|
+
responseArea.classList.add('visible');
|
|
309
|
+
statusEl.textContent = 'Network Error';
|
|
310
|
+
statusEl.className = 'response-status err';
|
|
311
|
+
resultEl.textContent = err.message;
|
|
312
|
+
} finally {
|
|
313
|
+
btn.disabled = false;
|
|
314
|
+
btn.textContent = '▶ Execute';
|
|
315
|
+
btn.classList.remove('running');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function setCategory(el, cat) {
|
|
320
|
+
document.querySelectorAll('.cat-btn').forEach(function(b) { b.classList.remove('active'); });
|
|
321
|
+
el.classList.add('active');
|
|
322
|
+
activeCategory = cat || null;
|
|
323
|
+
renderTools();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function filterTools() {
|
|
327
|
+
searchQuery = document.getElementById('search').value;
|
|
328
|
+
renderTools();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function expandAll() {
|
|
332
|
+
document.querySelectorAll('.category-title').forEach(function(t) { t.classList.remove('collapsed'); });
|
|
333
|
+
document.querySelectorAll('.tool-card').forEach(function(c) { c.style.display = ''; });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function collapseAll() {
|
|
337
|
+
document.querySelectorAll('.category-title').forEach(function(t) { t.classList.add('collapsed'); });
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
window.addEventListener('scroll', function() {
|
|
341
|
+
document.getElementById('scrollTop').classList.toggle('visible', window.scrollY > 400);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
renderTools();
|
|
345
|
+
</script>
|
|
346
|
+
</body>
|
|
347
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlisp/mcp",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.14",
|
|
4
4
|
"description": "MCP Server for @lisp on CAD,support AutoCAD/GstarCAD/ZWCAD/BricsCAD or CAD platform compatible with AutoLISP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"start": "node src/atlisp-mcp.js",
|
|
19
19
|
"build": "npm run build:main && npm run build:worker",
|
|
20
20
|
"build:main": "esbuild src/atlisp-mcp.js --bundle --platform=node --target=node18 --format=esm --outdir=dist --external:edge-js --packages=external --banner:js=\"#!/usr/bin/env node\"",
|
|
21
|
-
"build:worker": "node -e \"const fs=require('fs');for(const f of ['cad-worker.js','lisp-security.js','logger.js','config.js'])fs.copyFileSync('src/'+f,'dist/'+f)\"",
|
|
21
|
+
"build:worker": "node -e \"const fs=require('fs');const path=require('path');for(const f of ['cad-worker.js','lisp-security.js','logger.js','config.js'])fs.copyFileSync('src/'+f,'dist/'+f);if(!fs.existsSync('dist/html'))fs.mkdirSync('dist/html');for(const f of fs.readdirSync('src/html'))fs.copyFileSync('src/html/'+f,'dist/html/'+f)\"",
|
|
22
22
|
"prepublishOnly": "npm run build",
|
|
23
23
|
"test": "vitest run",
|
|
24
24
|
"test:watch": "vitest"
|