The Model Context Protocol SDK for the VAST Platform
# MCP VAST Smalltalk SDK
<div align="center">
<strong>VAST Smalltalk implementation of the Model Context Protocol \(MCP\)</strong>
[](LICENSE)
[](https://www.instantiations.com/vast-platform/)
[](https://modelcontextprotocol.io)
[](https://modelcontextprotocol.io/specification/2026-07-28)
</div>
> [!NOTE]
> **This SDK implements the modern [MCP 2026-07-28 specification](https://modelcontextprotocol.io/specification/2026-07-28)** \(stateless requests, per-request capability metadata, `server/discover`, and Streamable HTTP\), while retaining backward compatibility with earlier revisions \(`2025-11-25`, `2025-06-18`, `2025-03-26`, and `2024-11-05` handshake-era protocols and legacy SSE\).
>
> Choose your client mode explicitly or allow automatic negotiation:
>
> * `#modern` \(`McpClient modern`\): Modern `2026-07-28` specification with sessionless Streamable HTTP.
>
> * `#legacy` \(`McpClient legacy`\): Handshake lifecycle \(`initialize` → `notifications/initialized`\).
>
> * `#auto` \(`McpClient auto`\): Modern discovery with fallback to legacy handshake.
>
> **External interoperability target:** Official Python MCP SDK `2.2.0`.
---
## What is MCP?
The [Model Context Protocol](https://modelcontextprotocol.io) enables LLM applications to access external tools, prompts, and contextual resources through a standardized, secure protocol. Think of it like a web API specifically designed for AI agents and LLM host integrations.
With the VAST MCP SDK you can:
* **Build MCP servers** in VAST Smalltalk that expose tools, resources, and reusable prompt templates to any MCP client or host \(e.g., Claude Desktop, MCP Inspector, custom agents\).
* **Build MCP clients** in VAST Smalltalk to consume tools and resources from any MCP server \(running in Smalltalk, Python, TypeScript, etc.\).
* **Communicate across all standard transports:** In-Memory \(direct image dispatch\), Native OS Subprocess stdio, Streamable HTTP, and Legacy HTTP+SSE.
---
## Requirements
* **VAST Platform Smalltalk** 15 (or later).
* **OpenSSL libraries** installed and [configured in VAST](https://www.instantiations.com/vast-support/documentation/FAQ/index.html#page/FAQ/va09002.html).
---
## Installation / Loading
* Clone, or [download a ZIP archive](https://github.com/instantiations/VAST-Platform-MCP-SDK/archive/refs/heads/main.zip) of, this repository.
* In VAST, load [Tonel](https://www.instantiations.com/vast-support/documentation/1500/#page/sg/tonel/tnl01-index.520.02.html) support: from the System Transcript window, use the menu item *Tools › Load/Unload Features* and load the ‘ST: Tonel Support’ feature.
* From the Configuration Maps Browser, use the menu item *Names › Import › Load Configuration Maps from Tonel Repository* and select the root directory of the local clone or extracted archive of the repository.
* In the window that opens, add and load the config map for the MCP SDK that corresponds to your version of VAST. At this time, only `MCP SDK (VAST 15.0)`.
---
## A server workspace
Create and publish an MCP server over Streamable HTTP:
```smalltalk
| server tool template http |
server := McpServer new name: 'Demo'; version: '1.0.0'; yourself.
"1. Register a tool"
tool := McpBlockTool new
name: 'add';
description: 'Add two numbers';
inputSchema: ((EsOrderedDictionary new)
at: 'type' put: 'object';
at: 'properties' put: ((EsOrderedDictionary new)
at: 'a' put: (EsOrderedDictionary with: 'type' -> 'integer');
at: 'b' put: (EsOrderedDictionary with: 'type' -> 'integer');
yourself);
at: 'required' put: #('a' 'b');
yourself);
block: [:args | ((args at: 'a') + (args at: 'b')) printString];
yourself.
server toolRegistry registerTool: tool.
"2. Register a templated resource"
template := McpBlockResourceTemplate new
uriTemplate: 'greeting://{name}';
name: 'greeting';
readBlock: [:uri | | vars |
vars := (McpUriTemplate template: 'greeting://{name}') matchUri: uri.
EsOrderedDictionary with: 'contents' -> (Array with: ((EsOrderedDictionary new)
at: 'uri' put: uri;
at: 'mimeType' put: 'text/plain';
at: 'text' put: ('Hello, ' , (vars at: 'name') , '!');
yourself))];
yourself.
server resourceTemplateRegistry registerTemplate: template.
"3. Start HTTP server on port 8080"
http := McpHttpServer new
host: '127.0.0.1';
port: 8080;
mcpServer: server;
start;
yourself.
```
That's a complete MCP server exposing an `add` tool and a dynamic `greeting://{name}` resource template.
Test it using the official [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
```bash
npx @modelcontextprotocol/inspector http://127.0.0.1:8080/mcp
```
---
## A client workspace
The SDK is also a full-featured MCP **client**. Connect to the HTTP server created above:
```smalltalk
| client result resourceResult |
client := McpClient modern.
client transport: (McpHttpClientTransport url: 'http://127.0.0.1:8080/mcp').
[
client connect.
"Invoke a tool"
result := client callTool: 'add'
arguments: (EsOrderedDictionary with: 'a' -> 1 with: 'b' -> 2).
Transcript show: 'Sum: ' , ((result at: 'content') first at: 'text'); cr. "Outputs: 3"
"Read a templated resource"
resourceResult := client readResource: 'greeting://Smalltalker'.
Transcript show: ((resourceResult at: 'contents') first at: 'text'); cr. "Outputs: Hello, Smalltalker!"
] ensure: [
client close.
].
```
---
## Core Capabilities
### 1. In-Memory Direct Transport
For testing or hosting within the same Smalltalk image, bypass network serialization entirely:
```smalltalk
| client result |
client := McpClient forServer: server mode: #modern.
[
result := client callTool: 'add'
arguments: (EsOrderedDictionary with: 'a' -> 10 with: 'b' -> 20).
Transcript show: ((result at: 'content') first at: 'text'); cr.
] ensure: [client close].
```
### 2. Structured Output & Schemas
Tools can enforce input and output JSON schemas. When an `outputSchema` is defined, returning a keyed dictionary automatically populates `structuredContent`:
```smalltalk
| outputSchema tool |
outputSchema := (EsOrderedDictionary new)
at: 'type' put: 'object';
at: 'properties' put: (EsOrderedDictionary with: 'status' -> (EsOrderedDictionary with: 'type' -> 'string'));
at: 'required' put: #('status');
yourself.
tool := McpBlockTool new
name: 'status';
inputSchema: (EsOrderedDictionary with: 'type' -> 'object');
outputSchema: outputSchema;
block: [EsOrderedDictionary with: 'status' -> 'ready'];
yourself.
server toolRegistry registerTool: tool.
```
### 3. Reusable Prompt Templates
Prompts return parameterized message templates for LLMs:
```smalltalk
| prompt |
prompt := McpBlockPrompt new
name: 'language';
description: 'Programming language selector';
arguments: (Array with: (EsOrderedDictionary with: 'name' -> 'language' with: 'required' -> true));
block: [:args | | message |
message := EsOrderedDictionary
with:'role' -> 'user'
with: 'content' -> (EsOrderedDictionary with: 'type' -> 'text' with: 'text' -> ('Chosen language: ' , (args at: 'language'))).
EsOrderedDictionary with: 'messages' -> (Array with: message)];
yourself.
server promptRegistry registerPrompt: prompt.
```
### 4. Binary Resources
Binary content \(e.g. images, archives\) is supported via Base64 strings in the `blob` property:
```smalltalk
| resource |
resource := McpBlockResource new
uri: 'app://data/binary';
name: 'data';
mimeType: 'application/octet-stream';
block: [
EsOrderedDictionary with: 'contents' -> (Array with: ((EsOrderedDictionary new)
at: 'uri' put: 'app://data/binary';
at: 'mimeType' put: 'application/octet-stream';
at: 'blob' put: (Base64Coder current encode: #[1 2 3 4]) asString;
yourself))];
yourself.
server resourceRegistry registerResource: resource.
```
### 5. Argument Completions
Provide auto-completions for prompts or URI templates via `completionBlock:`:
```smalltalk
prompt completionBlock: [:argName :prefix :context |
argName = 'language'
ifTrue: [#('smalltalk' 'python' 'javascript') select: [:each | (each indexOfSubCollection: prefix startingAt: 1) = 1]]
ifFalse: [#()]].
```
### 6. Multi-Round-Trip Input \(Elicitation, Sampling, Roots\)
Tools can pause execution to request client/user input, sample a model, or request filesystem roots.
This example demonstrates a server tool requesting a coupon code, and a client intercepting that request to supply the code.
```smalltalk
tool2 := McpBlockTool new
name: 'checkout';
inputSchema: (EsOrderedDictionary with: 'type' -> 'object');
"McpBlockTool automatically skips this block if the client already answered"
resolve: 'coupon' with: [:ctx :args | McpElicit message: 'Enter coupon code (optional):'];
block: [:args | | elicitResult couponCode |
"The argument contains the ElicitResult object returned by the client"
elicitResult := args at: 'coupon'.
couponCode := elicitResult at: 'content' ifAbsent: ['none'].
'Processed with coupon: ' , couponCode printString
];
yourself.
server toolRegistry registerTool: tool2.
"Client supplies ca