Skip to content

Commit bd6e4df

Browse files
Working on the stack extension to ensure it has the correct thread
1 parent f829a9d commit bd6e4df

File tree

2 files changed

+96
-10
lines changed

2 files changed

+96
-10
lines changed

mcp_nexus/Extensions/ExtensionExecutor.cs

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ private IProcessHandle CreateProcess(
315315
string callbackToken,
316316
object? parameters)
317317
{
318-
// Build environment variables dictionary
318+
// Build environment variables dictionary (for secrets and system info only)
319319
var environmentVariables = new Dictionary<string, string>
320320
{
321321
["MCP_NEXUS_SESSION_ID"] = sessionId,
@@ -324,13 +324,6 @@ private IProcessHandle CreateProcess(
324324
["MCP_NEXUS_CALLBACK_TOKEN"] = callbackToken
325325
};
326326

327-
// Add extension parameters as JSON
328-
if (parameters != null)
329-
{
330-
var parametersJson = JsonSerializer.Serialize(parameters);
331-
environmentVariables["MCP_NEXUS_PARAMETERS"] = parametersJson;
332-
}
333-
334327
// Configure based on script type (only PowerShell supported)
335328
var scriptType = metadata.ScriptType.ToLowerInvariant();
336329
string fileName;
@@ -341,7 +334,23 @@ private IProcessHandle CreateProcess(
341334
// Try to find PowerShell - prefer pwsh (PowerShell 7+), fall back to powershell (5.1)
342335
string? powershellPath = FindPowerShell() ?? throw new InvalidOperationException("PowerShell not found. Please ensure pwsh.exe or powershell.exe is in PATH or installed.");
343336
fileName = powershellPath;
344-
arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{metadata.FullScriptPath}\"";
337+
338+
// Build PowerShell arguments with parameters
339+
var argumentsBuilder = new StringBuilder();
340+
argumentsBuilder.Append($"-NoProfile -ExecutionPolicy Bypass -File \"{metadata.FullScriptPath}\"");
341+
342+
// Add parameters as PowerShell command-line arguments
343+
if (parameters != null)
344+
{
345+
var paramArgs = BuildPowerShellParameterArguments(parameters);
346+
if (!string.IsNullOrWhiteSpace(paramArgs))
347+
{
348+
argumentsBuilder.Append(' ');
349+
argumentsBuilder.Append(paramArgs);
350+
}
351+
}
352+
353+
arguments = argumentsBuilder.ToString();
345354
}
346355
else
347356
{
@@ -354,6 +363,72 @@ private IProcessHandle CreateProcess(
354363
}
355364

356365

366+
/// <summary>
367+
/// Builds PowerShell command-line parameter arguments from a JSON object.
368+
/// Converts parameter names to PowerShell naming convention (camelCase to PascalCase).
369+
/// </summary>
370+
/// <param name="parameters">The parameters object to convert.</param>
371+
/// <returns>PowerShell parameter string (e.g., "-ThreadId '5' -Verbose $true").</returns>
372+
private string BuildPowerShellParameterArguments(object parameters)
373+
{
374+
if (parameters == null)
375+
return string.Empty;
376+
377+
var argumentsBuilder = new StringBuilder();
378+
379+
// Serialize to JSON and deserialize to JsonElement for easy property access
380+
var json = JsonSerializer.Serialize(parameters);
381+
using var doc = JsonDocument.Parse(json);
382+
var root = doc.RootElement;
383+
384+
foreach (var property in root.EnumerateObject())
385+
{
386+
// Convert camelCase to PascalCase for PowerShell convention
387+
var paramName = char.ToUpper(property.Name[0]) + property.Name[1..];
388+
389+
if (argumentsBuilder.Length > 0)
390+
argumentsBuilder.Append(' ');
391+
392+
argumentsBuilder.Append($"-{paramName}");
393+
394+
// Handle different value types
395+
switch (property.Value.ValueKind)
396+
{
397+
case JsonValueKind.String:
398+
// Escape single quotes in string values
399+
var stringValue = property.Value.GetString() ?? string.Empty;
400+
stringValue = stringValue.Replace("'", "''");
401+
argumentsBuilder.Append($" '{stringValue}'");
402+
break;
403+
404+
case JsonValueKind.Number:
405+
argumentsBuilder.Append($" {property.Value.GetRawText()}");
406+
break;
407+
408+
case JsonValueKind.True:
409+
argumentsBuilder.Append(" $true");
410+
break;
411+
412+
case JsonValueKind.False:
413+
argumentsBuilder.Append(" $false");
414+
break;
415+
416+
case JsonValueKind.Null:
417+
argumentsBuilder.Append(" $null");
418+
break;
419+
420+
default:
421+
// For complex types (objects, arrays), pass as JSON string
422+
var jsonValue = property.Value.GetRawText();
423+
jsonValue = jsonValue.Replace("'", "''");
424+
argumentsBuilder.Append($" '{jsonValue}'");
425+
break;
426+
}
427+
}
428+
429+
return argumentsBuilder.ToString();
430+
}
431+
357432
/// <summary>
358433
/// Finds PowerShell executable on the system.
359434
/// Prefers pwsh.exe (PowerShell 7+), falls back to powershell.exe (Windows PowerShell 5.1).

mcp_nexus/Extensions/stack_with_sources/stack_with_sources.ps1

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,33 @@ Downloads stack trace with source code for all frames.
66
This extension gets the stack trace for a specified thread and downloads
77
source files for all frames using the lsa command.
88
9+
.PARAMETER ThreadId
10+
Thread ID to analyze (e.g., '8' or '.' for current thread). Defaults to current thread ('.').
11+
12+
.EXAMPLE
13+
.\stack_with_sources.ps1 -ThreadId '5'
14+
15+
.EXAMPLE
16+
.\stack_with_sources.ps1
17+
918
.NOTES
1019
This is the workflow we discussed - gets stack with kL and runs lsa on each return address.
1120
#>
1221

1322
param(
23+
[Parameter(Mandatory=$false)]
1424
[string]$ThreadId = "." # Default to current thread
1525
)
1626

1727
# Import MCP Nexus helper module
1828
Import-Module "$PSScriptRoot\..\modules\McpNexusExtensions.psm1" -Force
1929

30+
Write-NexusLog "Starting stack_with_sources extension with ThreadId: $ThreadId" -Level Information
31+
2032
# Display user-friendly thread description
2133
$threadDisplay = if ($ThreadId -eq ".") { "current thread" } else { "thread $ThreadId" }
2234

2335
Write-NexusProgress "Starting stack analysis with source download for $threadDisplay"
24-
Write-NexusLog "Starting stack_with_sources extension for thread: $ThreadId" -Level Information
2536

2637
try {
2738
# Step 1: Get stack with line numbers

0 commit comments

Comments
 (0)