@launchframe/mcp 1.1.0 → 1.1.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/dist/tools/cli.js +46 -4
- package/package.json +1 -1
package/dist/tools/cli.js
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
|
+
/**
|
|
4
|
+
* Request human confirmation for a destructive action via MCP elicitation.
|
|
5
|
+
* Returns true if the user confirmed, false if declined/cancelled or if the
|
|
6
|
+
* client does not support elicitation (fails safe — aborts rather than proceeds).
|
|
7
|
+
*/
|
|
8
|
+
async function confirmDestructive(server, message) {
|
|
9
|
+
try {
|
|
10
|
+
const result = await server.server.elicitInput({
|
|
11
|
+
mode: 'form',
|
|
12
|
+
message,
|
|
13
|
+
requestedSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
confirmed: {
|
|
17
|
+
type: 'boolean',
|
|
18
|
+
title: 'Yes, proceed',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ['confirmed'],
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return result.action === 'accept' && result.content?.confirmed === true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Client does not support elicitation — fail safe
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
3
31
|
export function registerCliTools(server) {
|
|
4
32
|
// ─── docker:* ────────────────────────────────────────────────────────────
|
|
5
33
|
server.tool('cli_docker_up', 'Start Docker services for a LaunchFrame project. Always runs detached (background). Use cli_docker_logs to inspect output afterward.', {
|
|
@@ -54,10 +82,14 @@ export function registerCliTools(server) {
|
|
|
54
82
|
return { content: [{ type: 'text', text: error.message }] };
|
|
55
83
|
}
|
|
56
84
|
});
|
|
57
|
-
server.tool('cli_docker_destroy', 'Destroy ALL Docker resources for a LaunchFrame project (containers, volumes, images, network). IRREVERSIBLE — all local data will be lost.', {
|
|
85
|
+
server.tool('cli_docker_destroy', 'Destroy ALL Docker resources for a LaunchFrame project (containers, volumes, images, network). IRREVERSIBLE — all local data including database volumes will be lost. Will prompt for confirmation before proceeding.', {
|
|
58
86
|
projectPath: z.string().describe('Absolute path to the LaunchFrame project root'),
|
|
59
87
|
}, async ({ projectPath }) => {
|
|
60
88
|
try {
|
|
89
|
+
const confirmed = await confirmDestructive(server, '⚠️ This will permanently delete ALL Docker resources for this project: containers, volumes (including the local database), images, and the network. This cannot be undone. Proceed?');
|
|
90
|
+
if (!confirmed) {
|
|
91
|
+
return { content: [{ type: 'text', text: 'Aborted. No Docker resources were removed.' }] };
|
|
92
|
+
}
|
|
61
93
|
const output = execSync('launchframe docker:destroy --force', { cwd: projectPath, encoding: 'utf8' });
|
|
62
94
|
return { content: [{ type: 'text', text: output || 'All Docker resources destroyed.' }] };
|
|
63
95
|
}
|
|
@@ -100,12 +132,18 @@ export function registerCliTools(server) {
|
|
|
100
132
|
return { content: [{ type: 'text', text: error.message }] };
|
|
101
133
|
}
|
|
102
134
|
});
|
|
103
|
-
server.tool('cli_database_query', 'Execute a SQL query against the local (or remote) database and return results. Use for SELECT queries, schema inspection, or data checks.
|
|
135
|
+
server.tool('cli_database_query', 'Execute a SQL query against the local (or remote) database and return results. Use for SELECT queries, schema inspection, or data checks. When remote=true, will prompt for confirmation before touching production.', {
|
|
104
136
|
projectPath: z.string().describe('Absolute path to the LaunchFrame project root'),
|
|
105
137
|
sql: z.string().describe('SQL to execute (e.g., "SELECT * FROM users LIMIT 10;")'),
|
|
106
|
-
remote: z.boolean().optional().describe('If true, query the production database via SSH instead of local'),
|
|
138
|
+
remote: z.boolean().optional().describe('If true, query the production database via SSH instead of local. Requires confirmation.'),
|
|
107
139
|
}, async ({ projectPath, sql, remote }) => {
|
|
108
140
|
try {
|
|
141
|
+
if (remote) {
|
|
142
|
+
const confirmed = await confirmDestructive(server, `⚠️ This will execute SQL against the PRODUCTION database:\n\n${sql}\n\nProceed?`);
|
|
143
|
+
if (!confirmed) {
|
|
144
|
+
return { content: [{ type: 'text', text: 'Aborted. Query not executed on production.' }] };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
109
147
|
const remoteFlag = remote ? ' --remote' : '';
|
|
110
148
|
const output = execSync(`launchframe database:console${remoteFlag} --query ${JSON.stringify(sql)}`, { cwd: projectPath, encoding: 'utf8' });
|
|
111
149
|
return { content: [{ type: 'text', text: output || '(no output)' }] };
|
|
@@ -186,10 +224,14 @@ export function registerCliTools(server) {
|
|
|
186
224
|
return { content: [{ type: 'text', text: error.message }] };
|
|
187
225
|
}
|
|
188
226
|
});
|
|
189
|
-
server.tool('cli_deploy_sync_features', 'Sync subscription plan features from the local database to the production database.
|
|
227
|
+
server.tool('cli_deploy_sync_features', 'Sync subscription plan features from the local database to the production database. DESTRUCTIVE: truncates subscription_plan_features on production. Will prompt for confirmation before proceeding.', {
|
|
190
228
|
projectPath: z.string().describe('Absolute path to the LaunchFrame project root'),
|
|
191
229
|
}, async ({ projectPath }) => {
|
|
192
230
|
try {
|
|
231
|
+
const confirmed = await confirmDestructive(server, '⚠️ This will TRUNCATE subscription_plan_features on the PRODUCTION database and replace with local data. Proceed?');
|
|
232
|
+
if (!confirmed) {
|
|
233
|
+
return { content: [{ type: 'text', text: 'Aborted. No changes made to production.' }] };
|
|
234
|
+
}
|
|
193
235
|
const output = execSync('launchframe deploy:sync-features --yes', { cwd: projectPath, encoding: 'utf8' });
|
|
194
236
|
return { content: [{ type: 'text', text: output || 'Features synced to production.' }] };
|
|
195
237
|
}
|