magic-builder 1.3.1 → 1.3.3

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/README.md CHANGED
@@ -103,6 +103,17 @@ Deploy a FaaS function:
103
103
  magic-builder faas publish handler.js --name report-api
104
104
  ```
105
105
 
106
+ Publish a Tools-only MCP service (ordinary HTTP `handler` may coexist):
107
+
108
+ ```bash
109
+ magic-builder faas publish server.js --name weather-mcp --mcp --auth key,oauth --oauth-policy all
110
+ magic-builder faas mcp key create --id <id> --name production
111
+ magic-builder faas mcp key list --id <id>
112
+ magic-builder faas mcp key revoke --id <id> --key-id <key_id>
113
+ magic-builder faas mcp auth get --id <id>
114
+ magic-builder faas mcp auth update --id <id> --oauth-policy whitelist --oauth-user ou_xxx
115
+ ```
116
+
106
117
  List or delete FaaS functions:
107
118
 
108
119
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magic-builder",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "CLI for Magic Builder — publish pages, functions, files, and performance reviews",
5
5
  "bin": {
6
6
  "magic-builder": "bin/magic-builder.js",
@@ -29,6 +29,7 @@ async function login(opts) {
29
29
  const requestId = String(data.request_id || '');
30
30
  const pollToken = String(data.poll_token || '');
31
31
  const authUrl = String(data.auth_url || '');
32
+ const pollUrl = String(data.poll_url || '').trim() || `${baseUrl}/api/dev-token/auth/token`;
32
33
  if (!requestId || !pollToken || !authUrl) {
33
34
  fail(`Invalid auth start response: ${JSON.stringify(start)}`, 'E_AUTH_FAILED', 2);
34
35
  }
@@ -45,7 +46,7 @@ async function login(opts) {
45
46
 
46
47
  const deadline = Date.now() + timeoutSeconds * 1000;
47
48
  while (Date.now() < deadline) {
48
- const tokenJson = await request(`${baseUrl}/api/dev-token/auth/token`, {
49
+ const tokenJson = await request(pollUrl, {
49
50
  method: 'POST',
50
51
  body: {
51
52
  request_id: requestId,
@@ -12,7 +12,8 @@ async function run(args, opts) {
12
12
  if (sub === 'publish') return publish(args.slice(1), opts);
13
13
  if (sub === 'list') return list(opts);
14
14
  if (sub === 'delete') return deleteFaas(opts);
15
- fail('Usage: magic-builder faas <publish|list|delete>', 'E_INVALID_ARGS');
15
+ if (sub === 'mcp') return mcp(args.slice(1), opts);
16
+ fail('Usage: magic-builder faas <publish|list|delete|mcp>', 'E_INVALID_ARGS');
16
17
  }
17
18
 
18
19
  async function publish(args, opts) {
@@ -36,6 +37,15 @@ async function publish(args, opts) {
36
37
 
37
38
  const body = { code, name };
38
39
  if (opts.id) body.id = opts.id;
40
+ if (opts.mcp) {
41
+ body.mcp = true;
42
+ body.auth = String(opts.auth || 'key').split(',').map((item) => item.trim()).filter(Boolean);
43
+ if (opts.oauthUser !== undefined) {
44
+ body.oauth_users = String(opts.oauthUser || '').split(',').map((item) => item.trim()).filter(Boolean);
45
+ }
46
+ if (opts.oauthPolicy !== undefined) body.oauth_policy = String(opts.oauthPolicy).trim().toLowerCase();
47
+ else if (body.oauth_users?.length) body.oauth_policy = 'whitelist';
48
+ }
39
49
 
40
50
  if (!opts.quiet) process.stderr.write(`Deploying FaaS${opts.name ? ` "${opts.name}"` : ''}... `);
41
51
 
@@ -53,6 +63,7 @@ async function publish(args, opts) {
53
63
  const data = res.data || res;
54
64
  const id = data.id || data.record_id;
55
65
  const faasUrl = data.faas_url || `/api/faas/${id}`;
66
+ const mcpUrl = data.mcp_url || `/api/faas/${id}/mcp`;
56
67
 
57
68
  if (!opts.quiet) process.stderr.write('done\n');
58
69
 
@@ -63,9 +74,63 @@ async function publish(args, opts) {
63
74
  faas_url: `${baseUrl}${faasUrl}`,
64
75
  preview_url: `${baseUrl}/r?fid=${id}`,
65
76
  wss_url: `${wsBaseUrl}${faasUrl}`,
77
+ ...(opts.mcp ? { mcp_url: `${baseUrl}${mcpUrl}`, mcp_auth: data.mcp_auth || body.auth } : {}),
66
78
  }, opts);
67
79
  }
68
80
 
81
+ async function mcp(args, opts) {
82
+ const area = args[0];
83
+ const action = args[1];
84
+ if (area === 'key' && action === 'create') return mcpKeyCreate(opts);
85
+ if (area === 'key' && action === 'list') return mcpKeyList(opts);
86
+ if (area === 'key' && action === 'revoke') return mcpKeyRevoke(opts);
87
+ if (area === 'auth' && action === 'get') return mcpAuthGet(opts);
88
+ if (area === 'auth' && action === 'update') return mcpAuthUpdate(opts);
89
+ fail('Usage: magic-builder faas mcp <key create|key list|key revoke|auth get|auth update>', 'E_INVALID_ARGS');
90
+ }
91
+
92
+ async function mcpRequest(opts, path, init = {}) {
93
+ if (!opts.id) fail('Missing --id', 'E_INVALID_ARGS');
94
+ let token;
95
+ try { token = await getToken(opts); } catch (e) { fail(e.message, 'E_NO_TOKEN', 2); }
96
+ const baseUrl = getBaseUrl(opts);
97
+ try {
98
+ const result = await request(`${baseUrl}/api/faas/${encodeURIComponent(opts.id)}/mcp/${path}`, { token, ...init });
99
+ if (result.code !== 0) fail(result.msg || 'MCP operation failed', 'E_MCP_FAILED');
100
+ return result.data || result;
101
+ } catch (e) { failFromHttpError(e); }
102
+ }
103
+
104
+ async function mcpKeyCreate(opts) {
105
+ success(await mcpRequest(opts, 'keys', { method: 'POST', body: { name: opts.name || 'default' } }), opts);
106
+ }
107
+
108
+ async function mcpKeyList(opts) {
109
+ success(await mcpRequest(opts, 'keys'), opts);
110
+ }
111
+
112
+ async function mcpKeyRevoke(opts) {
113
+ if (!opts.keyId) fail('Missing --key-id', 'E_INVALID_ARGS');
114
+ success(await mcpRequest(opts, `keys?key_id=${encodeURIComponent(opts.keyId)}`, { method: 'DELETE' }), opts);
115
+ }
116
+
117
+ async function mcpAuthGet(opts) {
118
+ success(await mcpRequest(opts, 'auth'), opts);
119
+ }
120
+
121
+ async function mcpAuthUpdate(opts) {
122
+ const body = {};
123
+ if (opts.enabled !== undefined) body.enabled = String(opts.enabled).toLowerCase() !== 'false';
124
+ if (opts.auth !== undefined) body.auth = String(opts.auth).split(',').map((item) => item.trim()).filter(Boolean);
125
+ if (opts.oauthUser !== undefined) {
126
+ body.oauth_users = String(opts.oauthUser || '').split(',').map((item) => item.trim()).filter(Boolean);
127
+ }
128
+ if (opts.oauthPolicy !== undefined) body.oauth_policy = String(opts.oauthPolicy).trim().toLowerCase();
129
+ else if (body.oauth_users?.length) body.oauth_policy = 'whitelist';
130
+ if (!Object.keys(body).length) fail('No MCP auth changes supplied. Use auth get to inspect the current config.', 'E_INVALID_ARGS');
131
+ success(await mcpRequest(opts, 'auth', { method: 'PUT', body }), opts);
132
+ }
133
+
69
134
  async function list(opts) {
70
135
  let token;
71
136
  try { token = await getToken(opts); } catch (e) { fail(e.message, 'E_NO_TOKEN', 2); }
package/src/lib/help.js CHANGED
@@ -16,7 +16,7 @@ SYNTAX:
16
16
  COMMANDS:
17
17
  auth Login and manage Magic developer tokens
18
18
  page Publish and manage Magic pages, collaborators, and access
19
- faas Publish, list, and delete Magic FaaS functions
19
+ faas Publish and manage Magic FaaS HTTP/WSS/MCP functions
20
20
  file Upload, list, and delete TOS files
21
21
  link Generate Magic share links
22
22
  doc Create or append Feishu Doc HTML Box apps
@@ -42,6 +42,7 @@ EXAMPLES:
42
42
  magic-builder page collaborators add --id recxxx --open-ids ou_xxx,ou_yyy
43
43
  magic-builder page access groups add --id recxxx --chat-ids oc_xxx
44
44
  magic-builder faas publish handler.js --name report-api
45
+ magic-builder faas publish server.js --name weather-mcp --mcp --auth key,oauth
45
46
  magic-builder faas list
46
47
  magic-builder faas delete --id recxxx
47
48
  magic-builder file upload logo.png
@@ -101,10 +102,15 @@ COMMANDS:
101
102
  page access groups add|remove|set --id <id> --chat-ids <oc_a,oc_b>
102
103
  page access set --id <id> --file <access.json>
103
104
 
104
- faas publish <file.js> --name <name> [--id <id>]
105
+ faas publish <file.js> --name <name> [--id <id>] [--mcp --auth key,oauth --oauth-policy all|whitelist --oauth-user ou_xxx]
105
106
  faas publish --code <code> --name <name> [--id <id>]
106
107
  faas list [--title <keyword>]
107
108
  faas delete --id <id>
109
+ faas mcp key create --id <id> --name <name>
110
+ faas mcp key list --id <id>
111
+ faas mcp key revoke --id <id> --key-id <key_id>
112
+ faas mcp auth get --id <id>
113
+ faas mcp auth update --id <id> [--auth key,oauth] [--oauth-policy all|whitelist] [--oauth-user ou_xxx]
108
114
 
109
115
  file upload <file> [--key <key>] [--content-type <mime>]
110
116
  file list [--title <keyword>]
@@ -194,10 +200,15 @@ SYNTAX:
194
200
  faas: `@HELP magic-builder/faas
195
201
 
196
202
  SYNTAX:
197
- magic-builder faas publish <file.js> --name <name> [--id <id>]
203
+ magic-builder faas publish <file.js> --name <name> [--id <id>] [--mcp --auth key,oauth --oauth-policy all|whitelist --oauth-user ou_xxx]
198
204
  magic-builder faas publish --code <code> --name <name> [--id <id>]
199
205
  magic-builder faas list [--title <keyword>]
200
206
  magic-builder faas delete --id <id>
207
+ magic-builder faas mcp key create --id <id> --name production
208
+ magic-builder faas mcp key list --id <id>
209
+ magic-builder faas mcp key revoke --id <id> --key-id <key_id>
210
+ magic-builder faas mcp auth get --id <id>
211
+ magic-builder faas mcp auth update --id <id> --oauth-policy whitelist --oauth-user ou_xxx
201
212
  `,
202
213
  file: `@HELP magic-builder/file
203
214