flockbay 0.10.15
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 +56 -0
- package/bin/flockbay-mcp.mjs +56 -0
- package/bin/flockbay.mjs +78 -0
- package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
- package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
- package/dist/index--o4BPz5o.cjs +10311 -0
- package/dist/index-CUp3juDS.mjs +10268 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +40 -0
- package/dist/lib.cjs +33 -0
- package/dist/lib.d.cts +957 -0
- package/dist/lib.d.mts +957 -0
- package/dist/lib.mjs +23 -0
- package/dist/runCodex-D3eT-TvB.cjs +3449 -0
- package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
- package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
- package/dist/runGemini-CBxZp6I7.cjs +3185 -0
- package/dist/types-C-jnUdn_.cjs +4498 -0
- package/dist/types-DGd6ea2Z.mjs +4450 -0
- package/kits/kit.open_world/kit.json +59 -0
- package/package.json +130 -0
- package/scripts/claude_local_launcher.cjs +73 -0
- package/scripts/claude_remote_launcher.cjs +16 -0
- package/scripts/claude_version_utils.cjs +391 -0
- package/scripts/ripgrep_launcher.cjs +33 -0
- package/scripts/session_hook_forwarder.cjs +49 -0
- package/scripts/test-codex-abort-history.mjs +77 -0
- package/scripts/unpack-tools.cjs +222 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
- package/tools/unreal-mcp/upstream/Python/README.md +40 -0
- package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
- package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
- package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
- package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
- package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
- package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
- package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
- package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
- package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#include "MCPServerRunnable.h"
|
|
2
|
+
#include "UnrealMCPBridge.h"
|
|
3
|
+
#include "Sockets.h"
|
|
4
|
+
#include "SocketSubsystem.h"
|
|
5
|
+
#include "Interfaces/IPv4/IPv4Address.h"
|
|
6
|
+
#include "Dom/JsonObject.h"
|
|
7
|
+
#include "Dom/JsonValue.h"
|
|
8
|
+
#include "Serialization/JsonSerializer.h"
|
|
9
|
+
#include "Serialization/JsonReader.h"
|
|
10
|
+
#include "JsonObjectConverter.h"
|
|
11
|
+
#include "Misc/ScopeLock.h"
|
|
12
|
+
#include "HAL/PlatformTime.h"
|
|
13
|
+
|
|
14
|
+
// Buffer size for receiving data
|
|
15
|
+
const int32 BufferSize = 8192;
|
|
16
|
+
|
|
17
|
+
FMCPServerRunnable::FMCPServerRunnable(UUnrealMCPBridge* InBridge, TSharedPtr<FSocket> InListenerSocket)
|
|
18
|
+
: Bridge(InBridge)
|
|
19
|
+
, ListenerSocket(InListenerSocket)
|
|
20
|
+
, bRunning(true)
|
|
21
|
+
{
|
|
22
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Created server runnable"));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
FMCPServerRunnable::~FMCPServerRunnable()
|
|
26
|
+
{
|
|
27
|
+
// Note: We don't delete the sockets here as they're owned by the bridge
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
bool FMCPServerRunnable::Init()
|
|
31
|
+
{
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
uint32 FMCPServerRunnable::Run()
|
|
36
|
+
{
|
|
37
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Server thread starting..."));
|
|
38
|
+
|
|
39
|
+
while (bRunning)
|
|
40
|
+
{
|
|
41
|
+
// UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Waiting for client connection..."));
|
|
42
|
+
|
|
43
|
+
bool bPending = false;
|
|
44
|
+
if (ListenerSocket->HasPendingConnection(bPending) && bPending)
|
|
45
|
+
{
|
|
46
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Client connection pending, accepting..."));
|
|
47
|
+
|
|
48
|
+
ClientSocket = MakeShareable(ListenerSocket->Accept(TEXT("MCPClient")));
|
|
49
|
+
if (ClientSocket.IsValid())
|
|
50
|
+
{
|
|
51
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Client connection accepted"));
|
|
52
|
+
|
|
53
|
+
// Set socket options to improve connection stability
|
|
54
|
+
ClientSocket->SetNoDelay(true);
|
|
55
|
+
int32 SocketBufferSize = 65536; // 64KB buffer
|
|
56
|
+
ClientSocket->SetSendBufferSize(SocketBufferSize, SocketBufferSize);
|
|
57
|
+
ClientSocket->SetReceiveBufferSize(SocketBufferSize, SocketBufferSize);
|
|
58
|
+
|
|
59
|
+
uint8 Buffer[8192];
|
|
60
|
+
while (bRunning)
|
|
61
|
+
{
|
|
62
|
+
int32 BytesRead = 0;
|
|
63
|
+
if (ClientSocket->Recv(Buffer, sizeof(Buffer), BytesRead))
|
|
64
|
+
{
|
|
65
|
+
if (BytesRead == 0)
|
|
66
|
+
{
|
|
67
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Client disconnected (zero bytes)"));
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Convert received data to string
|
|
72
|
+
Buffer[BytesRead] = '\0';
|
|
73
|
+
FString ReceivedText = UTF8_TO_TCHAR(Buffer);
|
|
74
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Received: %s"), *ReceivedText);
|
|
75
|
+
|
|
76
|
+
// Parse JSON
|
|
77
|
+
TSharedPtr<FJsonObject> JsonObject;
|
|
78
|
+
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ReceivedText);
|
|
79
|
+
|
|
80
|
+
if (FJsonSerializer::Deserialize(Reader, JsonObject))
|
|
81
|
+
{
|
|
82
|
+
// Get command type
|
|
83
|
+
FString CommandType;
|
|
84
|
+
if (JsonObject->TryGetStringField(TEXT("type"), CommandType))
|
|
85
|
+
{
|
|
86
|
+
// Execute command
|
|
87
|
+
FString Response = Bridge->ExecuteCommand(CommandType, JsonObject->GetObjectField(TEXT("params")));
|
|
88
|
+
|
|
89
|
+
// Log response for debugging
|
|
90
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Sending response: %s"), *Response);
|
|
91
|
+
|
|
92
|
+
// Send response
|
|
93
|
+
int32 BytesSent = 0;
|
|
94
|
+
if (!ClientSocket->Send((uint8*)TCHAR_TO_UTF8(*Response), Response.Len(), BytesSent))
|
|
95
|
+
{
|
|
96
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Failed to send response"));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Response sent successfully, bytes: %d"), BytesSent);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else
|
|
103
|
+
{
|
|
104
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Missing 'type' field in command"));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
{
|
|
109
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Failed to parse JSON from: %s"), *ReceivedText);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
{
|
|
114
|
+
int32 LastError = (int32)ISocketSubsystem::Get()->GetLastErrorCode();
|
|
115
|
+
// Don't break the connection for WouldBlock error, which is normal for non-blocking sockets
|
|
116
|
+
bool bShouldBreak = true;
|
|
117
|
+
|
|
118
|
+
// Check for "would block" error which isn't a real error for non-blocking sockets
|
|
119
|
+
if (LastError == SE_EWOULDBLOCK)
|
|
120
|
+
{
|
|
121
|
+
UE_LOG(LogTemp, Verbose, TEXT("MCPServerRunnable: Socket would block, continuing..."));
|
|
122
|
+
bShouldBreak = false;
|
|
123
|
+
// Small sleep to prevent tight loop when no data
|
|
124
|
+
FPlatformProcess::Sleep(0.01f);
|
|
125
|
+
}
|
|
126
|
+
// Check for other transient errors we might want to tolerate
|
|
127
|
+
else if (LastError == SE_EINTR) // Interrupted system call
|
|
128
|
+
{
|
|
129
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Socket read interrupted, continuing..."));
|
|
130
|
+
bShouldBreak = false;
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
{
|
|
134
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Client disconnected or error. Last error code: %d"), LastError);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (bShouldBreak)
|
|
138
|
+
{
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Failed to accept client connection"));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Small sleep to prevent tight loop
|
|
151
|
+
FPlatformProcess::Sleep(0.1f);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Server thread stopping"));
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
void FMCPServerRunnable::Stop()
|
|
159
|
+
{
|
|
160
|
+
bRunning = false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
void FMCPServerRunnable::Exit()
|
|
164
|
+
{
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void FMCPServerRunnable::HandleClientConnection(TSharedPtr<FSocket> InClientSocket)
|
|
168
|
+
{
|
|
169
|
+
if (!InClientSocket.IsValid())
|
|
170
|
+
{
|
|
171
|
+
UE_LOG(LogTemp, Error, TEXT("MCPServerRunnable: Invalid client socket passed to HandleClientConnection"));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Starting to handle client connection"));
|
|
176
|
+
|
|
177
|
+
// Set socket options for better connection stability
|
|
178
|
+
InClientSocket->SetNonBlocking(false);
|
|
179
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Set socket to blocking mode"));
|
|
180
|
+
|
|
181
|
+
// Properly read full message with timeout
|
|
182
|
+
const int32 MaxBufferSize = 4096;
|
|
183
|
+
uint8 Buffer[MaxBufferSize];
|
|
184
|
+
FString MessageBuffer;
|
|
185
|
+
|
|
186
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Starting message receive loop"));
|
|
187
|
+
|
|
188
|
+
while (bRunning && InClientSocket.IsValid())
|
|
189
|
+
{
|
|
190
|
+
// Log socket state
|
|
191
|
+
bool bIsConnected = InClientSocket->GetConnectionState() == SCS_Connected;
|
|
192
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Socket state - Connected: %s"),
|
|
193
|
+
bIsConnected ? TEXT("true") : TEXT("false"));
|
|
194
|
+
|
|
195
|
+
// Log pending data status before receive
|
|
196
|
+
uint32 PendingDataSize = 0;
|
|
197
|
+
bool HasPendingData = InClientSocket->HasPendingData(PendingDataSize);
|
|
198
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Before Recv - HasPendingData=%s, Size=%d"),
|
|
199
|
+
HasPendingData ? TEXT("true") : TEXT("false"), PendingDataSize);
|
|
200
|
+
|
|
201
|
+
// Try to receive data with timeout
|
|
202
|
+
int32 BytesRead = 0;
|
|
203
|
+
bool bReadSuccess = false;
|
|
204
|
+
|
|
205
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Attempting to receive data..."));
|
|
206
|
+
bReadSuccess = InClientSocket->Recv(Buffer, MaxBufferSize, BytesRead, ESocketReceiveFlags::None);
|
|
207
|
+
|
|
208
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Recv attempt complete - Success=%s, BytesRead=%d"),
|
|
209
|
+
bReadSuccess ? TEXT("true") : TEXT("false"), BytesRead);
|
|
210
|
+
|
|
211
|
+
if (BytesRead > 0)
|
|
212
|
+
{
|
|
213
|
+
// Log raw data for debugging
|
|
214
|
+
FString HexData;
|
|
215
|
+
for (int32 i = 0; i < FMath::Min(BytesRead, 50); ++i)
|
|
216
|
+
{
|
|
217
|
+
HexData += FString::Printf(TEXT("%02X "), Buffer[i]);
|
|
218
|
+
}
|
|
219
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Raw data (first 50 bytes hex): %s%s"),
|
|
220
|
+
*HexData, BytesRead > 50 ? TEXT("...") : TEXT(""));
|
|
221
|
+
|
|
222
|
+
// Convert and log received data
|
|
223
|
+
Buffer[BytesRead] = 0; // Null terminate
|
|
224
|
+
FString ReceivedData = UTF8_TO_TCHAR(Buffer);
|
|
225
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Received data as string: '%s'"), *ReceivedData);
|
|
226
|
+
|
|
227
|
+
// Append to message buffer
|
|
228
|
+
MessageBuffer.Append(ReceivedData);
|
|
229
|
+
|
|
230
|
+
// Process complete messages (messages are terminated with newline)
|
|
231
|
+
if (MessageBuffer.Contains(TEXT("\n")))
|
|
232
|
+
{
|
|
233
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Newline detected in buffer, processing messages"));
|
|
234
|
+
|
|
235
|
+
TArray<FString> Messages;
|
|
236
|
+
MessageBuffer.ParseIntoArray(Messages, TEXT("\n"), true);
|
|
237
|
+
|
|
238
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Found %d message(s) in buffer"), Messages.Num());
|
|
239
|
+
|
|
240
|
+
// Process all complete messages
|
|
241
|
+
for (int32 i = 0; i < Messages.Num() - 1; ++i)
|
|
242
|
+
{
|
|
243
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Processing message %d: '%s'"),
|
|
244
|
+
i + 1, *Messages[i]);
|
|
245
|
+
ProcessMessage(InClientSocket, Messages[i]);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Keep any incomplete message in the buffer
|
|
249
|
+
MessageBuffer = Messages.Last();
|
|
250
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Remaining buffer after processing: %s"),
|
|
251
|
+
*MessageBuffer);
|
|
252
|
+
}
|
|
253
|
+
else
|
|
254
|
+
{
|
|
255
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: No complete message yet (no newline detected)"));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else if (!bReadSuccess)
|
|
259
|
+
{
|
|
260
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Connection closed or error occurred - Last error: %d"),
|
|
261
|
+
(int32)ISocketSubsystem::Get()->GetLastErrorCode());
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Small sleep to prevent tight loop
|
|
266
|
+
FPlatformProcess::Sleep(0.01f);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Exited message receive loop"));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
void FMCPServerRunnable::ProcessMessage(TSharedPtr<FSocket> Client, const FString& Message)
|
|
273
|
+
{
|
|
274
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Processing message: %s"), *Message);
|
|
275
|
+
|
|
276
|
+
// Parse message as JSON
|
|
277
|
+
TSharedPtr<FJsonObject> JsonMessage;
|
|
278
|
+
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Message);
|
|
279
|
+
|
|
280
|
+
if (!FJsonSerializer::Deserialize(Reader, JsonMessage) || !JsonMessage.IsValid())
|
|
281
|
+
{
|
|
282
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Failed to parse message as JSON"));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Extract command type and parameters using MCP protocol format
|
|
287
|
+
FString CommandType;
|
|
288
|
+
TSharedPtr<FJsonObject> Params = MakeShareable(new FJsonObject());
|
|
289
|
+
|
|
290
|
+
if (!JsonMessage->TryGetStringField(TEXT("command"), CommandType))
|
|
291
|
+
{
|
|
292
|
+
UE_LOG(LogTemp, Warning, TEXT("MCPServerRunnable: Message missing 'command' field"));
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Parameters are optional in MCP protocol
|
|
297
|
+
if (JsonMessage->HasField(TEXT("params")))
|
|
298
|
+
{
|
|
299
|
+
TSharedPtr<FJsonValue> ParamsValue = JsonMessage->TryGetField(TEXT("params"));
|
|
300
|
+
if (ParamsValue.IsValid() && ParamsValue->Type == EJson::Object)
|
|
301
|
+
{
|
|
302
|
+
Params = ParamsValue->AsObject();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Executing command: %s"), *CommandType);
|
|
307
|
+
|
|
308
|
+
// Execute command
|
|
309
|
+
FString Response = Bridge->ExecuteCommand(CommandType, Params);
|
|
310
|
+
|
|
311
|
+
// Send response with newline terminator
|
|
312
|
+
Response += TEXT("\n");
|
|
313
|
+
int32 BytesSent = 0;
|
|
314
|
+
|
|
315
|
+
UE_LOG(LogTemp, Display, TEXT("MCPServerRunnable: Sending response: %s"), *Response);
|
|
316
|
+
|
|
317
|
+
if (!Client->Send((uint8*)TCHAR_TO_UTF8(*Response), Response.Len(), BytesSent))
|
|
318
|
+
{
|
|
319
|
+
UE_LOG(LogTemp, Error, TEXT("MCPServerRunnable: Failed to send response"));
|
|
320
|
+
}
|
|
321
|
+
}
|