@evref-bl/pharo-mcp 1.5.1 → 2.1.0
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 +18 -13
- package/node/installer.js +9 -7
- package/package.json +1 -1
- package/templates/pharo-references/debugging.md +52 -129
- package/templates/pharo-references/getting-started.md +13 -5
- package/templates/pharo-references/pharo-coding-rules.md +1 -1
- package/templates/pharo-references/pharo-coding-style.md +2 -0
- package/templates/pharo-references/safety-and-ecosystem.md +106 -39
- package/templates/pharo-references/tool-reference.md +126 -206
- package/templates/pharo-references/troubleshooting.md +20 -12
- package/templates/pharo-references/using-pharo-mcp.md +50 -34
- package/templates/pharo-skills/pharo-code-profiling/SKILL.md +205 -0
- package/templates/pharo-skills/pharo-code-profiling/agents/openai.yaml +4 -0
- package/templates/pharo-skills/pharo-image-git-handoff/SKILL.md +3 -0
- package/templates/pharo.AGENTS.md +3 -1
- package/templates/pharo-references/debugger-driven-development.md +0 -101
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
# MCP for Pharo
|
|
2
|
+
|
|
3
|
+
[](https://github.com/pharo-project/Pharo)
|
|
2
4
|
[](https://github.com/Evref-BL/MCP/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush)
|
|
3
5
|
[](https://coveralls.io/github/Evref-BL/MCP?branch=main)
|
|
4
6
|
|
|
5
|
-
# MCP for Pharo
|
|
6
|
-
|
|
7
7
|
MCP is an in-image [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
8
8
|
server for Pharo. It lets MCP clients inspect and change the running image
|
|
9
9
|
through Pharo-aware tools for packages, classes, methods, tests, repositories,
|
|
@@ -15,8 +15,10 @@ files as plain text.
|
|
|
15
15
|
|
|
16
16
|
## Supported Versions
|
|
17
17
|
|
|
18
|
-
Pharo 12, 13, and
|
|
19
|
-
|
|
18
|
+
Pharo 12, 13, 14, and 15 are supported.
|
|
19
|
+
|
|
20
|
+
Protocol revisions `2025-03-26`, `2025-06-18`, `2025-11-25` and `2026-07-28`
|
|
21
|
+
are supported, each answered in its own shape.
|
|
20
22
|
|
|
21
23
|
## Install And Start
|
|
22
24
|
|
|
@@ -26,17 +28,20 @@ Load MCP in a supported image:
|
|
|
26
28
|
Metacello new
|
|
27
29
|
baseline: 'MCP';
|
|
28
30
|
repository: 'github://Evref-BL/MCP:main/src';
|
|
31
|
+
onConflictUseIncoming;
|
|
29
32
|
load.
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
Start the Streamable HTTP server:
|
|
33
36
|
|
|
34
37
|
```smalltalk
|
|
35
|
-
|
|
36
|
-
mcp port: 4000.
|
|
37
|
-
mcp start.
|
|
38
|
+
MCP startOnPort: 4000.
|
|
38
39
|
```
|
|
39
40
|
|
|
41
|
+
That answers the server already on 4000 when the image has one, so running it
|
|
42
|
+
again after a restart is safe. `MCP allServers` lists what the image holds, and
|
|
43
|
+
`Library → MCP Servers` in the world menu shows the same list.
|
|
44
|
+
|
|
40
45
|
Connect a local MCP client to `http://127.0.0.1:4000`. Client configuration
|
|
41
46
|
formats differ; see [Getting started](templates/pharo-references/getting-started.md) for setup
|
|
42
47
|
and first calls.
|
|
@@ -57,10 +62,10 @@ Install the guide, local references, workflow skills, and direct MCP
|
|
|
57
62
|
configuration for an agent host into the current project:
|
|
58
63
|
|
|
59
64
|
```sh
|
|
60
|
-
npx @evref-bl/pharo-mcp install --host
|
|
65
|
+
npx @evref-bl/pharo-mcp install --host claude
|
|
61
66
|
```
|
|
62
67
|
|
|
63
|
-
Use `--host
|
|
68
|
+
Use `--host codex` or `--host opencode` for those hosts. The direct MCP
|
|
64
69
|
configuration expects port `4000`; update it when the image uses another port.
|
|
65
70
|
|
|
66
71
|
Node integrations that provide their own MCP transport can install only the
|
|
@@ -74,7 +79,7 @@ installGuidance({ host: "codex", cwd: process.cwd() });
|
|
|
74
79
|
|
|
75
80
|
## Contributing
|
|
76
81
|
|
|
77
|
-
Use Pharo 14 for normal development and preserve Pharo 12
|
|
78
|
-
Live behavior must be verified in an image; source inspection
|
|
79
|
-
enough. Start with [AGENTS.md](AGENTS.md) and
|
|
82
|
+
Use Pharo 14 for normal development and preserve Pharo 12, 13 and 15
|
|
83
|
+
compatibility. Live behavior must be verified in an image; source inspection
|
|
84
|
+
alone is not enough. Start with [AGENTS.md](AGENTS.md) and
|
|
80
85
|
[MCP verification](docs/mcp-verification.md).
|
package/node/installer.js
CHANGED
|
@@ -44,9 +44,11 @@ function filesIn(directory) {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function directoryPlan(sourceRelativePath, targetRelativePath) {
|
|
47
|
+
function directoryPlan(sourceRelativePath, targetRelativePath, host) {
|
|
48
48
|
const sourceDirectory = path.join(templateDirectory(), sourceRelativePath);
|
|
49
|
-
return filesIn(sourceDirectory).
|
|
49
|
+
return filesIn(sourceDirectory).filter((source) =>
|
|
50
|
+
host === "codex" || !source.endsWith(`${path.sep}agents${path.sep}openai.yaml`)
|
|
51
|
+
).map((source) => ({
|
|
50
52
|
source,
|
|
51
53
|
target: path.join(targetRelativePath, path.relative(sourceDirectory, source)),
|
|
52
54
|
}));
|
|
@@ -59,17 +61,17 @@ function filePlan(sourceRelativePath, targetRelativePath) {
|
|
|
59
61
|
}];
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
function guidancePlan(configuration) {
|
|
64
|
+
function guidancePlan(configuration, host) {
|
|
63
65
|
return [
|
|
64
66
|
...filePlan("pharo.AGENTS.md", path.join(configuration.directory, "pharo.AGENTS.md")),
|
|
65
|
-
...directoryPlan("pharo-skills", path.join(configuration.directory, "skills")),
|
|
67
|
+
...directoryPlan("pharo-skills", path.join(configuration.directory, "skills"), host),
|
|
66
68
|
...directoryPlan("pharo-references", path.join(configuration.directory, "pharo-references")),
|
|
67
69
|
];
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
function fullPlan(configuration) {
|
|
72
|
+
function fullPlan(configuration, host) {
|
|
71
73
|
const [source, target] = configuration.configuration;
|
|
72
|
-
return [...guidancePlan(configuration), ...filePlan(source, target)];
|
|
74
|
+
return [...guidancePlan(configuration, host), ...filePlan(source, target)];
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
function absolutePlan(cwd, plan) {
|
|
@@ -129,7 +131,7 @@ function writeGuide({ target, content }) {
|
|
|
129
131
|
function prepare(options, direct) {
|
|
130
132
|
const cwd = path.resolve(options.cwd ?? process.cwd());
|
|
131
133
|
const configuration = hostConfiguration(options.host);
|
|
132
|
-
const plan = absolutePlan(cwd, direct ? fullPlan(configuration) : guidancePlan(configuration));
|
|
134
|
+
const plan = absolutePlan(cwd, direct ? fullPlan(configuration, options.host) : guidancePlan(configuration, options.host));
|
|
133
135
|
const guide = guidePlan(cwd, configuration);
|
|
134
136
|
assertCompatible(plan);
|
|
135
137
|
return { configuration, cwd, guide, plan };
|
package/package.json
CHANGED
|
@@ -1,147 +1,70 @@
|
|
|
1
1
|
# Debugging Tools
|
|
2
2
|
|
|
3
|
-
Applies when using MCP-Pharo to
|
|
4
|
-
|
|
5
|
-
state.
|
|
3
|
+
Applies when using MCP-Pharo to watch values while code runs, or to see what
|
|
4
|
+
debuggers a person has open.
|
|
6
5
|
|
|
7
6
|
## Goal
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
See what running code is doing without guessing from source and without driving
|
|
9
|
+
the Morphic debugger by hand.
|
|
11
10
|
|
|
12
11
|
Debugger tools are discoverable, not part of the default static surface.
|
|
13
12
|
|
|
14
13
|
## Discovery Flow
|
|
15
14
|
|
|
16
|
-
1. Use `tool_search` with `
|
|
17
|
-
tools.
|
|
15
|
+
1. Use `tool_search` with a query such as `watch` or `debugger`.
|
|
18
16
|
2. Use `tool_get` for the exact schema of the tool you plan to call.
|
|
19
17
|
3. If the current client exposes a catalog bridge, use `tool_call` to invoke
|
|
20
|
-
the selected
|
|
21
|
-
|
|
18
|
+
the selected tool by name. Otherwise use the callable form exposed by the
|
|
19
|
+
current client.
|
|
22
20
|
|
|
23
|
-
##
|
|
21
|
+
## Tool Map
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- Clear temporary breakpoints and forget agent-owned sessions when the task is
|
|
30
|
-
done.
|
|
31
|
-
- Report the exact debugger tool names used and the final session state.
|
|
23
|
+
| Tool | Use |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `debug_watch` | Record what variables hold while an expression runs, without stopping it. |
|
|
26
|
+
| `debug_search` | Answer the debuggers open in the image, read-only. |
|
|
32
27
|
|
|
33
|
-
|
|
28
|
+
Neither tool keeps anything. No session is started, attached or registered, so
|
|
29
|
+
there is no reference to carry between calls and nothing to clean up.
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
code.
|
|
37
|
-
- Do not reuse frame or variable references after stepping, restarting,
|
|
38
|
-
resuming, terminating, or editing.
|
|
39
|
-
- Do not leave breakpoints or captured sessions behind without reporting them.
|
|
40
|
-
- Do not use debugger editing as a substitute for normal source tools when
|
|
41
|
-
there is no paused debugger state.
|
|
31
|
+
## Watching Values
|
|
42
32
|
|
|
43
|
-
|
|
33
|
+
`debug_watch` is print debugging without editing the method. Name the methods to
|
|
34
|
+
probe, the variables to record, and the expression to run. Every assignment to a
|
|
35
|
+
named variable is recorded as it happens, the expression runs to completion, and
|
|
36
|
+
the probes are removed before the call answers.
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
If the test passes, there is no debugger session. If it fails or errors, use the
|
|
79
|
-
returned `sessionId` and `state`.
|
|
80
|
-
|
|
81
|
-
Use `debug_candidate_search` when a human already opened a debugger. It returns
|
|
82
|
-
unattached candidates with identifying details. Attach by passing the
|
|
83
|
-
candidate's `candidateRef` to `debug_candidate_attach`.
|
|
84
|
-
|
|
85
|
-
Use `debug_session_remove` when you are done. Removing an agent-owned captured
|
|
86
|
-
session can terminate its worker process. Removing an attached human debugger
|
|
87
|
-
only removes it from the MCP registry.
|
|
88
|
-
|
|
89
|
-
## State And References
|
|
90
|
-
|
|
91
|
-
Treat `stateId`, `frameRef`, and `variableRef` values as state-scoped opaque
|
|
92
|
-
references. After a debug-session control tool or `debug_method_update`, old
|
|
93
|
-
frame and variable refs can be stale. Use the new returned state before
|
|
94
|
-
evaluating, expanding variables, or controlling execution again.
|
|
95
|
-
|
|
96
|
-
Use `debug_state_get` as the main context-loading tool. Keep stack and variable
|
|
97
|
-
limits small first, then expand details with `debug_variable_get` only when needed.
|
|
98
|
-
|
|
99
|
-
Use `debug_expression_evaluate` only for expressions that need the selected frame's
|
|
100
|
-
receiver or temporaries. Prefer normal code tools for project edits.
|
|
101
|
-
|
|
102
|
-
## Control
|
|
103
|
-
|
|
104
|
-
Use `debug_session_step_into`, `debug_session_step_over`,
|
|
105
|
-
`debug_session_step_through`, `debug_session_restart`,
|
|
106
|
-
`debug_session_resume`, and `debug_session_terminate` for control actions.
|
|
107
|
-
Control tools can return a `debug_state_get` snapshot when execution pauses.
|
|
108
|
-
Set `returnState=true` when the next step needs that snapshot inline;
|
|
109
|
-
otherwise call `debug_state_get` after the control action.
|
|
110
|
-
When the user asks for a bounded action, such as "step into twice", perform
|
|
111
|
-
those control calls and stop.
|
|
112
|
-
|
|
113
|
-
For externally attached debuggers, control should operate through the attached
|
|
114
|
-
debugger controller so the visible debugger remains the owner of its UI. Do not
|
|
115
|
-
manipulate debugger windows or contexts with general `image_evaluate` code.
|
|
116
|
-
|
|
117
|
-
## Breakpoints
|
|
118
|
-
|
|
119
|
-
Use the `debug_breakpoint_*` tools for temporary method-entry or
|
|
120
|
-
source-interval DebugPoint breakpoints. Clear breakpoints when the debugging
|
|
121
|
-
task ends.
|
|
122
|
-
|
|
123
|
-
File/line breakpoints are intentionally not emulated. Resolve source intervals
|
|
124
|
-
from the relevant method when source-interval precision is needed.
|
|
125
|
-
|
|
126
|
-
## Debugger-Driven Development
|
|
127
|
-
|
|
128
|
-
When a debug state offers repair actions, prefer `debug_method_update` over separate
|
|
129
|
-
manual edits. It can create missing methods or recompile stub/selected methods,
|
|
130
|
-
formats the compiled method, reports critiques, and proceeds when the edit is
|
|
131
|
-
accepted.
|
|
132
|
-
|
|
133
|
-
Read [Debugger-Driven Development](debugger-driven-development.md) before using
|
|
134
|
-
`debug_method_update` for missing methods, `subclassResponsibility`,
|
|
135
|
-
`shouldBeImplemented`, `notYetImplemented`, or iterative repair workflows.
|
|
136
|
-
|
|
137
|
-
## Reporting
|
|
138
|
-
|
|
139
|
-
When finishing debugger work, report:
|
|
140
|
-
|
|
141
|
-
- how the session was obtained: capture, test, discovered debugger, or attached
|
|
142
|
-
debugger;
|
|
143
|
-
- debugger tools called;
|
|
144
|
-
- final session outcome: completed, paused, running, terminated, forgotten, or
|
|
145
|
-
still open;
|
|
146
|
-
- breakpoints created, cleared, or left in place;
|
|
147
|
-
- cleanup performed or still needed.
|
|
38
|
+
Name no variable and each method's arguments are recorded as it is entered.
|
|
39
|
+
Both `method` and `variable` take one value or a list, and a probe goes on every
|
|
40
|
+
pair that exists, so a variable a method never assigns simply has no series there.
|
|
41
|
+
|
|
42
|
+
Reach for it whenever the question is what a value became, rather than where to
|
|
43
|
+
intervene.
|
|
44
|
+
|
|
45
|
+
## Seeing A Person's Debuggers
|
|
46
|
+
|
|
47
|
+
`debug_search` answers the debuggers open in the image: each one's name, the
|
|
48
|
+
exception it stopped on, and the frames nearest the stop with what those frames
|
|
49
|
+
hold. Pass a `query` to keep only the debuggers whose name or exception matches.
|
|
50
|
+
|
|
51
|
+
It is a query and nothing else. It attaches to nothing, changes nothing, and
|
|
52
|
+
remembers nothing, so the picture it gives is whatever is open at that moment.
|
|
53
|
+
Ask again for a fresh one.
|
|
54
|
+
|
|
55
|
+
Act on what it shows with the ordinary tools: read the method with `method_get`,
|
|
56
|
+
change it with `method_compile`, run something with `image_evaluate`. Stepping,
|
|
57
|
+
resuming and repairing from inside a frame belong to the person at the debugger,
|
|
58
|
+
not to the agent.
|
|
59
|
+
|
|
60
|
+
## To Debug Your Own Code
|
|
61
|
+
|
|
62
|
+
Do not open a debugger for it. Call the tool that runs the code and read the
|
|
63
|
+
failure it reports: it names the frames nearest the error and the values they
|
|
64
|
+
held. When that is not enough, `debug_watch` shows how a value got there.
|
|
65
|
+
|
|
66
|
+
## Do Not
|
|
67
|
+
|
|
68
|
+
- Do not drive debugger windows or mutate contexts through general
|
|
69
|
+
`image_evaluate` code.
|
|
70
|
+
- Do not resume, step or terminate a person's debugger. It is theirs.
|
|
@@ -5,7 +5,7 @@ connecting a client.
|
|
|
5
5
|
|
|
6
6
|
## Requirements
|
|
7
7
|
|
|
8
|
-
- Pharo 12, 13, or
|
|
8
|
+
- Pharo 12, 13, 14, or 15
|
|
9
9
|
- An MCP client that supports Streamable HTTP directly or through a local bridge
|
|
10
10
|
- Network access from the client to the image host
|
|
11
11
|
|
|
@@ -58,6 +58,14 @@ Dependencies can select the same group with `loads: #( 'Core' )`.
|
|
|
58
58
|
|
|
59
59
|
## Start And Stop
|
|
60
60
|
|
|
61
|
+
```smalltalk
|
|
62
|
+
mcp := MCP startOnPort: 4000.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That answers the server already on 4000 when the image has one, rather than
|
|
66
|
+
failing on the port it holds. Build one by hand when it needs configuring
|
|
67
|
+
before it starts:
|
|
68
|
+
|
|
61
69
|
```smalltalk
|
|
62
70
|
mcp := MCP new.
|
|
63
71
|
mcp port: 4000.
|
|
@@ -121,16 +129,16 @@ tool_get
|
|
|
121
129
|
Then inspect the image with focused read-only tools such as:
|
|
122
130
|
|
|
123
131
|
```text
|
|
124
|
-
package_search
|
|
125
132
|
class_search
|
|
126
133
|
class_get
|
|
127
|
-
|
|
134
|
+
method_search
|
|
128
135
|
method_source_search
|
|
129
|
-
|
|
130
|
-
method_sender_search
|
|
136
|
+
method_reference_search
|
|
131
137
|
method_get
|
|
132
138
|
```
|
|
133
139
|
|
|
140
|
+
`package_search` and the specialized tools are found with `tool_search`.
|
|
141
|
+
|
|
134
142
|
Before mutation, inspect the target and use a copied or disposable image.
|
|
135
143
|
Prefer dedicated tools such as `class_create`, `method_compile`, refactoring
|
|
136
144
|
tools, and `test_run` over `image_evaluate`.
|
|
@@ -100,7 +100,7 @@ over clients branching on concrete classes or internal fields.
|
|
|
100
100
|
- Do not use `getName` or `setName:`.
|
|
101
101
|
- Predicates should read as predicates: `isReady`, `hasErrors`,
|
|
102
102
|
`canHandle:`.
|
|
103
|
-
- Action selectors should use verbs: `parseRequest:`, `
|
|
103
|
+
- Action selectors should use verbs: `parseRequest:`, `addTool:`,
|
|
104
104
|
`writeResponseOn:`.
|
|
105
105
|
- Conversion selectors should start with `as`.
|
|
106
106
|
|
|
@@ -133,6 +133,8 @@ Scan for:
|
|
|
133
133
|
`thenDo:` variant would avoid the intermediate collection;
|
|
134
134
|
- sorting through conversion chains instead of sorting a result array directly;
|
|
135
135
|
- defensive type checks in private helpers that hide caller bugs;
|
|
136
|
+
- cascaded stream writes, where `stream << a; << b` says what `stream << a << b`
|
|
137
|
+
says with more punctuation, since `<<` answers the stream;
|
|
136
138
|
- wrapper methods or extensions that exist only because a collaborator might be
|
|
137
139
|
wrong someday;
|
|
138
140
|
- dense nested expressions that would be clearer with a temporary or extracted
|
|
@@ -22,10 +22,22 @@ The execution path is:
|
|
|
22
22
|
3. The concrete tool parses the request into a typed request or spec object.
|
|
23
23
|
4. The tool dispatches a command or query object.
|
|
24
24
|
5. The command uses Pharo APIs to query or mutate the image.
|
|
25
|
-
6. The tool returns a payload with `
|
|
26
|
-
`
|
|
27
|
-
`content` field; the server can also emit
|
|
28
|
-
that need programmatic results.
|
|
25
|
+
6. The tool returns a payload with `summary`, `warnings`, and either `data` or
|
|
26
|
+
`error`, with a failure flagged by the protocol's own `isError`. By default
|
|
27
|
+
this payload reaches the MCP `content` field; the server can also emit
|
|
28
|
+
`structuredContent` for clients that need programmatic results.
|
|
29
|
+
|
|
30
|
+
### Notifications
|
|
31
|
+
|
|
32
|
+
A notification is not a failed call. Pharo signals them for remarks rather than
|
|
33
|
+
faults, and every `Warning` is one. The tool boundary resumes them with the
|
|
34
|
+
value the image itself would have produced and the call proceeds, so a
|
|
35
|
+
deprecated send, or an undeclared variable during a package load, does not fail
|
|
36
|
+
it. A deprecated method called from a test does not abort the suite.
|
|
37
|
+
|
|
38
|
+
Refactoring warnings are the exception. `RBRefactoringWarning` reports a change
|
|
39
|
+
that breaks something, so it reaches the boundary unresumed and stops the call,
|
|
40
|
+
aborting a removal or a rename that `force=true` did not authorize.
|
|
29
41
|
|
|
30
42
|
```mermaid
|
|
31
43
|
sequenceDiagram
|
|
@@ -104,44 +116,66 @@ Critiques include:
|
|
|
104
116
|
The method may compile successfully and still return critiques. Treat critiques
|
|
105
117
|
as follow-up review evidence, not as transport failures.
|
|
106
118
|
|
|
107
|
-
##
|
|
119
|
+
## Rewriting Methods
|
|
120
|
+
|
|
121
|
+
`method_rewrite` uses Smalltalk AST rewrite patterns, not regex. A rule has a
|
|
122
|
+
`match` and a `replacement`, and a scope is required, so rewriting everything is
|
|
123
|
+
something a caller asks for by naming the packages rather than by leaving an
|
|
124
|
+
argument out.
|
|
108
125
|
|
|
109
|
-
|
|
110
|
-
|
|
126
|
+
A metavariable starts with a backquote and stands for whatever is in its place.
|
|
127
|
+
`` `@receiver `` matches one expression, however big: the same rule rewrites
|
|
128
|
+
`anObject notNil` and `(anObject foo) notNil`. **The names must be the same on
|
|
129
|
+
both sides** — a name that appears only in `replacement` is bound to nothing.
|
|
111
130
|
|
|
112
|
-
The default mode is preview
|
|
131
|
+
The default mode is preview, which carries the old and new source of every
|
|
132
|
+
change:
|
|
113
133
|
|
|
114
134
|
```json
|
|
115
135
|
{
|
|
116
136
|
"rules": [
|
|
117
137
|
{
|
|
118
|
-
"
|
|
119
|
-
"
|
|
138
|
+
"match": "`@receiver notNil",
|
|
139
|
+
"replacement": "`@receiver isNotNil"
|
|
120
140
|
}
|
|
121
141
|
],
|
|
122
|
-
"
|
|
142
|
+
"scope": { "packages": ["MyPackage"] }
|
|
123
143
|
}
|
|
124
144
|
```
|
|
125
145
|
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
A metavariable stands for a block just as readily, which is how a rule drops
|
|
147
|
+
one branch of a conditional:
|
|
128
148
|
|
|
129
149
|
```json
|
|
130
150
|
{
|
|
131
151
|
"rules": [
|
|
132
152
|
{
|
|
133
|
-
"
|
|
134
|
-
"
|
|
153
|
+
"match": "`@receiver ifTrue: [ `@body ] ifFalse: [ nil ]",
|
|
154
|
+
"replacement": "`@receiver ifTrue: [ `@body ]"
|
|
135
155
|
}
|
|
136
156
|
],
|
|
137
|
-
"
|
|
138
|
-
"apply": true,
|
|
139
|
-
"expectedChangeSetHash": 123456
|
|
157
|
+
"scope": { "packages": ["MyPackage"] }
|
|
140
158
|
}
|
|
141
159
|
```
|
|
142
160
|
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
Add `apply` to make the changes. One call is enough; preview first only when
|
|
162
|
+
you want to read them before they land. `history_entry_revert` undoes a rewrite
|
|
163
|
+
that turned out wrong.
|
|
164
|
+
|
|
165
|
+
Any rewrite rule stands for its own patterns, so its name can be given instead
|
|
166
|
+
of writing them out. That includes Pharo's own, not only MCP's:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"ruleClasses": ["MCPCollectionThenDoRule"],
|
|
171
|
+
"scope": { "packages": ["MyPackage"] },
|
|
172
|
+
"apply": true
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Rules that report a critique are not applied by the tools that compile. A
|
|
177
|
+
compile reports what it would change; changing it is this tool's job, and the
|
|
178
|
+
caller asks.
|
|
145
179
|
|
|
146
180
|
## Tests And Coverage
|
|
147
181
|
|
|
@@ -189,39 +223,72 @@ live image back to Tonel/Git.
|
|
|
189
223
|
|
|
190
224
|
## Debugging
|
|
191
225
|
|
|
192
|
-
Debugger tools are discoverable through the `debugging` group. They
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
debuggers.
|
|
196
|
-
|
|
197
|
-
Treat debugger state references as opaque and state-scoped. After stepping,
|
|
198
|
-
resuming, restarting, terminating, or editing from a debug state, use the newly
|
|
199
|
-
returned state before expanding variables or evaluating in a frame again.
|
|
226
|
+
Debugger tools are discoverable through the `debugging` group. They keep no
|
|
227
|
+
state: `debug_watch` installs non-halting probes and removes them before it
|
|
228
|
+
answers, and `debug_search` only reads the debuggers a person has open.
|
|
200
229
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
proceeding a repaired computation.
|
|
230
|
+
A debugger somebody opened belongs to them. Read it, then act with the ordinary
|
|
231
|
+
class and method tools; do not step, resume or terminate it.
|
|
204
232
|
|
|
205
233
|
## Evaluation Escape Hatch
|
|
206
234
|
|
|
207
|
-
`image_evaluate` runs arbitrary Smalltalk
|
|
208
|
-
|
|
235
|
+
`image_evaluate` runs arbitrary Smalltalk in the running image without saving
|
|
236
|
+
it. It is useful for short inspection or glue code when no dedicated tool
|
|
209
237
|
exists.
|
|
210
238
|
|
|
211
239
|
Prefer a dedicated tool when one exists, because the dedicated tools validate
|
|
212
240
|
input, return structured result data, and often use safer Pharo APIs.
|
|
213
241
|
|
|
242
|
+
Compiling source is one of those cases. Method source in the image separates
|
|
243
|
+
lines with CR, and `method_compile` normalizes what it is given; a bare
|
|
244
|
+
`compile:` from `image_evaluate` stores whatever it receives, so source written
|
|
245
|
+
with LF compares unequal to every other method in the image. Use
|
|
246
|
+
`method_compile` for a method, and `withInternalLineEndings` if you must compile
|
|
247
|
+
source by hand.
|
|
248
|
+
|
|
214
249
|
## Observability And UI
|
|
215
250
|
|
|
216
|
-
The
|
|
251
|
+
The servers an image holds are listed under `Library → MCP Servers` in the
|
|
252
|
+
world menu, and on the `Servers` tab of an inspected `MCP` class. From there a
|
|
253
|
+
server can be started, stopped, or opened in its dashboard, and a new one
|
|
254
|
+
created on a port, where 0 asks for a free one. The tool catalog sits beside it
|
|
255
|
+
under `Library → MCP Tool Catalog`, since it describes the image rather than
|
|
256
|
+
any one server. The same list in a script:
|
|
217
257
|
|
|
218
|
-
|
|
258
|
+
```smalltalk
|
|
259
|
+
MCP allServers
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
It is taken from the heap rather than from a registry, so a server is never
|
|
263
|
+
kept alive for being listable, and one that is still holding a port after its
|
|
264
|
+
owner forgot it is shown rather than hidden.
|
|
265
|
+
|
|
266
|
+
To reach the server on a port, whether or not this script is the one that
|
|
267
|
+
started it, ask for the port rather than for a new server:
|
|
268
|
+
|
|
269
|
+
```smalltalk
|
|
270
|
+
MCP startOnPort: 4000
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
That answers the server already on 4000, starting it if it was stopped, and
|
|
274
|
+
makes one only when the image has none there. Starting a second server on a
|
|
275
|
+
taken port fails after a couple of seconds, and the error now says when the
|
|
276
|
+
port is held by another MCP in the same image.
|
|
277
|
+
|
|
278
|
+
An inspected `MCP` object has two Spec tabs. The dashboard runs the server:
|
|
279
|
+
|
|
280
|
+
- server status, endpoint and port
|
|
219
281
|
- debug mode
|
|
220
|
-
-
|
|
221
|
-
|
|
282
|
+
- every tool the server could run, with `Enabled` for whether it has the tool
|
|
283
|
+
at all and `Listed` for whether `tools/list` shows it; an unlisted tool is
|
|
284
|
+
still found by `tool_search` and still runs
|
|
285
|
+
|
|
286
|
+
The observability tab shows what the server recorded about itself:
|
|
287
|
+
|
|
222
288
|
- per-tool timing metrics
|
|
223
289
|
- traces for errors, outliers, and output overruns
|
|
224
290
|
- recent logs
|
|
291
|
+
- auto-refresh while the tab is displayed
|
|
225
292
|
|
|
226
293
|
MCP starts with the built-in JSON observability backend enabled. Disable it for
|
|
227
294
|
a specific server when its local metrics, traces, and logs are not wanted:
|
|
@@ -251,5 +318,5 @@ mcp useOpenTelemetryObservability
|
|
|
251
318
|
|
|
252
319
|
The core baseline loads PharoBackwardCompatibility, JRPC, and PCRE2.
|
|
253
320
|
OpenTelemetry is loaded only by the optional `Telemetry` group. CI covers
|
|
254
|
-
Pharo 12, 13, and
|
|
255
|
-
backports supported APIs to older images.
|
|
321
|
+
Pharo 12, 13, 14, and 15. Code should target the Pharo 14 API;
|
|
322
|
+
PharoBackwardCompatibility backports supported APIs to older images.
|