Skip to content

Commit 27fd0b2

Browse files
committed
Respond to feedback and some nits/reorganization
Signed-off-by: bowlofarugula <[email protected]>
1 parent f6a9195 commit 27fd0b2

File tree

1 file changed

+102
-62
lines changed

1 file changed

+102
-62
lines changed

content/blog/mcp-with-wasmcp.md

Lines changed: 102 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ Because the [Spin](https://github.com/spinframework/spin) runtime implements [wa
118118
## Quickstart
119119

120120
Install wasmcp via script to get the latest release binary.
121-
```
122-
$ curl -fsSL https://raw.githubusercontent.com/wasmcp/wasmcp/main/install.sh | bash
121+
```shell
122+
curl -fsSL https://raw.githubusercontent.com/wasmcp/wasmcp/main/install.sh | bash
123123
```
124124
Or build it from source.
125-
```
126-
$ cargo install --git https://github.com/wasmcp/wasmcp
125+
```shell
126+
cargo install --git https://github.com/wasmcp/wasmcp
127127
```
128128

129129
Source / open a new terminal and then scaffold out a tool component with `wasmcp new`. Only basic dependencies and build tooling from Bytecode Alliance are included. TypesScript uses [jco](https://github.com/bytecodealliance/jco), Rust uses [wit-bindgen](https://github.com/bytecodealliance/wit-bindgen), and Python uses [componentize-py](https://github.com/bytecodealliance/componentize-py).
@@ -132,14 +132,14 @@ wasmcp does not maintain any language-specific SDKs. The [WIT](https://component
132132

133133
We'll target Rust for our first one.
134134

135-
```
136-
$ wasmcp new my-first-tools --language rust
137-
📦 Fetching WIT dependencies...
135+
```shell
136+
wasmcp new my-first-tools --language rust
138137
```
139138

140-
If you open up `my-first-tools/src/lib.rs`, you’ll see some boilerplate that you can fill in with your tool implementations. A single tool component can define multiple MCP tools. As we’ll see, multiple tool components can then be chained together and their tools aggregated. This pattern also applies to the other MCP primitives: [resources](https://github.com/wasmcp/wasmcp/blob/main/cli/templates/rust-resources/src/lib.rs) and [prompts](https://github.com/wasmcp/wasmcp/blob/main/cli/templates/rust-prompts/src/lib.rs)
139+
If you open up `my-first-tools/src/lib.rs`, you’ll see some boilerplate similar to the code block below that you can fill in with your tool implementations. A single tool component can define multiple MCP tools. As we’ll see, multiple tool components can then be chained together and their tools aggregated. This pattern also applies to the other MCP primitives: [resources](https://github.com/wasmcp/wasmcp/blob/main/cli/templates/rust-resources/src/lib.rs) and [prompts](https://github.com/wasmcp/wasmcp/blob/main/cli/templates/rust-prompts/src/lib.rs)
141140

142141
```rust
142+
/// my-first-tools/src/lib.rs
143143
impl Guest for Calculator {
144144
fn list_tools(
145145
_ctx: RequestCtx,
@@ -200,30 +200,46 @@ This is accomplished with Bytecode Alliance’s [wac](https://github.com/bytecod
200200

201201
Note that any of the framework-level components can also be interchanged with your own custom implementations, like a custom transport component. See `wasmcp compose server –help` for details.
202202

203-
```
204-
$ make
205-
$ wasmcp compose server target/wasm32-wasip2/release/my-first-tools.wasm -o server.wasm
203+
```shell
204+
cd my-first-tools/
205+
make
206+
wasmcp compose server target/wasm32-wasip2/release/my-first-tools.wasm -o server.wasm
206207
```
207208

208209
Now that we have a complete `server.wasm` component, we can run it directly with `spin up`.
209210

211+
```shell
212+
spin up --from server.wasm
210213
```
211-
$ spin up -f server.wasm
212214

213-
Serving http://127.0.0.1:3000
214-
Available Routes:
215-
http-trigger1-component: http://127.0.0.1:3000 (wildcard)
216-
```
215+
We can provide more detailed runtime configuration with a [spin.toml](https://spinframework.dev/v3/writing-apps) file.
216+
217+
```toml
218+
# my-first-tools/spin.toml
219+
spin_manifest_version = 2
217220

218-
Note that runtime configuration can be managed with a [spin.toml](https://spinframework.dev/v3/writing-apps) file.
221+
[application]
222+
name = "mcp"
223+
version = "0.1.0"
224+
authors = ["You <[email protected]>"]
225+
description = "My MCP server"
219226

220-
And _just like that_, we have a functional MCP server over the Streamable HTTP transport! Authorization for providers that implement Dynamic Client Registration is configurable via [environment variables](https://github.com/wasmcp/wasmcp/tree/main/docs). The `stdio` transport can also be used via [Wasmtime](https://github.com/bytecodealliance/wasmtime) directly.
227+
[[trigger.http]]
228+
route = "/mcp"
229+
component = "mcp"
221230

231+
[component.mcp]
232+
source = "server.wasm"
233+
allowed_outbound_hosts = [] # Update for outbound HTTP
222234
```
223-
$ wasmtime run server.wasm
235+
236+
```shell
237+
spin up --from spin.toml
224238
```
225239

226-
You can now configure your favorite agent to use the MCP server.
240+
Just like _that_, we have a functional MCP server over the Streamable HTTP transport.
241+
242+
These AI applications are just some of the many that can use this MCP server to extend their capabilities.
227243

228244
* [Antigravity](https://antigravity.google/docs/mcp)
229245
* [ChatGPT (developer mode)](https://platform.openai.com/docs/guides/developer-mode)
@@ -236,17 +252,68 @@ You can now configure your favorite agent to use the MCP server.
236252
* [Visual Studio Code](https://code.visualstudio.com/docs/copilot/customization/mcp-servers)
237253
* [Zed](https://zed.dev/docs/ai/mcp)
238254

239-
## Unlimited Composition
255+
## Runtime Portability and Deployment Targets
240256

241-
The real power of the component model and wasmcp's composition architecture becomes apparent when adding another tool component to our server. We'll use Python this time.
257+
The MCP server component we just created exports the standard [`wasi:http/incoming-handler`](https://github.com/WebAssembly/wasi-http) interface. This means any WebAssembly runtime that supports `wasi:http` can serve the component to MCP clients over the Streamable HTTP transport.
258+
259+
For example, we can use [`wasmtime serve`](https://github.com/bytecodealliance/wasmtime):
260+
261+
```shell
262+
wasmtime serve -Scli server.wasm
263+
```
264+
265+
Our server also exports [`wasi:cli/run`](https://github.com/WebAssembly/wasi-cli), which lets it support the stdio MCP transport.
266+
267+
```shell
268+
wasmtime run server.wasm
269+
```
270+
271+
To deploy an MCP server as a Wasm component over the network, we can target a Spin-compatible cloud platform like [Fermyon Wasm Functions](https://www.fermyon.com/wasm-functions), which will scale a server component efficiently across [Akamai's](https://www.akamai.com/why-akamai/global-infrastructure)'s distributed network edge with application-scoped key-value storage. Projects like [SpinKube](https://www.spinkube.dev/) and [wasmCloud](https://github.com/wasmCloud/wasmCloud) allow MCP server components to be deployed on self-hosted Kubernetes clusters. A hypothetical MCP-specific hosting platform could potentially leverage this architecture to manage user-submitted MCP components.
272+
273+
This story will expand as the ecosystems around both WebAssembly components and MCP continue to grow.
274+
275+
## Publishing to OCI Registries
276+
277+
With a `spin.toml` file like the one above, we can use the `spin registry` command to publish our server component to an [OCI](https://opencontainers.org/) registry like [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry), [Docker Hub](https://docs.docker.com/docker-hub/repos/manage/hub-images/oci-artifacts/), or [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/).
278+
279+
```shell
280+
echo $GHCR_PAT | spin registry login --username mygithub --password-stdin ghcr.io
281+
spin registry push ghcr.io/mygithub/basic-utils:0.1.0
282+
```
283+
284+
`spin up` can automatically resolve a component from the registry.
285+
286+
```shell
287+
spin up --from ghcr.io/mygithub/basic-utils:0.1.0
288+
```
289+
290+
We can also use [wkg](https://github.com/bytecodealliance/wasm-pkg-tools) directly to publish our server to an [OCI](https://opencontainers.org/) registry like [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry), [Docker Hub](https://docs.docker.com/docker-hub/repos/manage/hub-images/oci-artifacts/), or [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/).
242291

292+
```shell
293+
wkg oci push ghcr.io/mygithub/basic-utils:0.1.0 polyglot.wasm
243294
```
244-
$ wasmcp new python-tools –language python
245-
$ cd python-tools # Develop
246-
$ make # Builds to python-tools/python-tools.wasm
295+
296+
Anyone with read access to this artifact can then pull the component using `wkg` to run it with a particular runtime.
297+
298+
```shell
299+
wkg oci pull ghcr.io/mygithub/basic-utils:0.1.0
300+
wasmtime serve -Scli mygithub:[email protected]
301+
```
302+
303+
We can publish any individual MCP feature component, or any sequence of composed components (which need not be servers) as a standalone artifact in the same way. This allows for composition and distribution of pre-built component patterns which are themselves not yet servers, and are further composable. See `wasmcp compose --help` for details.
304+
305+
## The Architecture of Wasmcp
306+
307+
The real power of the component model and wasmcp's composition architecture becomes apparent when adding another tool component to our server. We'll use Python this time.
308+
309+
```shell
310+
wasmcp new python-tools –-language python
311+
cd python-tools
312+
make
247313
```
248314

249315
```python
316+
# python-tools/app.py
250317
class StringsTools(exports.Tools):
251318
def list_tools(
252319
self,
@@ -305,21 +372,18 @@ class StringsTools(exports.Tools):
305372

306373
We compose our first and second tool components together by adding the paths to both tool component binaries in the `wasmcp compose server` arguments. Note that these local paths can be substituted for OCI registry artifacts. See `wasmcp compose server –help` for details.
307374

308-
```
309-
$ wasmcp compose server ./my-first-tools/target/wasm32-wasip2/release/my-first-tools.wasm ./python-tools/python-tools.wasm -o polyglot.wasm
310-
375+
```shell
376+
wasmcp compose server ./my-first-tools/target/wasm32-wasip2/release/my-first-tools.wasm ./python-tools/python-tools.wasm -o polyglot.wasm
311377
```
312378

313379
Run `polyglot.wasm` with `spin up`.
314-
```
315-
$ spin up -f polyglot.wasm
316-
317-
Serving http://127.0.0.1:3000
380+
```shell
381+
spin up -f polyglot.wasm
318382
```
319383

320384
Now our server has four tools: `add`, `subtract`, `reverse`, and `uppercase`! Two are implemented in Python, and two in Rust.
321385

322-
### Wasmcp's architecture
386+
### How?
323387

324388
Server features like tools, resources, prompts, and completions, are implemented by individual WebAssembly components that export narrow [WIT](https://component-model.bytecodealliance.org/design/wit.html) interfaces mapped from the MCP spec's [schema types](https://modelcontextprotocol.io/specification/draft/schema).
325389

@@ -352,36 +416,12 @@ This enables dynamic composition without complex configuration, all within a sin
352416

353417
This example only scratched the surface of what we can potentially do with `wasmcp`. To see some of the more advanced patterns like custom middleware components and session-enabled features, check out the [examples](https://github.com/wasmcp/wasmcp/tree/main/examples).
354418

355-
## Publishing to OCI Registries
356-
357-
We can use [wkg](https://github.com/bytecodealliance/wasm-pkg-tools) to publish our server to an [OCI](https://opencontainers.org/) registry like [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry), [Docker Hub](https://docs.docker.com/docker-hub/repos/manage/hub-images/oci-artifacts/), or [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/).
358-
359-
```
360-
$ wkg publish polyglot.wasm --package mygithub:[email protected]
361-
```
362-
363-
Anyone with read access to this artifact can then download and run the server using `wkg`.
364-
365-
```
366-
$ wkg get mygithub:[email protected]
367-
368-
$ spin up -f mygithub:[email protected]
369-
370-
Serving http://127.0.0.1:3000
371-
```
372-
373-
We can publish any individual component, or any sequence of composed MCP feature components and middleware, as a standalone artifact in the same way. This enables dynamic and flexible composition of reusable components across servers in a kind of recursive drag-and-drop way, supporting composition and distribution of pre-built patterns which are themselves further composable. See `wasmcp compose --help` for details.
374-
375-
## Related projects
376-
377-
Microsoft's [Wassette](https://github.com/microsoft/wassette) is a security-oriented runtime that runs WebAssembly Components via MCP.
419+
## Related Projects
378420

379-
While Wassette is a custom MCP-specific runtime that can dynamically load and execute components as individual tools on demand with deeply integrated access control, Wasmcp is a toolchain for producing an MCP server as a component that is compatible across Wasm runtimes.
421+
Microsoft's [Wassette](https://github.com/microsoft/wassette) is a security-oriented runtime that runs WebAssembly Components via MCP. It can dynamically load and execute components as individual tools on demand with deeply integrated access controls. Wassette itself is not a component. It is an MCP server than runs components.
380422

381-
## An Open Foundation for AI Agents
423+
By contrast, Wasmcp is a toolchain for producing an MCP server as a component that exports the standard [WASI](https://wasi.dev/) interfaces for HTTP and CLI commands: [`wasi:http`](https://github.com/WebAssembly/wasi-http) and [`wasi:cli`](https://github.com/WebAssembly/wasi-cli). This component runs on any server runtime that supports WASI and the component model.
382424

383-
By building on two complementary open standards, MCP and the WebAssembly component model, we can expose new context to AI applications and agents in a useful way that solves some of the current challenges towards achieving that goal.
425+
## Implications
384426

385-
To distribute an MCP server as a Wasm component over the network, we can target Spin-compatible cloud platforms like [Fermyon Wasm Functions](https://www.fermyon.com/wasm-functions), which will scale a server component efficiently across the global network edge with access to application-scoped key-value storage. [SpinKube](https://www.spinkube.dev/), which you can host on your own infrastructure, unlocks another level of flexibility. Any platform or runtime that directly supports the Wasm component model becomes a valid deployment target for the same component binary. A hypothetical MCP-specific hosting platform could even leverage this architecture to safely run user-submitted MCP features more directly.
386-
387-
This story will only get better as Wasm components improve alongside active advances in language models.
427+
The ecosystems around both WebAssembly components and MCP continue to grow rapidly. As more developers adopt these technologies, we can expect to see more innovative projects and applications emerge across a variety of use cases.

0 commit comments

Comments
 (0)