@atezer/figma-mcp-bridge 1.1.1 → 1.1.2

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.
@@ -9,12 +9,27 @@
9
9
  padding: 0;
10
10
  }
11
11
 
12
+ html, body {
13
+ overflow: hidden !important;
14
+ overflow-x: hidden !important;
15
+ overflow-y: hidden !important;
16
+ /* Scrollbar'ları gizle; içerik ne ise öyle görünsün (taşma yok) */
17
+ -ms-overflow-style: none;
18
+ scrollbar-width: none;
19
+ }
20
+ html::-webkit-scrollbar, body::-webkit-scrollbar {
21
+ display: none;
22
+ }
23
+
12
24
  body {
13
25
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
14
26
  font-size: 11px;
15
27
  background: var(--figma-color-bg, #2c2c2c);
16
28
  color: var(--figma-color-text, rgba(255, 255, 255, 0.9));
17
- height: 100%;
29
+ width: fit-content;
30
+ min-width: 0;
31
+ height: auto;
32
+ min-height: 0;
18
33
  display: flex;
19
34
  align-items: center;
20
35
  justify-content: center;
@@ -83,17 +98,29 @@
83
98
  display: flex;
84
99
  flex-direction: column;
85
100
  gap: 6px;
86
- width: 100%;
101
+ width: fit-content;
102
+ min-width: 0;
103
+ max-width: 100%;
104
+ overflow: hidden;
87
105
  }
88
- .bridge-port {
106
+ .bridge-host, .bridge-port {
89
107
  display: flex;
90
108
  align-items: center;
91
109
  gap: 6px;
92
110
  font-size: 10px;
93
111
  }
94
- .bridge-port label {
112
+ .bridge-host label, .bridge-port label {
95
113
  color: var(--figma-color-text-secondary, rgba(255, 255, 255, 0.7));
96
114
  }
115
+ .bridge-host input {
116
+ width: 90px;
117
+ padding: 2px 4px;
118
+ background: var(--figma-color-bg-tertiary, #1e1e1e);
119
+ border: 1px solid var(--figma-color-border, #4a4a4a);
120
+ border-radius: 3px;
121
+ color: inherit;
122
+ font-size: 11px;
123
+ }
97
124
  .bridge-port input {
98
125
  width: 56px;
99
126
  padding: 2px 4px;
@@ -125,16 +152,20 @@
125
152
  </head>
126
153
  <body>
127
154
  <div class="bridge-row">
128
- <div class="bridge-status" id="status-container" title="When 'no server': run MCP server (e.g. npm run dev:local) or set correct port">
155
+ <div class="bridge-status" id="status-container" title="'no server': MCP bridge çalıştığından emin olun. Browser Figma'da da çalışır (aynı makinede localhost, uzakta IP girin).">
129
156
  <div class="status-indicator loading" id="status-dot"></div>
130
157
  <div class="status-text">
131
158
  <span class="label">MCP</span>
132
159
  <span class="state" id="status-state">connecting</span>
133
160
  </div>
134
161
  </div>
135
- <div class="bridge-port" title="Port (multi-instance: her kullanici farkli port)">
162
+ <div class="bridge-host" title="Host: localhost (aynı makine) veya IP adresi (uzak makine). Browser Figma'da da çalışır.">
163
+ <label for="mcp-host">Host</label>
164
+ <input type="text" id="mcp-host" value="localhost" placeholder="localhost" aria-label="MCP bridge host (localhost veya IP)" />
165
+ </div>
166
+ <div class="bridge-port" title="Port: Claude açıkken 5454'te bağlanır. Çoklu kullanıcıda her kullanıcı farklı port (5455–5470) seçer.">
136
167
  <label for="mcp-port">Port</label>
137
- <input type="number" id="mcp-port" min="5454" max="5470" value="5454" />
168
+ <input type="number" id="mcp-port" min="5454" max="5470" value="5454" aria-label="MCP bridge port (5454 varsayılan, Claude açıkken bağlanır)" />
138
169
  </div>
139
170
  </div>
140
171
 
@@ -257,8 +288,11 @@
257
288
  // COMPONENT OPERATIONS
258
289
  // ============================================================================
259
290
 
260
- window.getLocalComponents = () => {
261
- return window.sendPluginCommand('GET_LOCAL_COMPONENTS', {}, 300000)
291
+ window.getLocalComponents = (currentPageOnly, limit) => {
292
+ var params = {};
293
+ params.currentPageOnly = currentPageOnly !== false;
294
+ if (limit != null && limit > 0) params.limit = limit;
295
+ return window.sendPluginCommand('GET_LOCAL_COMPONENTS', params, 120000)
262
296
  .catch(function(err) { return { success: false, error: err.message || String(err) }; });
263
297
  };
264
298
 
@@ -588,6 +622,9 @@
588
622
  case 'GET_DOCUMENT_STRUCTURE_RESULT':
589
623
  handleResult('GET_DOCUMENT_STRUCTURE', null);
590
624
  break;
625
+ case 'GET_NODE_CONTEXT_RESULT':
626
+ handleResult('GET_NODE_CONTEXT', null);
627
+ break;
591
628
  case 'GET_LOCAL_STYLES_RESULT':
592
629
  handleResult('GET_LOCAL_STYLES', null);
593
630
  break;
@@ -612,8 +649,26 @@
612
649
  }
613
650
  };
614
651
 
615
- window.getDocumentStructure = (depth, verbosity) => {
616
- return window.sendPluginCommand('GET_DOCUMENT_STRUCTURE', { depth: depth || 1, verbosity: verbosity || 'summary' }, 30000).then(function(r) {
652
+ window.getDocumentStructure = (depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint) => {
653
+ var payload = { depth: depth || 1, verbosity: verbosity || 'summary' };
654
+ if (includeLayout !== undefined) payload.includeLayout = !!includeLayout;
655
+ if (includeVisual !== undefined) payload.includeVisual = !!includeVisual;
656
+ if (includeTypography !== undefined) payload.includeTypography = !!includeTypography;
657
+ if (includeCodeReady !== undefined) payload.includeCodeReady = !!includeCodeReady;
658
+ if (outputHint !== undefined && outputHint != null) payload.outputHint = outputHint;
659
+ return window.sendPluginCommand('GET_DOCUMENT_STRUCTURE', payload, 90000).then(function(r) {
660
+ if (r && r.success === false) return r;
661
+ return r && r.data !== undefined ? r.data : r;
662
+ });
663
+ };
664
+ window.getNodeContext = (nodeId, depth, verbosity, includeLayout, includeVisual, includeTypography, includeCodeReady, outputHint) => {
665
+ var payload = { nodeId: nodeId, depth: depth || 2, verbosity: verbosity || 'standard' };
666
+ if (includeLayout !== undefined) payload.includeLayout = !!includeLayout;
667
+ if (includeVisual !== undefined) payload.includeVisual = !!includeVisual;
668
+ if (includeTypography !== undefined) payload.includeTypography = !!includeTypography;
669
+ if (includeCodeReady !== undefined) payload.includeCodeReady = !!includeCodeReady;
670
+ if (outputHint !== undefined && outputHint != null) payload.outputHint = outputHint;
671
+ return window.sendPluginCommand('GET_NODE_CONTEXT', payload, 90000).then(function(r) {
617
672
  if (r && r.success === false) return r;
618
673
  return r && r.data !== undefined ? r.data : r;
619
674
  });
@@ -649,12 +704,20 @@
649
704
 
650
705
  // ============================================================================
651
706
  // MCP PLUGIN BRIDGE - WebSocket client (no Figma debug port needed)
652
- // Port configurable for multi-instance: her kullanici kendi portunu secer (5454-5470)
707
+ // Host + Port configurable: browser Figma ve uzak makine destegi
653
708
  // ============================================================================
654
- var MCP_BRIDGE_STORAGE_KEY = 'f-mcp-bridge-port';
709
+ var MCP_BRIDGE_PORT_KEY = 'f-mcp-bridge-port';
710
+ var MCP_BRIDGE_HOST_KEY = 'f-mcp-bridge-host';
655
711
  var mcpBridgeWs = null;
656
712
  var mcpBridgeReconnectTimer = null;
657
713
 
714
+ function getMcpBridgeHost() {
715
+ var el = document.getElementById('mcp-host');
716
+ if (!el) return 'localhost';
717
+ var v = (el.value || '').trim();
718
+ return v || 'localhost';
719
+ }
720
+
658
721
  function getMcpBridgePort() {
659
722
  var el = document.getElementById('mcp-port');
660
723
  if (!el) return 5454;
@@ -663,9 +726,31 @@
663
726
  return n;
664
727
  }
665
728
 
729
+ function initMcpHostInput() {
730
+ try {
731
+ var stored = localStorage.getItem(MCP_BRIDGE_HOST_KEY);
732
+ if (stored) {
733
+ var el = document.getElementById('mcp-host');
734
+ if (el) { el.value = stored; }
735
+ }
736
+ } catch (e) {}
737
+ var el = document.getElementById('mcp-host');
738
+ if (el) {
739
+ el.addEventListener('change', function() {
740
+ var host = getMcpBridgeHost();
741
+ try { localStorage.setItem(MCP_BRIDGE_HOST_KEY, host); } catch (e) {}
742
+ if (mcpBridgeWs) {
743
+ mcpBridgeWs.close();
744
+ mcpBridgeWs = null;
745
+ }
746
+ connectMcpBridge();
747
+ });
748
+ }
749
+ }
750
+
666
751
  function initMcpPortInput() {
667
752
  try {
668
- var stored = localStorage.getItem(MCP_BRIDGE_STORAGE_KEY);
753
+ var stored = localStorage.getItem(MCP_BRIDGE_PORT_KEY);
669
754
  if (stored) {
670
755
  var n = parseInt(stored, 10);
671
756
  if (n >= 5454 && n <= 5470) {
@@ -678,7 +763,7 @@
678
763
  if (el) {
679
764
  el.addEventListener('change', function() {
680
765
  var port = getMcpBridgePort();
681
- try { localStorage.setItem(MCP_BRIDGE_STORAGE_KEY, String(port)); } catch (e) {}
766
+ try { localStorage.setItem(MCP_BRIDGE_PORT_KEY, String(port)); } catch (e) {}
682
767
  if (mcpBridgeWs) {
683
768
  mcpBridgeWs.close();
684
769
  mcpBridgeWs = null;
@@ -688,29 +773,52 @@
688
773
  }
689
774
  }
690
775
 
776
+ var mcpHandshakeTimer = null;
777
+ var mcpHandshakeDone = false;
778
+
691
779
  function connectMcpBridge() {
692
780
  if (mcpBridgeWs && mcpBridgeWs.readyState === 1) return;
781
+ var host = getMcpBridgeHost();
693
782
  var port = getMcpBridgePort();
694
- var url = 'ws://localhost:' + port;
783
+ var url = 'ws://' + host + ':' + port;
784
+ mcpHandshakeDone = false;
695
785
  try {
696
786
  mcpBridgeWs = new WebSocket(url);
697
787
  mcpBridgeWs.onopen = function() {
698
- console.log('[F-MCP ATezer Bridge] Connected to MCP server on port ' + port);
699
- updateStatus('ready', true, false);
788
+ console.log('[F-MCP ATezer Bridge] WebSocket opened to ' + url + ', waiting for handshake...');
789
+ updateStatus('connecting...', false, false);
700
790
  mcpBridgeWs.send(JSON.stringify({ type: 'ready' }));
791
+ if (mcpHandshakeTimer) clearTimeout(mcpHandshakeTimer);
792
+ mcpHandshakeTimer = setTimeout(function() {
793
+ if (!mcpHandshakeDone && mcpBridgeWs) {
794
+ console.warn('[F-MCP ATezer Bridge] No welcome from server — wrong server or outdated bridge');
795
+ updateStatus('wrong server', false, true);
796
+ }
797
+ }, 5000);
701
798
  };
702
799
  mcpBridgeWs.onmessage = function(event) {
703
800
  try {
704
801
  var msg = JSON.parse(event.data);
802
+ if (msg.type === 'welcome') {
803
+ mcpHandshakeDone = true;
804
+ if (mcpHandshakeTimer) { clearTimeout(mcpHandshakeTimer); mcpHandshakeTimer = null; }
805
+ var connectedPort = msg.port || port;
806
+ console.log('[F-MCP ATezer Bridge] Handshake OK — bridge v' + (msg.bridgeVersion || '?') + ' on port ' + connectedPort);
807
+ updateStatus('ready (:' + connectedPort + ')', true, false);
808
+ return;
809
+ }
705
810
  if (!msg.id || !msg.method) return;
706
811
  var id = msg.id;
707
812
  var method = msg.method;
708
813
  var params = msg.params || {};
709
814
  var run = function() {
710
815
  if (method === 'getVariablesFromPluginUI') {
711
- if (!window.__figmaVariablesReady || !window.__figmaVariablesData)
712
- return { success: false, error: 'Variables not loaded yet' };
713
- return { success: true, variables: window.__figmaVariablesData.variables, variableCollections: window.__figmaVariablesData.variableCollections };
816
+ // Always refresh first (async API) so variables work in dynamic-page context
817
+ return window.refreshVariables().then(function(r) {
818
+ if (r && r.success === false) return { success: false, error: r.error || 'Variables refresh failed' };
819
+ if (!window.__figmaVariablesData) return { success: false, error: 'Variables not loaded' };
820
+ return { success: true, variables: window.__figmaVariablesData.variables, variableCollections: window.__figmaVariablesData.variableCollections };
821
+ });
714
822
  }
715
823
  if (method === 'getComponentFromPluginUI') {
716
824
  return window.requestComponentData(params.nodeId).then(function(data) {
@@ -758,7 +866,7 @@
758
866
  return window.refreshVariables();
759
867
  }
760
868
  if (method === 'getLocalComponents') {
761
- return window.getLocalComponents();
869
+ return window.getLocalComponents(params.currentPageOnly, params.limit);
762
870
  }
763
871
  if (method === 'instantiateComponent') {
764
872
  return window.instantiateComponent(params.componentKey, params.options);
@@ -815,7 +923,10 @@
815
923
  return window.setInstanceProperties(params.nodeId, params.properties);
816
924
  }
817
925
  if (method === 'getDocumentStructure') {
818
- return window.getDocumentStructure(params.depth, params.verbosity);
926
+ return window.getDocumentStructure(params.depth, params.verbosity, params.includeLayout, params.includeVisual, params.includeTypography, params.includeCodeReady, params.outputHint);
927
+ }
928
+ if (method === 'getNodeContext') {
929
+ return window.getNodeContext(params.nodeId, params.depth, params.verbosity, params.includeLayout, params.includeVisual, params.includeTypography, params.includeCodeReady, params.outputHint);
819
930
  }
820
931
  if (method === 'getLocalStyles') {
821
932
  return window.getLocalStyles(params.verbosity);
@@ -869,6 +980,7 @@
869
980
  }
870
981
  }
871
982
  if (typeof WebSocket !== 'undefined') {
983
+ initMcpHostInput();
872
984
  initMcpPortInput();
873
985
  connectMcpBridge();
874
986
  }
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@atezer/figma-mcp-bridge",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "F-MCP ATezer: MCP server and Figma plugin bridge for Claude/Cursor. No REST token required.",
5
5
  "type": "module",
6
6
  "main": "dist/local.js",
7
7
  "types": "dist/local.d.ts",
8
8
  "bin": {
9
- "figma-mcp-bridge": "./dist/local.js"
9
+ "figma-mcp-bridge": "./dist/local-plugin-only.js",
10
+ "figma-mcp-bridge-full": "./dist/local.js"
10
11
  },
11
12
  "files": [
12
13
  "dist",