Skip to content

Commit 83e53cd

Browse files
authored
Merge pull request #14 from CorporateSmalltalkConsultingLtd/osprocess-gui-fix
Update MCP-Server to v11 with OSProcess for GUI responsiveness
2 parents 687b6b6 + 6c3c16a commit 83e53cd

File tree

3 files changed

+72
-67
lines changed

3 files changed

+72
-67
lines changed

ClaudeCuis.image

8.38 MB
Binary file not shown.

MCP-Server.pck.st

Lines changed: 67 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1-
'From Cuis7.7 [latest update: #7777] on 20 January 2026 at 5:17:14 pm'!
1+
'From Cuis7.7 [latest update: #7777] on 21 January 2026 at 6:20:31 pm'!
22
'Description MCP Server for Claude Code integration.
33

44
Implements the Model Context Protocol (MCP) over stdio with JSON-RPC 2.0.
55
Uses JSON Lines protocol (one JSON message per line, no Content-Length headers).
66
Provides 12 tools for Smalltalk interaction (saveImage intentionally excluded).
77

8+
REQUIRES: OSProcess package for async stdio support (GUI responsive during MCP wait).
9+
Uses BufferedAsyncFileReadStream which provides semaphore-based waiting,
10+
allowing the VM scheduler to run other processes (including the UI event loop)
11+
while the MCP server waits for input from Claude Code.
12+
813
Usage:
9-
1. Load this package into a Cuis image
10-
2. Save the image
11-
3. Run with --mcp flag:
14+
1. Load JSON and OSProcess packages into a Cuis image
15+
2. Load this package (MCP-Server)
16+
3. Save the image
17+
4. Run with --mcp flag:
1218
squeak myImage.image --mcp
1319

1420
Claude Code config (~/.claude.json):
@@ -22,7 +28,9 @@ Claude Code config (~/.claude.json):
2228
}
2329
}
2430
'!
25-
!provides: 'MCP-Server' 1 4!
31+
!provides: 'MCP-Server' 1 11!
32+
!requires: 'JSON' nil nil nil!
33+
!requires: 'OSProcess' nil nil nil!
2634
SystemOrganization addCategory: #'MCP-Server'!
2735

2836

@@ -47,24 +55,22 @@ MCPTransport class
4755
instanceVariableNames: ''!
4856

4957

50-
!MCPServer methodsFor: 'initialization' stamp: ''!
58+
!MCPServer methodsFor: 'initialization' stamp: 'jmm 1/26/2026 11:00'!
5159
initialize
5260
transport := MCPTransport new.
5361
running := false.! !
5462

55-
!MCPServer methodsFor: 'running' stamp: ''!
63+
!MCPServer methodsFor: 'running' stamp: 'jmm 1/26/2026 11:00'!
5664
run
57-
| temp1 temp2 |
65+
| request response |
5866
running := true.
5967
[ running ] whileTrue: [
60-
temp1 := nil.
61-
temp2 := nil.
62-
temp1 := transport readMessage.
63-
temp1
68+
request := transport readMessage.
69+
request
6470
ifNil: [ running := false ]
6571
ifNotNil: [
66-
temp2 := self handleRequest: temp1.
67-
temp2 ifNotNil: [ transport writeMessage: (Json render: temp2) ]]].! !
72+
response := self handleRequest: request.
73+
response ifNotNil: [ transport writeMessage: (Json render: response) ]]].! !
6874

6975
!MCPServer methodsFor: 'running' stamp: ''!
7076
stop
@@ -779,7 +785,7 @@ toolClassesInCategory: arg1
779785
argm3_5 name ]) asArray sorted.
780786
^ Json render: temp4.! !
781787

782-
!MCPServer methodsFor: 'tool implementations' stamp: ''!
788+
!MCPServer methodsFor: 'tool implementations' stamp: 'jmm 1/26/2026 09:30'!
783789
toolDefineClass: arg1
784790
| temp2 |
785791
temp2 := arg1
@@ -807,7 +813,7 @@ toolDefineMethod: arg1
807813
at: temp2 asSymbol
808814
ifAbsent: [ self error: 'Class not found: ' , temp2 ].
809815
temp5
810-
compile: temp3
816+
compileSilently: temp3
811817
classified: temp4.
812818
^ 'Method defined successfully'.! !
813819

