@symbo.ls/mcp-server 3.7.0 → 3.7.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@symbo.ls/mcp-server",
3
- "version": "3.7.0",
3
+ "version": "3.7.4",
4
4
  "description": "HTTP proxy for the Symbols MCP server — runs as a Cloudflare Worker",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -212,6 +212,104 @@ const TOOLS = [
212
212
  required: ['component_code'],
213
213
  },
214
214
  },
215
+ {
216
+ name: 'login',
217
+ description:
218
+ 'Log in to the Symbols platform with email and password. Returns a JWT token for use with publish and push tools.',
219
+ inputSchema: {
220
+ type: 'object',
221
+ properties: {
222
+ email: {
223
+ type: 'string',
224
+ description: 'Symbols account email address',
225
+ },
226
+ password: {
227
+ type: 'string',
228
+ description: 'Symbols account password',
229
+ },
230
+ },
231
+ required: ['email', 'password'],
232
+ },
233
+ },
234
+ {
235
+ name: 'publish',
236
+ description:
237
+ 'Publish a version of a Symbols project to the platform. Requires authentication via token or api_key.',
238
+ inputSchema: {
239
+ type: 'object',
240
+ properties: {
241
+ project: {
242
+ type: 'string',
243
+ description: 'Project ID (MongoDB ObjectId) or project key (pr_xxxx)',
244
+ },
245
+ token: {
246
+ type: 'string',
247
+ description: 'JWT access token from login or ~/.smblsrc',
248
+ },
249
+ api_key: {
250
+ type: 'string',
251
+ description:
252
+ 'API key (sk_live_...) from project integration settings. Alternative to token.',
253
+ },
254
+ version: {
255
+ type: 'string',
256
+ description: 'Version string or version ID to publish. Leave empty for latest.',
257
+ default: '',
258
+ },
259
+ branch: {
260
+ type: 'string',
261
+ description: 'Branch to publish from',
262
+ default: 'main',
263
+ },
264
+ },
265
+ required: ['project'],
266
+ },
267
+ },
268
+ {
269
+ name: 'push',
270
+ description:
271
+ 'Push/deploy a Symbols project to a specific environment. Requires authentication via token or api_key.',
272
+ inputSchema: {
273
+ type: 'object',
274
+ properties: {
275
+ project: {
276
+ type: 'string',
277
+ description: 'Project ID (MongoDB ObjectId) or project key (pr_xxxx)',
278
+ },
279
+ token: {
280
+ type: 'string',
281
+ description: 'JWT access token from login or ~/.smblsrc',
282
+ },
283
+ api_key: {
284
+ type: 'string',
285
+ description:
286
+ 'API key (sk_live_...) from project integration settings. Alternative to token.',
287
+ },
288
+ environment: {
289
+ type: 'string',
290
+ description: 'Target environment key (e.g. "production", "staging", "dev")',
291
+ default: 'production',
292
+ },
293
+ mode: {
294
+ type: 'string',
295
+ description:
296
+ 'Deploy mode — "latest" (newest from branch), "published" (current published version), "version" (specific version), or "branch" (track a branch)',
297
+ default: 'published',
298
+ },
299
+ version: {
300
+ type: 'string',
301
+ description: 'Required when mode is "version" — the version string or ID to deploy',
302
+ default: '',
303
+ },
304
+ branch: {
305
+ type: 'string',
306
+ description: 'Branch to deploy from when mode is "latest" or "branch"',
307
+ default: 'main',
308
+ },
309
+ },
310
+ required: ['project'],
311
+ },
312
+ },
215
313
  {
216
314
  name: 'detect_environment',
217
315
  description:
@@ -259,7 +357,42 @@ const TOOLS = [
259
357
  },
260
358
  ];
261
359
 
