Skip to content

Commit 4c3aae8

Browse files
committed
improve serialization for workflow interrupt
1 parent 3118662 commit 4c3aae8

File tree

5 files changed

+35
-17
lines changed

5 files changed

+35
-17
lines changed

src/MCP/McpConnector.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,17 @@ class McpConnector
4444

4545
/**
4646
* @param array<string, mixed> $config
47-
* @throws McpException
4847
*/
4948
public function __construct(protected array $config)
5049
{
51-
$this->connectClient();
5250
}
5351

54-
protected function connectClient()
52+
/**
53+
* @throws McpException
54+
*/
55+
protected function client(): MCPClient
5556
{
56-
$this->client = new McpClient($this->config);
57+
return $this->client ??= new McpClient($this->config);
5758
}
5859

5960
public function __serialize(): array
@@ -70,8 +71,6 @@ public function __unserialize(array $data): void
7071
$this->config = $data['config'];
7172
$this->only = $data['only'];
7273
$this->exclude = $data['exclude'];
73-
74-
$this->connectClient();
7574
}
7675

7776
/**
@@ -102,7 +101,7 @@ public function tools(): array
102101
{
103102
// Filter by the only and exclude preferences.
104103
$tools = array_filter(
105-
$this->client->listTools(),
104+
$this->client()->listTools(),
106105
fn (array $tool): bool =>
107106
!in_array($tool['name'], $this->exclude) &&
108107
($this->only === [] || in_array($tool['name'], $this->only)),
@@ -202,11 +201,12 @@ protected function createObjectProperty(string $name, bool $required, array $pro
202201

203202
/**
204203
* This might look counter-intuitive, but when dealing with interrupts and serialization PHP doesnt allow for MCP connectors serialization
204+
* @throws McpException
205205
*/
206206
public function invokeTool(array $item, array $arguments): mixed
207207
{
208208
$response = call_user_func(
209-
$this->client->callTool(...),
209+
$this->client()->callTool(...),
210210
$item['name'],
211211
$arguments
212212
);

src/Testing/FakeMcpTransport.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ public function __serialize(): array
4545
return [
4646
'queue' => [
4747
...$this->sent,
48-
...$this->responseQueue
48+
...$this->responseQueue,
4949
],
50-
'connected' => $this->connected
50+
'connected' => $this->connected,
5151
];
5252
}
5353

src/Workflow/Persistence/DatabasePersistence.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use function serialize;
1212
use function unserialize;
13+
use function base64_decode;
1314

1415
class DatabasePersistence implements PersistenceInterface
1516
{
@@ -33,17 +34,32 @@ public function save(string $workflowId, WorkflowInterrupt $interrupt): void
3334
]);
3435
}
3536

37+
/**
38+
* @throws WorkflowException
39+
*/
3640
public function load(string $workflowId): WorkflowInterrupt
3741
{
3842
$stmt = $this->pdo->prepare("SELECT interrupt FROM {$this->table} WHERE workflow_id = :id");
3943
$stmt->execute(['id' => $workflowId]);
40-
$result = $stmt->fetch();
44+
$record = $stmt->fetch();
4145

42-
if (!$result) {
46+
if (!$record) {
4347
throw new WorkflowException("No saved workflow found for ID: {$workflowId}.");
4448
}
4549

46-
return unserialize($result['interrupt']);
50+
$interruptData = @unserialize(
51+
base64_decode((string) $record['interrupt'], true)
52+
);
53+
54+
if ($interruptData === false) {
55+
$interruptData = unserialize($record['interrupt']); // This makes sure that previous records still work
56+
}
57+
58+
if ($interruptData === false) {
59+
throw new WorkflowException("Failed to unserialize saved workflow for ID: {$workflowId}.");
60+
}
61+
62+
return $interruptData;
4763
}
4864

4965
public function delete(string $workflowId): void

src/Workflow/Persistence/EloquentPersistence.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ public function save(string $workflowId, WorkflowInterrupt $interrupt): void
3333
]);
3434
}
3535

36+
/**
37+
* @throws WorkflowException
38+
*/
3639
public function load(string $workflowId): WorkflowInterrupt
3740
{
3841
/** @var Model&object{interrupt: string} $model */

tests/MCP/McpConnectorTest.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ public function testCallableMcpToolsIsSerializable(): void
7575

7676
// Test serialization
7777
$serialized = serialize($callable);
78-
$this->assertIsString($serialized);
7978

8079
// Test unserialization
8180
$unserialized = unserialize($serialized);
@@ -99,7 +98,7 @@ public function testInvokeToolStaticMethodCreatesNewInstance(): void
9998
['type' => 'text', 'text' => 'The result is 42'],
10099
],
101100
],
102-
]
101+
],
103102
]);
104103

105104

@@ -136,7 +135,7 @@ public function testInvokeToolThrowsExceptionOnError(): void
136135
'error' => [
137136
'message' => 'Tool execution failed',
138137
],
139-
]
138+
],
140139
]
141140
);
142141

@@ -259,7 +258,7 @@ public function testFakeTransportToolCalling(): void
259258
['type' => 'text', 'text' => 'The result is 42'],
260259
],
261260
],
262-
]
261+
],
263262
]
264263
);
265264

0 commit comments

Comments
 (0)