@@ -924,25 +930,52 @@ toolSubclasses: arg1
924930
argm3_5 name ]) asArray sorted.
925931
^ Json render: temp4.! !
926932

927-
!MCPServer class methodsFor: 'system startup' stamp: ''!
928-
startUp: arg1
929-
| temp2 |
930-
arg1 ifFalse: [ ^ self ].
931-
SourceFiles
932-
at: 2
933-
put: nil.
934-
temp2 := Smalltalk startUpArguments.
935-
(temp2 includes: '--mcp') ifTrue: [ self startServer ].! !
933+
!MCPServer class methodsFor: 'system startup' stamp: 'jmm 1/26/2026 11:00'!
934+
startUp: resuming
935+
| args |
936+
resuming ifFalse: [ ^ self ].
937+
args := Smalltalk startUpArguments.
938+
(args includes: '--mcp') ifTrue: [ self startServer ].! !
939+
940+
!MCPServer class methodsFor: 'version' stamp: 'jmm 1/26/2026 11:00'!
941+
version
942+
"Return the MCP server version number.
943+
Increment when making changes that external tools should detect.
944+
Version history:
945+
1 - Initial version
946+
2 - Fixed toolDefineMethod: to use compileSilently: for headless operation
947+
3 - (skipped)
948+
4 - Fork MCP to background process, allowing GUI to display
949+
5 - Set author initials to avoid prompt during class/method definition
950+
6 - Port to OSProcess for non-blocking stdio (GUI responsive during MCP wait)
951+
7 - Ensure ThisOSProcess is initialized before MCP transport accesses it
952+
8 - Remove debug logging that blocked UI startup
953+
9 - Simplify MCPTransport initialize
954+
10 - Add extensive logging to debug UI startup hang
955+
11 - Remove debug logging, use correct Cuis author API"
956+
^ 11! !
936957

937-
!MCPServer class methodsFor: 'instance creation' stamp: ''!
958+
!MCPServer class methodsFor: 'instance creation' stamp: 'jmm 1/26/2026 11:00'!
938959
startServer
939-
(Delay forMilliseconds: 500) wait.
940-
self new run.! !
960+
"Start MCP server in background process, allowing GUI to initialize normally"
961+
SourceFiles at: 2 put: nil. "Disable changes file for MCP mode"
962+
Utilities setAuthorName: 'ClaudeSmalltalk' initials: 'LLM'.
963+
[
964+
(Delay forMilliseconds: 500) wait.
965+
self new run
966+
] forkAt: Processor userBackgroundPriority named: 'MCP Server'.! !
941967

942-
!MCPTransport methodsFor: 'initialization' stamp: ''!
968+
!MCPTransport methodsFor: 'initialization' stamp: 'jmm 1/26/2026 11:00'!
943969
initialize
944-
stdin := StdIOReadStream stdin.
945-
stdout := StdIOWriteStream stdout.! !
970+
"Initialize using OSProcess for stdio with buffered async reads.
971+
BufferedAsyncFileReadStream uses semaphore-based waiting which
972+
allows the VM to schedule other processes (like the UI) while waiting for input."
973+
974+
| osProc |
975+
osProc := OSProcess thisOSProcess.
976+
stdin := osProc stdIn asBufferedAsyncFileReadStream.
977+
stdin setBlocking.
978+
stdout := osProc stdOut.! !
946979

947980
!MCPTransport methodsFor: 'reading' stamp: ''!
948981
readLine
@@ -994,13 +1027,8 @@ checkIfAlreadyRunningOrStoppedNoExit
9941027

