metro-mcp 0.6.2 → 0.6.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.
@@ -3740,7 +3740,7 @@ function extractCDPExceptionMessage(details, fallback = "Evaluation failed") {
3740
3740
  // package.json
3741
3741
  var package_default = {
3742
3742
  name: "metro-mcp",
3743
- version: "0.6.2",
3743
+ version: "0.6.3",
3744
3744
  description: "Plugin-based MCP server for React Native/Expo runtime debugging, inspection, and automation via Metro/CDP",
3745
3745
  homepage: "https://metromcp.dev",
3746
3746
  repository: {
@@ -3941,45 +3941,103 @@ class DeviceBufferManager {
3941
3941
  }
3942
3942
 
3943
3943
  // src/plugins/console.ts
3944
+ function formatPreview(preview) {
3945
+ if (!preview.properties)
3946
+ return null;
3947
+ const props = preview.properties.map((p) => {
3948
+ if (p.type === "object" && p.valuePreview) {
3949
+ const nested = formatPreview(p.valuePreview);
3950
+ return `${p.name}: ${nested || p.value || "[object]"}`;
3951
+ }
3952
+ return `${p.name}: ${p.value}`;
3953
+ });
3954
+ const overflow = preview.overflow ? ", ..." : "";
3955
+ if (preview.subtype === "array")
3956
+ return `[${props.join(", ")}${overflow}]`;
3957
+ return `{${props.join(", ")}${overflow}}`;
3958
+ }
3959
+ function formatRemoteObject(obj) {
3960
+ if (obj.type === "string")
3961
+ return obj.value;
3962
+ if (obj.type === "number")
3963
+ return String(obj.value);
3964
+ if (obj.type === "boolean")
3965
+ return String(obj.value);
3966
+ if (obj.type === "undefined")
3967
+ return "undefined";
3968
+ if (obj.subtype === "null")
3969
+ return "null";
3970
+ if (obj.preview) {
3971
+ const formatted = formatPreview(obj.preview);
3972
+ if (formatted)
3973
+ return formatted;
3974
+ }
3975
+ if (obj.description)
3976
+ return obj.description;
3977
+ if (obj.value !== undefined)
3978
+ return JSON.stringify(obj.value);
3979
+ return obj.className || obj.type || "[object]";
3980
+ }
3944
3981
  function formatCDPArgs(args) {
3945
3982
  return args.map((arg) => {
3946
3983
  if (typeof arg === "object" && arg !== null) {
3947
- const remoteObj = arg;
3948
- if (remoteObj.type === "string")
3949
- return remoteObj.value;
3950
- if (remoteObj.type === "number")
3951
- return String(remoteObj.value);
3952
- if (remoteObj.type === "boolean")
3953
- return String(remoteObj.value);
3954
- if (remoteObj.type === "undefined")
3955
- return "undefined";
3956
- if (remoteObj.subtype === "null")
3957
- return "null";
3958
- if (remoteObj.description)
3959
- return remoteObj.description;
3960
- if (remoteObj.value !== undefined)
3961
- return JSON.stringify(remoteObj.value);
3962
- return remoteObj.className || remoteObj.type || "[object]";
3984
+ return formatRemoteObject(arg);
3963
3985
  }
3964
3986
  return String(arg);
3965
3987
  }).join(" ");
3966
3988
  }
3989
+ async function resolveRemoteObject(cdpSend, objectId) {
3990
+ try {
3991
+ const result = await cdpSend("Runtime.callFunctionOn", {
3992
+ objectId,
3993
+ functionDeclaration: 'function() { try { return JSON.stringify(this, null, 2); } catch(e) { return "[unserializable]"; } }',
3994
+ returnByValue: true
3995
+ });
3996
+ const inner = result.result;
3997
+ return inner?.value ? inner.value : null;
3998
+ } catch {
3999
+ return null;
4000
+ }
4001
+ }
4002
+ async function formatCDPArgsDeep(cdpSend, args) {
4003
+ const parts = await Promise.all(args.map(async (arg) => {
4004
+ if (typeof arg !== "object" || arg === null)
4005
+ return String(arg);
4006
+ const remoteObj = arg;
4007
+ if (remoteObj.objectId && remoteObj.type === "object") {
4008
+ const deep = await resolveRemoteObject(cdpSend, remoteObj.objectId);
4009
+ if (deep)
4010
+ return deep;
4011
+ }
4012
+ return formatRemoteObject(remoteObj);
4013
+ }));
4014
+ return parts.join(" ");
4015
+ }
3967
4016
  var consolePlugin = definePlugin({
3968
4017
  name: "console",
3969
4018
  description: "Console log collection and filtering",
3970
4019
  async setup(ctx) {
3971
4020
  const buffers = new DeviceBufferManager(500);
4021
+ const cdpSend = ctx.cdp.send.bind(ctx.cdp);
3972
4022
  ctx.cdp.on("Runtime.consoleAPICalled", (params) => {
3973
4023
  const key = ctx.getActiveDeviceKey();
3974
4024
  if (!key)
3975
4025
  return;
3976
4026
  const args = params.args || [];
3977
- buffers.getOrCreate(key).push({
4027
+ const entry = {
3978
4028
  timestamp: Date.now(),
3979
4029
  level: params.type,
3980
4030
  message: formatCDPArgs(args),
3981
4031
  stackTrace: params.stackTrace ? JSON.stringify(params.stackTrace.callFrames) : undefined
3982
- });
4032
+ };
4033
+ buffers.getOrCreate(key).push(entry);
4034
+ const hasResolvable = args.some((arg) => typeof arg === "object" && arg !== null && arg.objectId);
4035
+ if (hasResolvable) {
4036
+ formatCDPArgsDeep(cdpSend, args).then((deep) => {
4037
+ if (deep !== entry.message)
4038
+ entry.message = deep;
4039
+ }).catch(() => {});
4040
+ }
3983
4041
  });
3984
4042
  ctx.events.on("bundle_transform_progressed", (event) => {
3985
4043
  if (event.transformedFileCount === 1) {
package/dist/index.js CHANGED
@@ -3748,7 +3748,7 @@ function extractCDPExceptionMessage(details, fallback = "Evaluation failed") {
3748
3748
  // package.json
3749
3749
  var package_default = {
3750
3750
  name: "metro-mcp",
3751
- version: "0.6.2",
3751
+ version: "0.6.3",
3752
3752
  description: "Plugin-based MCP server for React Native/Expo runtime debugging, inspection, and automation via Metro/CDP",
3753
3753
  homepage: "https://metromcp.dev",
3754
3754
  repository: {
@@ -3944,45 +3944,103 @@ class DeviceBufferManager {
3944
3944
  }
3945
3945
 
3946
3946
  // src/plugins/console.ts
3947
+ function formatPreview(preview) {
3948
+ if (!preview.properties)
3949
+ return null;
3950
+ const props = preview.properties.map((p) => {
3951
+ if (p.type === "object" && p.valuePreview) {
3952
+ const nested = formatPreview(p.valuePreview);
3953
+ return `${p.name}: ${nested || p.value || "[object]"}`;
3954
+ }
3955
+ return `${p.name}: ${p.value}`;
3956
+ });
3957
+ const overflow = preview.overflow ? ", ..." : "";
3958
+ if (preview.subtype === "array")
3959
+ return `[${props.join(", ")}${overflow}]`;
3960
+ return `{${props.join(", ")}${overflow}}`;
3961
+ }
3962
+ function formatRemoteObject(obj) {
3963
+ if (obj.type === "string")
3964
+ return obj.value;
3965
+ if (obj.type === "number")
3966
+ return String(obj.value);
3967
+ if (obj.type === "boolean")
3968
+ return String(obj.value);
3969
+ if (obj.type === "undefined")
3970
+ return "undefined";
3971
+ if (obj.subtype === "null")
3972
+ return "null";
3973
+ if (obj.preview) {
3974
+ const formatted = formatPreview(obj.preview);
3975
+ if (formatted)
3976
+ return formatted;
3977
+ }
3978
+ if (obj.description)
3979
+ return obj.description;
3980
+ if (obj.value !== undefined)
3981
+ return JSON.stringify(obj.value);
3982
+ return obj.className || obj.type || "[object]";
3983
+ }
3947
3984
  function formatCDPArgs(args) {
3948
3985
  return args.map((arg) => {
3949
3986
  if (typeof arg === "object" && arg !== null) {
3950
- const remoteObj = arg;
3951
- if (remoteObj.type === "string")
3952
- return remoteObj.value;
3953
- if (remoteObj.type === "number")
3954
- return String(remoteObj.value);
3955
- if (remoteObj.type === "boolean")
3956
- return String(remoteObj.value);
3957
- if (remoteObj.type === "undefined")
3958
- return "undefined";
3959
- if (remoteObj.subtype === "null")
3960
- return "null";
3961
- if (remoteObj.description)
3962
- return remoteObj.description;
3963
- if (remoteObj.value !== undefined)
3964
- return JSON.stringify(remoteObj.value);
3965
- return remoteObj.className || remoteObj.type || "[object]";
3987
+ return formatRemoteObject(arg);
3966
3988
  }
3967
3989
  return String(arg);
3968
3990
  }).join(" ");
3969
3991
  }
3992
+ async function resolveRemoteObject(cdpSend, objectId) {
3993
+ try {
3994
+ const result = await cdpSend("Runtime.callFunctionOn", {
3995
+ objectId,
3996
+ functionDeclaration: 'function() { try { return JSON.stringify(this, null, 2); } catch(e) { return "[unserializable]"; } }',
3997
+ returnByValue: true
3998
+ });
3999
+ const inner = result.result;
4000
+ return inner?.value ? inner.value : null;
4001
+ } catch {
4002
+ return null;
4003
+ }
4004
+ }
4005
+ async function formatCDPArgsDeep(cdpSend, args) {
4006
+ const parts = await Promise.all(args.map(async (arg) => {
4007
+ if (typeof arg !== "object" || arg === null)
4008
+ return String(arg);
4009
+ const remoteObj = arg;
4010
+ if (remoteObj.objectId && remoteObj.type === "object") {
4011
+ const deep = await resolveRemoteObject(cdpSend, remoteObj.objectId);
4012
+ if (deep)
4013
+ return deep;
4014
+ }
4015
+ return formatRemoteObject(remoteObj);
4016
+ }));
4017
+ return parts.join(" ");
4018
+ }
3970
4019
  var consolePlugin = definePlugin({
3971
4020
  name: "console",
3972
4021
  description: "Console log collection and filtering",
3973
4022
  async setup(ctx) {
3974
4023
  const buffers = new DeviceBufferManager(500);
4024
+ const cdpSend = ctx.cdp.send.bind(ctx.cdp);
3975
4025
  ctx.cdp.on("Runtime.consoleAPICalled", (params) => {
3976
4026
  const key = ctx.getActiveDeviceKey();
3977
4027
  if (!key)
3978
4028
  return;
3979
4029
  const args = params.args || [];
3980
- buffers.getOrCreate(key).push({
4030
+ const entry = {
3981
4031
  timestamp: Date.now(),
3982
4032
  level: params.type,
3983
4033
  message: formatCDPArgs(args),
3984
4034
  stackTrace: params.stackTrace ? JSON.stringify(params.stackTrace.callFrames) : undefined
3985
- });
4035
+ };
4036
+ buffers.getOrCreate(key).push(entry);
4037
+ const hasResolvable = args.some((arg) => typeof arg === "object" && arg !== null && arg.objectId);
4038
+ if (hasResolvable) {
4039
+ formatCDPArgsDeep(cdpSend, args).then((deep) => {
4040
+ if (deep !== entry.message)
4041
+ entry.message = deep;
4042
+ }).catch(() => {});
4043
+ }
3986
4044
  });
3987
4045
  ctx.events.on("bundle_transform_progressed", (event) => {
3988
4046
  if (event.transformedFileCount === 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/plugins/console.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,aAAa,yCAkHxB,CAAC"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/plugins/console.ts"],"names":[],"mappings":"AAuHA,eAAO,MAAM,aAAa,yCAiIxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metro-mcp",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Plugin-based MCP server for React Native/Expo runtime debugging, inspection, and automation via Metro/CDP",
5
5
  "homepage": "https://metromcp.dev",
6
6
  "repository": {