SmalltalkGenie-VAST

Description

An MCP server for coding in a live VASTPlatform environment

Details

Source
GitHub
Dialect
va_smalltalk (25% confidence)
License
MIT
Stars
1
Created
June 28, 2026
Updated
July 30, 2026

README excerpt

# SmalltalkGenie (VAST Platform)

Program a live **VAST Platform (VA Smalltalk)** image from an AI agent — over the
**Model Context Protocol (MCP)**, with no bridge process in between.

SmalltalkGenie is an MCP server that lives *inside* a VAST image and speaks MCP
directly over HTTP. Point an MCP client (e.g. Claude Code) at it and the agent can
define classes and methods, run tests, search the system, rename classes,
import/export applications, and save the image — all by remote control.

The metaphor: the image is the **lamp**, `GenieServer` is the **genie** inside it,
and each MCP tool call is a **wish** the genie carries out in its own world. You
never enter the lamp; you make wishes.

> This is a VAST port of [KentBeck/SmalltalkGenie](https://github.com/KentBeck/SmalltalkGenie)
> (originally for Pharo). The protocol and tool surface match; the implementation is
> rebuilt on VAST/ENVY internals — `SstHttpServletEngine` instead of Teapot,
> `EsCompiler` for `eval`, and ENVY applications in place of Pharo packages.
> See **[COMPARISON.md](COMPARISON.md)** for a tool-by-tool VAST ⇄ Pharo matrix.

> ⚠️ **Security: `eval` runs arbitrary code.** A client that can reach the server has
> the full power of the VAST process. By default the server binds to **loopback only**
> (no network access) and checks the `Origin` header; optional **token auth** and
> **dangerous-tool gating** harden it further. Run it only on a machine and image you
> trust. See **[Security](#security)**.

## Install

SmalltalkGenie ships as **Tonel** source (the `source/` tree), loaded with VAST's
Tonel support — not Metacello.

### Easiest: the configuration map (bundles every prerequisite)

The repo ships a VAST **configuration map**, `SmalltalkGenie` (`source/.configmaps`),
that lists the Genie application and requires the feature maps it needs (Refactoring
Browser, NeoJSON, SUnit, Tonel, and SST HTTP). Loading it is **two steps** — import into
the ENVY library, then load into the image:

1. **Import the map from Tonel into your ENVY library:**

   ```smalltalk
   (TonelLoader readFromPath: 'path/to/SmalltalkGenie' asPath)
       loadConfigurationMapNamed: 'SmalltalkGenie'.
   ```

   This brings the map (and the Genie application source) into the **library** — it does
   **not** load anything into the running image yet.

2. **Load it into the image:** open the **Application Configuration Maps** tool (the
   Config Maps Browser), select the `SmalltalkGenie` map, and choose **Load With Required
   Maps**. That loads Genie and every prerequisite feature map into the image.

   (Programmatic equivalent, if you prefer:
   `((Smalltalk at: #EmConfigurationMap) editionsFor: 'SmalltalkGenie') first
   loadWithRequiredMaps`.)

Those feature maps ship with VAST 2026, so the map resolves them from your library by
version.

### Manual: load just the application

If the prerequisites are already loaded — **AbtViewApplication**,
**SstHttpServletSupport**, **SUnit**, **NeoJSON** (`NeoJSONCoreApp`), **Tonel Support**,
and the **Refactoring Browser** feature (`RBRefactoringsApp` — "z.ST: Refactoring
Browser") — load the application directly:

```smalltalk
(TonelLoader readFromPath: 'path/to/SmalltalkGenie' asPath) loadAllApplications.
```

`SstHttpServletSupport` provides the HTTP servlet engine; `NeoJSON` provides the JSON
codec; the Refactoring Browser provides the scriptable refactoring engine the
refactoring tools drive.

Either path creates the **Genie** application with its `GenieServer` and `GenieSettings`
classes (plus the two `Genie*Refactoring` helper subclasses). (No "author initials"
step — that is Pharo-specific.)

## Run

```smalltalk
GenieServer current.   "starts the server on http://localhost:8088/mcp"
```

`GenieServer current` is idempotent — it starts the server if needed and answers the
running engine. `GenieServer stop` / `GenieServer restart` manage its lifecycle.

Then register it with your MCP client. For Claude Code:

```
claude mcp add --transport http genie-vast http://localhost:8088/mcp
```

Port **8088** is used so a Pharo SmalltalkGenie (which defaults to 8087) can run on
the same machine alongside it.

## Tools

The genie grants 53 wishes over MCP — 24 core tools, a packaging tool, and 28
refactorings. For how this lines up against the Pharo original tool-for-tool, see
**[COMPARISON.md](COMPARISON.md)**.

- **Code:** `eval`, `define_class`, `define_method`, `rename_class`,
  `remove_class`, `remove_method`
- **Tests:** `run_test` (structured pass/fail/error counts, by class or application)
- **Read / search:** `list_packages`, `list_classes`, `list_methods`,
  `list_extended_classes`, `get_class_source`, `get_method_source`,
  `get_class_comment`, `search_classes_like`, `search_methods_like`,
  `search_implementors`, `search_references`, `search_references_to_class`
- **Applications / settings:** `export_package`, `import_package`,
  `get_settings`, `apply_settings`
- **Persistence:** `save_image` — saves the image, optionally **gated on tests**:
  pass `test_package` / `test_class` and it saves *only* if they pass.
- **Packaging:** `create_configuration_map` — build a VAST configuration map that
  bundles applications with the required maps they need, for one-step loading.

### Refactorings

Wrapping VAST's Refactoring Browser engine, driven headlessly. New methods a
refactoring introduces are added as **Genie class extensions** (the target class's
own application is left untouched). The genie **only edits classes it owns or that
are already open editions** — a refactoring whose changes would modify the definition
or an existing method of a **core or versioned** class the genie doesn't own (for
example an image-wide sender rewrite from `rename_method` that reaches a base class)
is **refused** with a clear error, before anything is applied. To refactor such a
class, open an edition of it yourself first.

- **Variables:** `add_instance_variable`, `remove_instance_variable`,
  `add_class_variable`, `remove_class_variable`, `rename_instance_variable`,
  `rename_class_variable`, `pull_up_instance_variable`, `pull_up_class_variable`,
  `push_down_instance_variable`, `push_down_class_variable`,
  `protect_instance_variable`, `generate_variable_accessors`,
  `temporary_to_instance_variable`
- **Methods:** `rename_method`, `change_method_signature`, `pull_up_method`,
  `push_down_method`, `move_method`, `add_parameter`, `remove_parameter`,
  `inline_parameter`, `inline_all_senders`
- **Extract / inline (by source range):** `extract_method`, `extract_temporary`,
  `inline_method`, `inline_temporary`, `rename_argument_or_temporary`,
  `move_variable_definition_to_smallest_scope`

The extract/inline tools take a 1-based inclusive character range `start`..`stop`
into the method source (use `get_method_source` to get the canonical text to index
into).

**"package" means an ENVY application.** `list_packages` lists applications,
`list_classes`/`list_methods` work over an application, and `export_package` /
`import_package` write and read an application **including its sub-applications** as
an ENVY chunk file (re-loadable with `import_package` or File In).

Some tools from the Pharo original are intentionally omitted because they have no
VAST equivalent: `search_traits_like` (VAST has no traits) and `install_project`
(Metacello; use `import_package` instead). `rename_class` is provided (hand-built).

A handful of upstream refactorings are not ported — either they have no VAST
Refactoring-Browser counterpart or they are Pharo/SUnit-specific:
`rename_accessors`, `extract_method_to_component`, the `move_method_to_class` /
`move_method_to_class_side` / `move_method_to_instance_side` variants,
`extract_setup_method*`, `deprecate_method`, `merge_instance_variable`,
`generate_lazy_variable_accessor`, `remove_shared_variable` / `rename_shared_variable`
(pool variables), `remove_all_message_sends`, and `remove_methods_in_hierarchy`.

## Persistence: ENVY *and* the image

VAST keeps code in two places, and SmalltalkGenie uses both:

- **ENVY (the manager library)** records every class/method change per *application
  edition* automatically — so your code survives even without saving the image. To
  cut a release, **version and release** the Genie application (this freezes the
  current class editions into an immutable version, e.g. `1.0`).
- **`save_image`** writes the binary image (`abt.icx`) so the running server, loaded
  state, and settings persist across restarts.

## Security

Genie exists to let a client program a live image, so **a client that can reach the
server has the full power of the VAST process.** `eval` compiles and runs arbitrary
Smalltalk (`handleEval:` is essentially `EsCompiler evaluate: code for: nil
ifFail: …`): read, write, or delete any file the user can, open sockets, spawn
processes, modify or wipe the image. So the real job is containing *who can reach the
server*.

**Safe by default:**

- **Loopback-only binding.** The listening socket binds to `127.0.0.1`, so the server
  is reachable only from processes on the same machine. (Applies when the server next
  starts.)
- **Origin check.** Requests whose HTTP `Origin` header isn't local are rejected
  (403), blocking browser DNS-rebinding. This is defense-in-depth, *not* access
  control — non-browser clients (`curl`, scripts, MCP clients) send no `Origin` and
  aren't gated by it; the token below is the real gate.

**Opt-in hardening** — settings, applied via `apply_settings` or
`GenieServer settings at: #key put: value` (save the image to persist):

- **`authToken`** — set a non-empty token to require `Authorization: Bearer <token>`
  on every request (401 otherwise); off by default. **Enable it in this order so you
  don't lock yourself out** (it takes effect on the very next request): add the header
  to your client *first* — `claude mcp add --transport http genie-vast
  http://localhost:8088/mcp --header "Authorization: Bearer <token>"` — *then* set
  `authToken`, *th
← Back to results