9951028
!SystemDictionary methodsFor: '*MCP-Server' stamp: ''!
9961029
openSourcesAndChanges
997-
| temp1 temp2 temp3 temp4 temp5 temp6 temp7 temp8 temp9 temp11 |
998-
temp6 := false.
999-
temp8 := 2.
1000-
[
1001-
temp8 <= 100 and: [ (temp7 := self getSystemAttribute: temp8) notNil ]] whileTrue: [
1002-
(temp7 = '--mcp' or: [ temp7 = '-d' ]) ifTrue: [ temp6 := true ].
1003-
temp8 := temp8 + 1 ].
1030+
"Always run without changes file - allows image to be distributed without .changes"
1031+
| temp1 temp9 temp3 |
10041032
temp1 := SourceFiles at: 1.
10051033
temp1 ifNil: [
10061034
temp9 := self defaultSourcesName asFullFileEntry.
@@ -1012,36 +1040,9 @@ openSourcesAndChanges
10121040
(temp1 isNil and: [ Preferences at: #warnIfNoSourcesFile ]) ifTrue: [
10131041
temp3 := 'Cuis cannot locate the sources file named ' , temp9 pathName , '.' , String newLineString , 'Please check that the file is properly named and is in the same directory as this image.'.
10141042
self logStartupError: temp3 ].
1015-
temp6 ifTrue: [
1016-
SourceFiles := Array
1017-
with: temp1
1018-
with: nil.
1019-
^ self ].
1020-
temp2 := SourceFiles at: 2.
1021-
temp2 ifNil: [
1022-
temp9 := self defaultChangesName asFullFileEntry.
1023-
temp5 := temp9 pathName.
1024-
temp9 exists
1025-
ifTrue: [
1026-
temp4 := self lastQuitLogPosition.
1027-
temp4 > 0 ifTrue: [
1028-
temp9 readStreamDo: [ :argm11_12 |
1029-
argm11_12 position: temp4.
1030-
temp11 := argm11_12 nextChunk ].
1031-
((temp11 beginsWith: self tagHeader) and: [ temp11 includesSubString: 'priorSource: ' ]) ifFalse: [
1032-
(Preferences at: #warnIfNoChangesFile) ifTrue: [ self logStartupError: 'Incorrect changes file: ' , temp5 , String newLineString , 'Missing code will be decompiled' , String newLineString , 'New source code will not be saved' ].
1033-
temp9 := nil ]]]
1034-
ifFalse: [
1035-
(Preferences at: #warnIfNoChangesFile) ifTrue: [ self logStartupError: 'Could not find changes file: ' , temp5 , String newLineString , 'Missing code will be decompiled' , String newLineString , 'New source code will not be saved' ].
1036-
temp9 := nil ].
1037-
temp9 ifNotNil: [
1038-
temp2 := [ temp9 appendStream ]
1039-
on: FileWriteError
1040-
do: [ self logStartupError: 'Could not write to changes file: ' , temp5 , String newLineString , 'Changes file will not be used.' , String newLineString , 'Missing code will be decompiled' , String newLineString , 'New source code will not be saved' ]]].
1041-
ChangesInitialFileSize := temp2 ifNotNil: [ temp2 position ].
10421043
SourceFiles := Array
10431044
with: temp1
1044-
with: temp2.! !
1045+
with: nil.! !
10451046

10461047
"Register MCPServer for startup"!
10471048
Smalltalk addToStartUpList: MCPServer!

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ Developed by John M McIntosh, Corporate Smalltalk Consulting Ltd. 2026
1414
```
1515
┌─────────────┐ MCP/stdio ┌─────────────────┐
1616
│ Claude │ ◄────────────────► │ Cuis Smalltalk │
17-
│ (Desktop │ (JSON Lines) │ (headless) │
17+
│ (Desktop │ (JSON Lines) │ (with GUI) │
1818
│ or Code) │ │ MCPServer │
1919
└─────────────┘ └─────────────────┘
2020
```
2121

2222
- **Simplest setup** - No Python, no MQTT broker required
23+
- **Responsive GUI** - Cuis GUI remains responsive during MCP operations
24+
- Uses OSProcess with `BufferedAsyncFileReadStream` for non-blocking stdio
2325
- Claude spawns the Cuis image directly
2426
- 12 tools available (saveImage intentionally excluded for safety)
2527

@@ -82,6 +84,7 @@ Developed by John M McIntosh, Corporate Smalltalk Consulting Ltd. 2026
8284

8385
**For Option B (Cuis Native MCP):**
8486
- **Cuis Smalltalk VM** (Squeak VM or Cog VM)
87+
- **OSProcess package** (available via `Feature require: 'OSProcess'`)
8588
- **ClaudeCuis.image** (provided, or build your own)
8689

8790
**For Option C (Squeak Native MCP):**
@@ -148,6 +151,7 @@ If you want to build your own image instead of using the provided `ClaudeCuis.im
148151

149152
```smalltalk
150153
Feature require: 'JSON'.
154+
Feature require: 'OSProcess'.
151155
CodePackageFile installPackage: '/path/to/MCP-Server.pck.st' asFileEntry.
152156
Smalltalk saveImage.
153157
```

0 commit comments

Comments
 (0)