262
- function callTool(name, args = {}) {
360
+ const API_BASE = 'https://api.symbols.app';
361
+
362
+ const AUTH_HELP = `To authenticate, provide one of:
363
+ - **token**: JWT from \`smbls login\` (stored in ~/.smblsrc) or env var SYMBOLS_TOKEN
364
+ - **api_key**: API key (sk_live_...) from your project's integration settings
365
+
366
+ To get a token:
367
+ 1. Run \`smbls login\` in your terminal, or
368
+ 2. Use the \`login\` tool with your email and password
369
+
370
+ Your project can be identified by either:
371
+ - **project**: MongoDB ObjectId (from project settings or symbols.json)
372
+ - **project**: Project key (pr_xxxx, found in symbols.json or project URL)`;
373
+
374
+ function authHeader(token, apiKey) {
375
+ if (apiKey) return { 'Authorization': `ApiKey ${apiKey}`, 'Content-Type': 'application/json' };
376
+ if (token) return { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' };
377
+ return null;
378
+ }
379
+
380
+ async function apiRequest(method, path, { token, api_key, body } = {}) {
381
+ const headers = authHeader(token, api_key);
382
+ if (!headers) return { success: false, error: 'No credentials provided', message: AUTH_HELP };
383
+ const resp = await fetch(`${API_BASE}${path}`, {
384
+ method,
385
+ headers,
386
+ body: body ? JSON.stringify(body) : undefined,
387
+ });
388
+ try {
389
+ return await resp.json();
390
+ } catch {
391
+ return { success: false, error: `HTTP ${resp.status}`, message: await resp.text() };
392
+ }
393
+ }
394
+
395
+ async function callTool(name, args = {}) {
263
396
  if (name === 'get_project_rules') {
264
397
  return readSkill('RULES.md');
265
398
  }
@@ -376,6 +509,70 @@ function callTool(name, args = {}) {
376
509
  return output;
377
510
  }
378
511
 
512
+ if (name === 'login') {
513
+ const { email, password } = args;
514
+ if (!email || !password) return 'Error: email and password are required.';
515
+ const resp = await fetch(`${API_BASE}/core/auth/login`, {
516
+ method: 'POST',
517
+ headers: { 'Content-Type': 'application/json' },
518
+ body: JSON.stringify({ email, password }),
519
+ });
520
+ let result;
521
+ try {
522
+ result = await resp.json();
523
+ } catch {
524
+ return `Login failed: HTTP ${resp.status}`;
525
+ }
526
+ if (result.success) {
527
+ const data = result.data || {};
528
+ const tokens = data.tokens || {};
529
+ const user = data.user || {};
530
+ return `Logged in as ${user.name || user.email || 'unknown'}.\nToken: ${tokens.accessToken || ''}\nExpires: ${(tokens.accessTokenExp || {}).expiresAt || 'unknown'}\n\nUse this token with the \`publish\` and \`push\` tools.`;
531
+ }
532
+ return `Login failed: ${result.error || result.message || 'Unknown error'}`;
533
+ }
534
+
535
+ if (name === 'publish') {
536
+ const { project, token, api_key, version, branch = 'main' } = args;
537
+ if (!project) return 'Error: project (ID or key) is required.';
538
+ if (!token && !api_key) return `Authentication required.\n\n${AUTH_HELP}`;
539
+ const body = { branch };
540
+ if (version) body.version = version;
541
+ const result = await apiRequest('POST', `/${project}/publish`, { token, api_key, body });
542
+ if (result.success) {
543
+ const data = result.data || {};
544
+ return `Published successfully.\nVersion: ${data.value || data.id || 'unknown'}`;
545
+ }
546
+ return `Publish failed: ${result.error || 'Unknown error'}\n${result.message || ''}`;
547
+ }
548
+
549
+ if (name === 'push') {
550
+ const {
551
+ project,
552
+ token,
553
+ api_key,
554
+ environment = 'production',
555
+ mode = 'published',
556
+ version,
557
+ branch = 'main',
558
+ } = args;
559
+ if (!project) return 'Error: project (ID or key) is required.';
560
+ if (!token && !api_key) return `Authentication required.\n\n${AUTH_HELP}`;
561
+ const body = { mode, branch };
562
+ if (version) body.version = version;
563
+ const result = await apiRequest('POST', `/${project}/environments/${environment}/publish`, {
564
+ token,
565
+ api_key,
566
+ body,
567
+ });
568
+ if (result.success) {
569
+ const data = result.data || {};
570
+ const config = data.config || {};
571
+ return `Pushed to ${data.key || environment} successfully.\nMode: ${config.mode || mode}\nVersion: ${config.version || 'latest'}\nBranch: ${config.branch || branch}`;
572
+ }
573
+ return `Push failed: ${result.error || 'Unknown error'}\n${result.message || ''}`;
574
+ }
575
+
379
576
  if (name === 'detect_environment') {
380
577
  const {
381
578
  has_symbols_json,
@@ -590,7 +787,7 @@ const PROMPTS = [
590
787
 
591
788
  const SERVER_INFO = { name: 'Symbols MCP', version: '1.1.1' };
592
789
 
593
- export function handleJsonRpc(req) {
790
+ export async function handleJsonRpc(req) {
594
791
  const { method, params, id } = req;
595
792
 
596
793
  if (method === 'initialize') {
@@ -615,7 +812,7 @@ export function handleJsonRpc(req) {
615
812
  if (method === 'tools/call') {
616
813
  const { name, arguments: args = {} } = params || {};
617
814
  try {
618
- const text = callTool(name, args);
815
+ const text = await callTool(name, args);
619
816
  return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text }] } };
620
817
  } catch (e) {
621
818
  return {
@@ -66,14 +66,14 @@ function isNotificationOrResponse(msg) {
66
66
  return false;
67
67
  }
68
68
 
69
- function handleMcpPost(request, body) {
69
+ async function handleMcpPost(request, body) {
70
70
  // Notifications and responses get 202 Accepted
71
71
  if (isNotificationOrResponse(body)) {
72
72
  return new Response(null, { status: 202, headers: CORS_HEADERS });
73
73
  }
74
74
 
75
75
  // Handle JSON-RPC request
76
- const result = handleJsonRpc(body);
76
+ const result = await handleJsonRpc(body);
77
77
  if (result === null) {
78
78
  return new Response(null, { status: 202, headers: CORS_HEADERS });
79
79
  }
@@ -166,7 +166,7 @@ export async function handleRequest(request) {
166
166
  return json({ error: 'Invalid JSON body' }, 400);
167
167
  }
168
168
  try {
169
- const result = callTool(toolName, args);
169
+ const result = await callTool(toolName, args);
170
170
  return json({ content: [{ type: 'text', text: result }] });
171
171
  } catch (e) {
172
172
  return json({ error: e.message }, 404);