minecraft-bedrock-mcp-server 0.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/LICENSE +21 -0
- package/README.md +577 -0
- package/dist/bridge/event-route.d.ts +11 -0
- package/dist/bridge/event-route.d.ts.map +1 -0
- package/dist/bridge/event-route.js +28 -0
- package/dist/bridge/event-route.js.map +1 -0
- package/dist/bridge/handshake-route.d.ts +11 -0
- package/dist/bridge/handshake-route.d.ts.map +1 -0
- package/dist/bridge/handshake-route.js +45 -0
- package/dist/bridge/handshake-route.js.map +1 -0
- package/dist/bridge/poll-route.d.ts +11 -0
- package/dist/bridge/poll-route.d.ts.map +1 -0
- package/dist/bridge/poll-route.js +28 -0
- package/dist/bridge/poll-route.js.map +1 -0
- package/dist/bridge/result-route.d.ts +10 -0
- package/dist/bridge/result-route.d.ts.map +1 -0
- package/dist/bridge/result-route.js +23 -0
- package/dist/bridge/result-route.js.map +1 -0
- package/dist/config/config-error.d.ts +12 -0
- package/dist/config/config-error.d.ts.map +1 -0
- package/dist/config/config-error.js +13 -0
- package/dist/config/config-error.js.map +1 -0
- package/dist/config/environment.d.ts +89 -0
- package/dist/config/environment.d.ts.map +1 -0
- package/dist/config/environment.js +73 -0
- package/dist/config/environment.js.map +1 -0
- package/dist/config/tls.d.ts +15 -0
- package/dist/config/tls.d.ts.map +1 -0
- package/dist/config/tls.js +27 -0
- package/dist/config/tls.js.map +1 -0
- package/dist/errors/bridge-error.d.ts +41 -0
- package/dist/errors/bridge-error.d.ts.map +1 -0
- package/dist/errors/bridge-error.js +33 -0
- package/dist/errors/bridge-error.js.map +1 -0
- package/dist/errors/error-codes.d.ts +13 -0
- package/dist/errors/error-codes.d.ts.map +1 -0
- package/dist/errors/error-codes.js +41 -0
- package/dist/errors/error-codes.js.map +1 -0
- package/dist/events/subscription-registry.d.ts +55 -0
- package/dist/events/subscription-registry.d.ts.map +1 -0
- package/dist/events/subscription-registry.js +64 -0
- package/dist/events/subscription-registry.js.map +1 -0
- package/dist/http/app.d.ts +26 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +88 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/authentication.d.ts +11 -0
- package/dist/http/authentication.d.ts.map +1 -0
- package/dist/http/authentication.js +36 -0
- package/dist/http/authentication.js.map +1 -0
- package/dist/http/health-route.d.ts +10 -0
- package/dist/http/health-route.d.ts.map +1 -0
- package/dist/http/health-route.js +18 -0
- package/dist/http/health-route.js.map +1 -0
- package/dist/http/metrics-route.d.ts +8 -0
- package/dist/http/metrics-route.d.ts.map +1 -0
- package/dist/http/metrics-route.js +11 -0
- package/dist/http/metrics-route.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/mcp-route.d.ts +12 -0
- package/dist/mcp/mcp-route.d.ts.map +1 -0
- package/dist/mcp/mcp-route.js +49 -0
- package/dist/mcp/mcp-route.js.map +1 -0
- package/dist/mcp/mcp-server-factory.d.ts +20 -0
- package/dist/mcp/mcp-server-factory.d.ts.map +1 -0
- package/dist/mcp/mcp-server-factory.js +23 -0
- package/dist/mcp/mcp-server-factory.js.map +1 -0
- package/dist/mcp/session-manager.d.ts +30 -0
- package/dist/mcp/session-manager.d.ts.map +1 -0
- package/dist/mcp/session-manager.js +38 -0
- package/dist/mcp/session-manager.js.map +1 -0
- package/dist/mcp/tool-registry.d.ts +15 -0
- package/dist/mcp/tool-registry.d.ts.map +1 -0
- package/dist/mcp/tool-registry.js +27 -0
- package/dist/mcp/tool-registry.js.map +1 -0
- package/dist/observability/logger.d.ts +16 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +19 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +27 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +72 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/protocol/command.d.ts +92 -0
- package/dist/protocol/command.d.ts.map +1 -0
- package/dist/protocol/command.js +37 -0
- package/dist/protocol/command.js.map +1 -0
- package/dist/protocol/event.d.ts +82 -0
- package/dist/protocol/event.d.ts.map +1 -0
- package/dist/protocol/event.js +37 -0
- package/dist/protocol/event.js.map +1 -0
- package/dist/protocol/handshake.d.ts +150 -0
- package/dist/protocol/handshake.d.ts.map +1 -0
- package/dist/protocol/handshake.js +65 -0
- package/dist/protocol/handshake.js.map +1 -0
- package/dist/protocol/index.d.ts +14 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +14 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/protocol-version.d.ts +18 -0
- package/dist/protocol/protocol-version.d.ts.map +1 -0
- package/dist/protocol/protocol-version.js +28 -0
- package/dist/protocol/protocol-version.js.map +1 -0
- package/dist/protocol/result.d.ts +79 -0
- package/dist/protocol/result.d.ts.map +1 -0
- package/dist/protocol/result.js +35 -0
- package/dist/protocol/result.js.map +1 -0
- package/dist/queue/command-id.d.ts +15 -0
- package/dist/queue/command-id.d.ts.map +1 -0
- package/dist/queue/command-id.js +38 -0
- package/dist/queue/command-id.js.map +1 -0
- package/dist/queue/command-queue.d.ts +90 -0
- package/dist/queue/command-queue.d.ts.map +1 -0
- package/dist/queue/command-queue.js +151 -0
- package/dist/queue/command-queue.js.map +1 -0
- package/dist/queue/command-throttle.d.ts +38 -0
- package/dist/queue/command-throttle.d.ts.map +1 -0
- package/dist/queue/command-throttle.js +26 -0
- package/dist/queue/command-throttle.js.map +1 -0
- package/dist/queue/instrumented-command-queue.d.ts +9 -0
- package/dist/queue/instrumented-command-queue.d.ts.map +1 -0
- package/dist/queue/instrumented-command-queue.js +39 -0
- package/dist/queue/instrumented-command-queue.js.map +1 -0
- package/dist/queue/pending-commands.d.ts +35 -0
- package/dist/queue/pending-commands.d.ts.map +1 -0
- package/dist/queue/pending-commands.js +41 -0
- package/dist/queue/pending-commands.js.map +1 -0
- package/dist/server-info.d.ts +5 -0
- package/dist/server-info.d.ts.map +1 -0
- package/dist/server-info.js +22 -0
- package/dist/server-info.js.map +1 -0
- package/dist/structures/structure-file-store.d.ts +22 -0
- package/dist/structures/structure-file-store.d.ts.map +1 -0
- package/dist/structures/structure-file-store.js +89 -0
- package/dist/structures/structure-file-store.js.map +1 -0
- package/dist/tools/block-tools.d.ts +4 -0
- package/dist/tools/block-tools.d.ts.map +1 -0
- package/dist/tools/block-tools.js +111 -0
- package/dist/tools/block-tools.js.map +1 -0
- package/dist/tools/command-tools.d.ts +4 -0
- package/dist/tools/command-tools.d.ts.map +1 -0
- package/dist/tools/command-tools.js +23 -0
- package/dist/tools/command-tools.js.map +1 -0
- package/dist/tools/common-schemas.d.ts +65 -0
- package/dist/tools/common-schemas.d.ts.map +1 -0
- package/dist/tools/common-schemas.js +32 -0
- package/dist/tools/common-schemas.js.map +1 -0
- package/dist/tools/effect-tools.d.ts +4 -0
- package/dist/tools/effect-tools.d.ts.map +1 -0
- package/dist/tools/effect-tools.js +32 -0
- package/dist/tools/effect-tools.js.map +1 -0
- package/dist/tools/entity-tools.d.ts +4 -0
- package/dist/tools/entity-tools.d.ts.map +1 -0
- package/dist/tools/entity-tools.js +133 -0
- package/dist/tools/entity-tools.js.map +1 -0
- package/dist/tools/event-tools.d.ts +4 -0
- package/dist/tools/event-tools.d.ts.map +1 -0
- package/dist/tools/event-tools.js +84 -0
- package/dist/tools/event-tools.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +30 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/inventory-tools.d.ts +4 -0
- package/dist/tools/inventory-tools.d.ts.map +1 -0
- package/dist/tools/inventory-tools.js +52 -0
- package/dist/tools/inventory-tools.js.map +1 -0
- package/dist/tools/player-tools.d.ts +4 -0
- package/dist/tools/player-tools.d.ts.map +1 -0
- package/dist/tools/player-tools.js +117 -0
- package/dist/tools/player-tools.js.map +1 -0
- package/dist/tools/property-tools.d.ts +4 -0
- package/dist/tools/property-tools.d.ts.map +1 -0
- package/dist/tools/property-tools.js +45 -0
- package/dist/tools/property-tools.js.map +1 -0
- package/dist/tools/scoreboard-tools.d.ts +4 -0
- package/dist/tools/scoreboard-tools.d.ts.map +1 -0
- package/dist/tools/scoreboard-tools.js +68 -0
- package/dist/tools/scoreboard-tools.js.map +1 -0
- package/dist/tools/server-tools.d.ts +4 -0
- package/dist/tools/server-tools.d.ts.map +1 -0
- package/dist/tools/server-tools.js +25 -0
- package/dist/tools/server-tools.js.map +1 -0
- package/dist/tools/structure-file-tools.d.ts +4 -0
- package/dist/tools/structure-file-tools.d.ts.map +1 -0
- package/dist/tools/structure-file-tools.js +57 -0
- package/dist/tools/structure-file-tools.js.map +1 -0
- package/dist/tools/structure-tools.d.ts +4 -0
- package/dist/tools/structure-tools.d.ts.map +1 -0
- package/dist/tools/structure-tools.js +91 -0
- package/dist/tools/structure-tools.js.map +1 -0
- package/dist/tools/tool-definition.d.ts +68 -0
- package/dist/tools/tool-definition.d.ts.map +1 -0
- package/dist/tools/tool-definition.js +40 -0
- package/dist/tools/tool-definition.js.map +1 -0
- package/dist/tools/tool-result.d.ts +17 -0
- package/dist/tools/tool-result.d.ts.map +1 -0
- package/dist/tools/tool-result.js +52 -0
- package/dist/tools/tool-result.js.map +1 -0
- package/dist/tools/world-tools.d.ts +4 -0
- package/dist/tools/world-tools.d.ts.map +1 -0
- package/dist/tools/world-tools.js +97 -0
- package/dist/tools/world-tools.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 John Chapman (@amzn)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
# Minecraft Bedrock MCP Server
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that bridges MCP
|
|
4
|
+
clients — Claude and other AI agents — to a **Minecraft Bedrock Dedicated Server** (BDS). It
|
|
5
|
+
exposes the Bedrock Script API as MCP tools, so an agent can read and manipulate a live world
|
|
6
|
+
programmatically.
|
|
7
|
+
|
|
8
|
+
## ⚠️ Built on an experimental API
|
|
9
|
+
|
|
10
|
+
This project depends on Mojang's Bedrock **Script API**, including the **beta** modules
|
|
11
|
+
`@minecraft/server-net` and `@minecraft/server-admin`. The Script API is an evolving surface that
|
|
12
|
+
Mojang revises between Minecraft versions, and **a Bedrock update can change, deprecate, or remove
|
|
13
|
+
APIs this project depends on** — beta modules can be discontinued outright with no stable
|
|
14
|
+
replacement. Pin your BDS to a known-good version, do not auto-update it, and keep the BDS, the
|
|
15
|
+
behavior pack, and this server upgraded together. Treat the whole stack as experimental.
|
|
16
|
+
|
|
17
|
+
## The two repositories
|
|
18
|
+
|
|
19
|
+
This system is split across two repositories:
|
|
20
|
+
|
|
21
|
+
| Repository | Role |
|
|
22
|
+
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
23
|
+
| **`minecraft-bedrock-mcp-server`** (this repo) | The MCP server. Speaks MCP to clients and bridges commands to the world. |
|
|
24
|
+
| **[`minecraft-bedrock-mcp-behavior-pack`](https://github.com/chapmanjw/minecraft-bedrock-mcp-behavior-pack)** | The BDS behavior pack. Runs inside the world and executes commands via the Script API. |
|
|
25
|
+
|
|
26
|
+
This README is the **end-to-end guide** — it covers standing up the whole stack. The behavior
|
|
27
|
+
pack repository documents the pack itself in more depth.
|
|
28
|
+
|
|
29
|
+
## How it works
|
|
30
|
+
|
|
31
|
+
The server runs on the same host as BDS and exposes two authenticated HTTP surfaces:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
MCP clients (Claude Desktop, Cursor, ...)
|
|
35
|
+
| MCP over Streamable HTTP + bearer token
|
|
36
|
+
minecraft-bedrock-mcp-server <-- this repository
|
|
37
|
+
| HTTP long-poll + bearer token
|
|
38
|
+
Bedrock Bridge behavior pack <-- separate repository
|
|
39
|
+
| @minecraft/server Script API
|
|
40
|
+
the Minecraft world
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- The **`/mcp`** surface speaks the MCP Streamable HTTP transport to clients.
|
|
44
|
+
- The **`/bridge`** surface is long-polled by the companion behavior pack running inside the world.
|
|
45
|
+
|
|
46
|
+
An MCP tool call enqueues a command; the behavior pack polls for it, executes it through the
|
|
47
|
+
Script API, and posts the result back. The server correlates that result to the waiting tool call
|
|
48
|
+
and returns it to the client.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
# End-to-end setup tutorial
|
|
53
|
+
|
|
54
|
+
This walkthrough takes you from nothing to an AI agent building in your world. It has eight steps:
|
|
55
|
+
|
|
56
|
+
1. [Set up a Bedrock Dedicated Server](#step-1--set-up-a-bedrock-dedicated-server)
|
|
57
|
+
2. [Create a compatible world](#step-2--create-a-compatible-world)
|
|
58
|
+
3. [Transfer the world to the server](#step-3--transfer-the-world-to-the-server)
|
|
59
|
+
4. [Install the behavior pack](#step-4--install-the-behavior-pack)
|
|
60
|
+
5. [Install and configure the MCP server](#step-5--install-and-configure-the-mcp-server)
|
|
61
|
+
6. [Configure the behavior pack](#step-6--configure-the-behavior-pack)
|
|
62
|
+
7. [Start everything](#step-7--start-everything)
|
|
63
|
+
8. [Connect Claude Desktop](#step-8--connect-claude-desktop)
|
|
64
|
+
|
|
65
|
+
> **Assumption:** this tutorial assumes the Bedrock Dedicated Server and the MCP server run on the
|
|
66
|
+
> **same Ubuntu (Linux) host**. The commands below are written for Ubuntu. BDS also ships for
|
|
67
|
+
> Windows; if you run it there, adapt the paths and shell commands accordingly — the configuration
|
|
68
|
+
> values are identical.
|
|
69
|
+
|
|
70
|
+
## Prerequisites
|
|
71
|
+
|
|
72
|
+
- An Ubuntu host (a VM, a spare machine, or a cloud instance) for the server.
|
|
73
|
+
- Node.js 20 or newer on that host.
|
|
74
|
+
- A copy of **Minecraft: Bedrock Edition** on a PC or device — used once to create the world.
|
|
75
|
+
- About 20 minutes.
|
|
76
|
+
|
|
77
|
+
## Step 1 — Set up a Bedrock Dedicated Server
|
|
78
|
+
|
|
79
|
+
1. Download the Linux Bedrock Dedicated Server from the official page:
|
|
80
|
+
<https://www.minecraft.net/en-us/download/server/bedrock>. Accept the EULA and privacy policy
|
|
81
|
+
prompts on that page to reveal the download link.
|
|
82
|
+
|
|
83
|
+
2. Unzip it on the Ubuntu host:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
sudo mkdir -p /opt/bedrock-server
|
|
87
|
+
sudo unzip bedrock-server-*.zip -d /opt/bedrock-server
|
|
88
|
+
sudo chown -R "$USER" /opt/bedrock-server
|
|
89
|
+
cd /opt/bedrock-server
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
3. Do a first test run so BDS generates its default files, then stop it with `Ctrl+C`:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
LD_LIBRARY_PATH=. ./bedrock_server
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If it complains about a missing library, install the basics:
|
|
99
|
+
`sudo apt-get update && sudo apt-get install -y libcurl4 unzip`.
|
|
100
|
+
|
|
101
|
+
4. Edit `server.properties`. The settings that matter for this project:
|
|
102
|
+
|
|
103
|
+
| Setting | Value | Why |
|
|
104
|
+
| -------------- | ------------------------ | ------------------------------------------------------- |
|
|
105
|
+
| `level-name` | _your world folder name_ | Selects which world under `worlds/` to load. |
|
|
106
|
+
| `allow-cheats` | `true` | Required for `mc_run_command` and command-backed tools. |
|
|
107
|
+
| `gamemode` | `creative` | Recommended so agents can place and break freely. |
|
|
108
|
+
|
|
109
|
+
Leave the rest at their defaults for now. You will set `level-name` in Step 3.
|
|
110
|
+
|
|
111
|
+
Step 7 covers running BDS as a `systemd` service. For more detail (firewall rules, backups),
|
|
112
|
+
search "Bedrock Dedicated Server" in the Minecraft help center at <https://help.minecraft.net>.
|
|
113
|
+
|
|
114
|
+
## Step 2 — Create a compatible world
|
|
115
|
+
|
|
116
|
+
The behavior pack needs a world created with the **Beta APIs** experiment enabled. That toggle can
|
|
117
|
+
only be set when the world is created **in the Minecraft client** — the dedicated server cannot
|
|
118
|
+
turn it on. So create the world on your PC/device first, then move it to the server.
|
|
119
|
+
|
|
120
|
+
In Minecraft: Bedrock Edition, choose **Create New World** and set:
|
|
121
|
+
|
|
122
|
+
| Setting | Value | Why |
|
|
123
|
+
| ---------------------------- | -------- | ------------------------------------------------------------------ |
|
|
124
|
+
| **Game Mode** | Creative | Agents place/break blocks and spawn entities freely. |
|
|
125
|
+
| **Cheats** (Activate Cheats) | On | Enables commands; pairs with `allow-cheats` on the server. |
|
|
126
|
+
| **Experiments → Beta APIs** | On | **Required.** `@minecraft/server-net` / `-admin` are beta modules. |
|
|
127
|
+
|
|
128
|
+
Then **play the world once** for a few seconds so it is fully written to disk, and exit.
|
|
129
|
+
|
|
130
|
+
## Step 3 — Transfer the world to the server
|
|
131
|
+
|
|
132
|
+
1. In Minecraft, on the worlds list, open the world's settings (the pencil icon) and choose
|
|
133
|
+
**Export World**. This produces a `.mcworld` file — which is just a ZIP archive.
|
|
134
|
+
|
|
135
|
+
2. Copy that file to the Ubuntu host (e.g. with `scp`) and unzip it into a folder under `worlds/`:
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
cd /opt/bedrock-server/worlds
|
|
139
|
+
mkdir "mcp-world"
|
|
140
|
+
unzip ~/exported-world.mcworld -d "mcp-world"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
3. Set `level-name=mcp-world` in `/opt/bedrock-server/server.properties` so BDS loads it.
|
|
144
|
+
|
|
145
|
+
The world's absolute path is now `/opt/bedrock-server/worlds/mcp-world` — you will need it shortly.
|
|
146
|
+
|
|
147
|
+
## Step 4 — Install the behavior pack
|
|
148
|
+
|
|
149
|
+
1. Get the pack from the
|
|
150
|
+
[behavior pack repository](https://github.com/chapmanjw/minecraft-bedrock-mcp-behavior-pack) —
|
|
151
|
+
download `bedrock-bridge.mcpack` from its
|
|
152
|
+
[Releases](https://github.com/chapmanjw/minecraft-bedrock-mcp-behavior-pack/releases), or clone
|
|
153
|
+
and `npm run build` it. The pack is the folder holding `manifest.json`, `scripts/main.js`, and
|
|
154
|
+
`pack_icon.png`.
|
|
155
|
+
|
|
156
|
+
2. Place the pack folder inside the world:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
mkdir -p "/opt/bedrock-server/worlds/mcp-world/behavior_packs"
|
|
160
|
+
cp -r bedrock-bridge "/opt/bedrock-server/worlds/mcp-world/behavior_packs/"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
3. Activate it for the world by creating (or editing)
|
|
164
|
+
`/opt/bedrock-server/worlds/mcp-world/world_behavior_packs.json`:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
[{ "pack_id": "fa013817-66f2-4a5f-a724-1347f912bd40", "version": [0, 1, 0] }]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The pack's absolute path is now
|
|
171
|
+
`/opt/bedrock-server/worlds/mcp-world/behavior_packs/bedrock-bridge`.
|
|
172
|
+
|
|
173
|
+
## Step 5 — Install and configure the MCP server
|
|
174
|
+
|
|
175
|
+
Install this server on the same host:
|
|
176
|
+
|
|
177
|
+
```sh
|
|
178
|
+
npm install -g minecraft-bedrock-mcp-server
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Generate two long random secrets — one for MCP clients, one for the behavior pack:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
openssl rand -hex 32 # use for BRIDGE_CLIENT_TOKEN
|
|
185
|
+
openssl rand -hex 32 # use for BRIDGE_AGENT_TOKEN
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Create a `.env` file (copy [.env.example](.env.example) as a starting point):
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
BRIDGE_CLIENT_TOKEN=<first secret>
|
|
192
|
+
BRIDGE_AGENT_TOKEN=<second secret>
|
|
193
|
+
BRIDGE_WORLD_PATH=/opt/bedrock-server/worlds/mcp-world
|
|
194
|
+
BRIDGE_BEHAVIOR_PACK_PATH=/opt/bedrock-server/worlds/mcp-world/behavior_packs/bedrock-bridge
|
|
195
|
+
BRIDGE_HOST=0.0.0.0
|
|
196
|
+
BRIDGE_PORT=8765
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
See the [configuration reference](#configuration-reference) for every variable.
|
|
200
|
+
|
|
201
|
+
## Step 6 — Configure the behavior pack
|
|
202
|
+
|
|
203
|
+
The pack reads its configuration from the BDS scripting config directory. Create
|
|
204
|
+
`/opt/bedrock-server/config/default/` and add three files (the behavior pack repository ships
|
|
205
|
+
copy-ready versions under its `config/default/`):
|
|
206
|
+
|
|
207
|
+
**`permissions.json`** — lets the pack load its Script API modules:
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"allowed_modules": ["@minecraft/server", "@minecraft/server-net", "@minecraft/server-admin"]
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**`variables.json`** — where the bridge listens (the MCP server's `/bridge` surface):
|
|
216
|
+
|
|
217
|
+
```json
|
|
218
|
+
{ "bridge_url": "http://localhost:8765" }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**`secrets.json`** — the bridge token. The value is the **full `Authorization` header** — the word
|
|
222
|
+
`Bearer`, a space, then the `BRIDGE_AGENT_TOKEN` from your `.env`:
|
|
223
|
+
|
|
224
|
+
```json
|
|
225
|
+
{ "bridge_agent_token": "Bearer <the BRIDGE_AGENT_TOKEN second secret>" }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
> The `Bearer ` prefix must be part of the stored secret — the pack receives an opaque handle it
|
|
229
|
+
> cannot read or concatenate, so the scheme prefix has to travel inside the secret itself.
|
|
230
|
+
|
|
231
|
+
## Step 7 — Start everything
|
|
232
|
+
|
|
233
|
+
You can start the two processes by hand, or — recommended — install them as `systemd` services so
|
|
234
|
+
they survive logout, restart on crash, and start at boot.
|
|
235
|
+
|
|
236
|
+
### Option A — run in the foreground
|
|
237
|
+
|
|
238
|
+
Start the MCP server, then the Bedrock server, in two terminals:
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
# Terminal 1 — the MCP server
|
|
242
|
+
minecraft-bedrock-mcp-server # reads .env from the working directory
|
|
243
|
+
|
|
244
|
+
# Terminal 2 — the Bedrock Dedicated Server
|
|
245
|
+
cd /opt/bedrock-server && LD_LIBRARY_PATH=. ./bedrock_server
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Option B — run as systemd services (recommended)
|
|
249
|
+
|
|
250
|
+
This is how the two processes are run in a typical long-lived deployment.
|
|
251
|
+
|
|
252
|
+
1. Create a dedicated unprivileged user to own and run both processes, and hand it the files:
|
|
253
|
+
|
|
254
|
+
```sh
|
|
255
|
+
sudo useradd --system --no-create-home --shell /usr/sbin/nologin minecraft
|
|
256
|
+
sudo chown -R minecraft:minecraft /opt/bedrock-server
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
2. Move the MCP server's `.env` (from Step 5) somewhere the service can read it, and lock it down
|
|
260
|
+
— it holds both bearer tokens:
|
|
261
|
+
|
|
262
|
+
```sh
|
|
263
|
+
sudo mkdir -p /etc/minecraft-bedrock-mcp
|
|
264
|
+
sudo cp .env /etc/minecraft-bedrock-mcp/.env
|
|
265
|
+
sudo chown -R minecraft:minecraft /etc/minecraft-bedrock-mcp
|
|
266
|
+
sudo chmod 600 /etc/minecraft-bedrock-mcp/.env
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
3. Create `/etc/systemd/system/bedrock-server.service`:
|
|
270
|
+
|
|
271
|
+
```ini
|
|
272
|
+
[Unit]
|
|
273
|
+
Description=Minecraft Bedrock Dedicated Server
|
|
274
|
+
After=network.target
|
|
275
|
+
|
|
276
|
+
[Service]
|
|
277
|
+
Type=simple
|
|
278
|
+
User=minecraft
|
|
279
|
+
Group=minecraft
|
|
280
|
+
WorkingDirectory=/opt/bedrock-server
|
|
281
|
+
Environment=LD_LIBRARY_PATH=/opt/bedrock-server
|
|
282
|
+
ExecStart=/opt/bedrock-server/bedrock_server
|
|
283
|
+
Restart=on-failure
|
|
284
|
+
RestartSec=10
|
|
285
|
+
StandardInput=null
|
|
286
|
+
StandardOutput=journal
|
|
287
|
+
StandardError=journal
|
|
288
|
+
|
|
289
|
+
[Install]
|
|
290
|
+
WantedBy=multi-user.target
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
4. Create `/etc/systemd/system/mc-mcp-server.service`:
|
|
294
|
+
|
|
295
|
+
```ini
|
|
296
|
+
[Unit]
|
|
297
|
+
Description=Minecraft Bedrock MCP server
|
|
298
|
+
After=network.target bedrock-server.service
|
|
299
|
+
|
|
300
|
+
[Service]
|
|
301
|
+
Type=simple
|
|
302
|
+
User=minecraft
|
|
303
|
+
Group=minecraft
|
|
304
|
+
EnvironmentFile=/etc/minecraft-bedrock-mcp/.env
|
|
305
|
+
ExecStart=/usr/bin/minecraft-bedrock-mcp-server
|
|
306
|
+
Restart=on-failure
|
|
307
|
+
RestartSec=10
|
|
308
|
+
StandardOutput=journal
|
|
309
|
+
StandardError=journal
|
|
310
|
+
|
|
311
|
+
[Install]
|
|
312
|
+
WantedBy=multi-user.target
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
`ExecStart` points at the global install from Step 5. Run `command -v minecraft-bedrock-mcp-server`
|
|
316
|
+
to confirm its path on your host and adjust the line if it differs.
|
|
317
|
+
|
|
318
|
+
5. Enable and start both — the MCP server first, so the bridge is listening when the world loads:
|
|
319
|
+
|
|
320
|
+
```sh
|
|
321
|
+
sudo systemctl daemon-reload
|
|
322
|
+
sudo systemctl enable --now mc-mcp-server bedrock-server
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
6. Check status and follow the logs:
|
|
326
|
+
|
|
327
|
+
```sh
|
|
328
|
+
systemctl status mc-mcp-server bedrock-server
|
|
329
|
+
journalctl -u mc-mcp-server -f
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Confirm the handshake
|
|
333
|
+
|
|
334
|
+
When the world loads, the behavior pack handshakes with the bridge. The MCP server logs the
|
|
335
|
+
successful handshake, and BDS logs that the `bedrock-bridge` pack's script started. If the
|
|
336
|
+
handshake fails, the most common causes are a token mismatch between `secrets.json` and `.env`, or
|
|
337
|
+
a wrong `bridge_url`.
|
|
338
|
+
|
|
339
|
+
Quick liveness check:
|
|
340
|
+
|
|
341
|
+
```sh
|
|
342
|
+
curl http://localhost:8765/healthz
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Step 8 — Connect Claude Desktop
|
|
346
|
+
|
|
347
|
+
The MCP server speaks the **Streamable HTTP** transport. Claude Desktop connects to it through the
|
|
348
|
+
[`mcp-remote`](https://www.npmjs.com/package/mcp-remote) adapter, which bridges a local stdio
|
|
349
|
+
server entry to a remote HTTP endpoint and attaches the bearer token.
|
|
350
|
+
|
|
351
|
+
Edit Claude Desktop's config file:
|
|
352
|
+
|
|
353
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
354
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
355
|
+
|
|
356
|
+
Add a `minecraft-bedrock` entry under `mcpServers`:
|
|
357
|
+
|
|
358
|
+
```json
|
|
359
|
+
{
|
|
360
|
+
"mcpServers": {
|
|
361
|
+
"minecraft-bedrock": {
|
|
362
|
+
"command": "npx",
|
|
363
|
+
"args": [
|
|
364
|
+
"-y",
|
|
365
|
+
"mcp-remote",
|
|
366
|
+
"http://YOUR-SERVER-HOST:8765/mcp",
|
|
367
|
+
"--header",
|
|
368
|
+
"Authorization:${AUTH_HEADER}"
|
|
369
|
+
],
|
|
370
|
+
"env": {
|
|
371
|
+
"AUTH_HEADER": "Bearer <the BRIDGE_CLIENT_TOKEN first secret>"
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Replace `YOUR-SERVER-HOST` with the host running the MCP server (`localhost` if it is the same
|
|
379
|
+
machine as Claude Desktop). The token is passed via the `AUTH_HEADER` env var so its space is not
|
|
380
|
+
mangled by argument parsing.
|
|
381
|
+
|
|
382
|
+
Restart Claude Desktop fully. The `mc_*` tools appear under the tools (🔌) menu once it
|
|
383
|
+
reconnects. If your Claude Desktop version supports **custom connectors** natively, you can
|
|
384
|
+
instead add the `http://YOUR-SERVER-HOST:8765/mcp` URL directly in **Settings → Connectors** with
|
|
385
|
+
the `Authorization: Bearer <token>` header — that skips `mcp-remote` entirely.
|
|
386
|
+
|
|
387
|
+
## Sample prompts
|
|
388
|
+
|
|
389
|
+
With at least one player in the world (the agent acts relative to players and the world origin),
|
|
390
|
+
try prompts like these in Claude Desktop:
|
|
391
|
+
|
|
392
|
+
**Building**
|
|
393
|
+
|
|
394
|
+
> "Build a 9×9×5 hollow stone-brick house at around x=100, z=100 on the surface, with a door, a
|
|
395
|
+
> couple of glass windows, and torches inside. Find a flat spot first."
|
|
396
|
+
|
|
397
|
+
> "Clear a 20×20 area to bedrock-flat grass, then lay out a small village square — a fountain in
|
|
398
|
+
> the middle, paths to four corners, and a lamp post at each corner."
|
|
399
|
+
|
|
400
|
+
> "Save the structure I just built as `starter-house` so I can paste copies of it elsewhere."
|
|
401
|
+
|
|
402
|
+
**Interacting with the world**
|
|
403
|
+
|
|
404
|
+
> "What's the time and weather right now? Set it to clear and to midday."
|
|
405
|
+
|
|
406
|
+
> "List the players online and tell me what each is holding and standing on."
|
|
407
|
+
|
|
408
|
+
> "Spawn a ring of twelve armor stands around the nearest player, then give that player a
|
|
409
|
+
> netherite pickaxe."
|
|
410
|
+
|
|
411
|
+
**Reacting to events**
|
|
412
|
+
|
|
413
|
+
> "Subscribe to block-break events, then tell me what gets broken over the next minute."
|
|
414
|
+
|
|
415
|
+
> "Strike lightning wherever a player places a redstone block — keep watching until I say stop."
|
|
416
|
+
|
|
417
|
+
Start small and concrete. The agent works through the tool surface below; vague prompts ("make it
|
|
418
|
+
cooler") give it nothing to aim at.
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
# Reference
|
|
423
|
+
|
|
424
|
+
## Install
|
|
425
|
+
|
|
426
|
+
```sh
|
|
427
|
+
npm install -g minecraft-bedrock-mcp-server
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Run it directly without installing:
|
|
431
|
+
|
|
432
|
+
```sh
|
|
433
|
+
npx minecraft-bedrock-mcp-server
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
Or with Docker. Each `v*` tag publishes a multi-arch image (`linux/amd64`,
|
|
437
|
+
`linux/arm64`) to the GitHub Container Registry — pull and run it directly:
|
|
438
|
+
|
|
439
|
+
```sh
|
|
440
|
+
docker run --env-file .env -p 8765:8765 ghcr.io/chapmanjw/minecraft-bedrock-mcp-server:latest
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Pin to a specific version (e.g. `:0.1.0`) for reproducible deployments. To build the
|
|
444
|
+
image from source instead:
|
|
445
|
+
|
|
446
|
+
```sh
|
|
447
|
+
docker build -t minecraft-bedrock-mcp-server .
|
|
448
|
+
docker run --env-file .env -p 8765:8765 minecraft-bedrock-mcp-server
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
## Configuration reference
|
|
452
|
+
|
|
453
|
+
All configuration is through environment variables, validated at startup — the server exits with
|
|
454
|
+
a clear message if a required variable is missing. Copy [.env.example](.env.example) and adjust.
|
|
455
|
+
|
|
456
|
+
| Variable | Default | Description |
|
|
457
|
+
| ------------------------------------ | ------------ | --------------------------------------------- |
|
|
458
|
+
| `BRIDGE_CLIENT_TOKEN` | _(required)_ | Bearer token for MCP clients |
|
|
459
|
+
| `BRIDGE_AGENT_TOKEN` | _(required)_ | Bearer token for the behavior pack |
|
|
460
|
+
| `BRIDGE_WORLD_PATH` | _(required)_ | Absolute path to the active world folder |
|
|
461
|
+
| `BRIDGE_BEHAVIOR_PACK_PATH` | _(required)_ | Absolute path to the behavior pack folder |
|
|
462
|
+
| `BRIDGE_HOST` | `0.0.0.0` | Bind address |
|
|
463
|
+
| `BRIDGE_PORT` | `8765` | Listen port |
|
|
464
|
+
| `BRIDGE_TLS_CERT` / `BRIDGE_TLS_KEY` | _(none)_ | TLS cert/key paths — set both, or neither |
|
|
465
|
+
| `BRIDGE_TRUST_PROXY` | `false` | Trust `X-Forwarded-*` (enable behind a proxy) |
|
|
466
|
+
| `BRIDGE_LOG_LEVEL` | `info` | Log level |
|
|
467
|
+
| `BRIDGE_POLL_TIMEOUT_MS` | `30000` | Bridge long-poll hold time |
|
|
468
|
+
| `BRIDGE_COMMAND_TIMEOUT_MS` | `15000` | How long a tool call awaits a result |
|
|
469
|
+
| `BRIDGE_RATE_LIMIT_RPM` | `60` | Per-token request rate on `/mcp` |
|
|
470
|
+
| `BRIDGE_MAX_BODY_BYTES` | `16777216` | Maximum request body size |
|
|
471
|
+
| `BRIDGE_QUEUE_MAX` | `256` | Maximum outstanding commands |
|
|
472
|
+
| `BRIDGE_METRICS_ENABLED` | `false` | Expose the Prometheus `/metrics` endpoint |
|
|
473
|
+
| `BRIDGE_CORS_ORIGINS` | _(none)_ | Comma-separated allowed CORS origins |
|
|
474
|
+
|
|
475
|
+
## Endpoints
|
|
476
|
+
|
|
477
|
+
| Route | Auth | Purpose |
|
|
478
|
+
| ------------------------ | ------------ | ------------------------------------ |
|
|
479
|
+
| `POST/GET/DELETE /mcp` | client token | MCP Streamable HTTP transport |
|
|
480
|
+
| `GET /bridge/poll` | agent token | Behavior-pack long-poll for commands |
|
|
481
|
+
| `POST /bridge/result` | agent token | Behavior-pack command results |
|
|
482
|
+
| `POST /bridge/event` | agent token | Behavior-pack world events |
|
|
483
|
+
| `POST /bridge/handshake` | agent token | Behavior-pack version negotiation |
|
|
484
|
+
| `GET /healthz` | none | Liveness probe |
|
|
485
|
+
| `GET /metrics` | client token | Prometheus metrics (when enabled) |
|
|
486
|
+
|
|
487
|
+
## TLS
|
|
488
|
+
|
|
489
|
+
The bridge carries bearer tokens and world data. **Use TLS** outside a fully trusted network.
|
|
490
|
+
|
|
491
|
+
### Direct TLS with mkcert (private LAN)
|
|
492
|
+
|
|
493
|
+
[mkcert](https://github.com/FiloSottile/mkcert) issues a certificate trusted by your LAN machines:
|
|
494
|
+
|
|
495
|
+
```sh
|
|
496
|
+
mkcert -install
|
|
497
|
+
mkcert bedrock-host.lan 192.168.1.50
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Point the server at the generated files:
|
|
501
|
+
|
|
502
|
+
```sh
|
|
503
|
+
BRIDGE_TLS_CERT=./bedrock-host.lan+1.pem
|
|
504
|
+
BRIDGE_TLS_KEY=./bedrock-host.lan+1-key.pem
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
When both are set, the server listens HTTPS only. When neither is set, it listens HTTP and logs a
|
|
508
|
+
prominent warning at startup.
|
|
509
|
+
|
|
510
|
+
### TLS at a reverse proxy
|
|
511
|
+
|
|
512
|
+
Alternatively, terminate TLS upstream — Caddy with its internal CA, or Traefik — and run this
|
|
513
|
+
server on plain HTTP bound to `localhost`. Set `BRIDGE_TRUST_PROXY=true` so client IP addresses
|
|
514
|
+
are logged correctly.
|
|
515
|
+
|
|
516
|
+
## Tool surface
|
|
517
|
+
|
|
518
|
+
77 tools across 13 domains, consistently named `mc_<domain>_<action>`:
|
|
519
|
+
|
|
520
|
+
| Domain | Examples |
|
|
521
|
+
| --------------- | ----------------------------------------------------------------- |
|
|
522
|
+
| World | `mc_world_get_info`, `mc_world_set_time`, `mc_world_set_weather` |
|
|
523
|
+
| Blocks | `mc_block_get`, `mc_block_fill`, `mc_block_clone` |
|
|
524
|
+
| Structures | `mc_structure_create_from_world`, `mc_structure_place` |
|
|
525
|
+
| Structure files | `mc_structure_file_read`, `mc_structure_file_write` |
|
|
526
|
+
| Entities | `mc_entity_spawn`, `mc_entity_teleport`, `mc_entity_apply_effect` |
|
|
527
|
+
| Players | `mc_player_list`, `mc_player_give_item`, `mc_player_set_gamemode` |
|
|
528
|
+
| Inventory | `mc_inventory_get`, `mc_inventory_set_slot` |
|
|
529
|
+
| Scoreboard | `mc_scoreboard_set_score`, `mc_scoreboard_add_objective` |
|
|
530
|
+
| Properties | `mc_property_get`, `mc_property_set` |
|
|
531
|
+
| Effects | `mc_explosion_create`, `mc_lightning_strike` |
|
|
532
|
+
| Events | `mc_event_subscribe`, `mc_event_poll` |
|
|
533
|
+
| Server | `mc_server_save_world`, `mc_server_get_status` |
|
|
534
|
+
| Escape hatch | `mc_run_command` |
|
|
535
|
+
|
|
536
|
+
## Stability and versioning
|
|
537
|
+
|
|
538
|
+
This server is a stable foundation for separately built skills and plugins. Its **public
|
|
539
|
+
contract**, governed by semantic versioning, is:
|
|
540
|
+
|
|
541
|
+
- tool **names**,
|
|
542
|
+
- tool **input schemas**,
|
|
543
|
+
- tool **output** (the `result` field of the response envelope),
|
|
544
|
+
- stable **error codes**,
|
|
545
|
+
- the **bridge protocol** envelopes.
|
|
546
|
+
|
|
547
|
+
Internal structure — the HTTP framework, module layout, logging format — is not part of the
|
|
548
|
+
contract and may change at any time. The bridge protocol is versioned independently; its major
|
|
549
|
+
version is negotiated at handshake.
|
|
550
|
+
|
|
551
|
+
Note that this contract is the _server's_ contract. The **underlying Bedrock Script API is not
|
|
552
|
+
stable** (see the warning at the top): a Bedrock update can still break behavior even when this
|
|
553
|
+
server's contract is unchanged.
|
|
554
|
+
|
|
555
|
+
## Security
|
|
556
|
+
|
|
557
|
+
- Two separate bearer tokens isolate MCP clients from the behavior pack; tokens are compared in
|
|
558
|
+
constant time.
|
|
559
|
+
- Every route except `/healthz` requires a token.
|
|
560
|
+
- Per-token rate limiting on `/mcp`; per-command throttling protects the BDS script watchdog.
|
|
561
|
+
- The command queue is in memory and is not persisted — commands do not survive a restart.
|
|
562
|
+
|
|
563
|
+
See [SECURITY.md](SECURITY.md) to report a vulnerability.
|
|
564
|
+
|
|
565
|
+
## Development
|
|
566
|
+
|
|
567
|
+
```sh
|
|
568
|
+
npm install
|
|
569
|
+
npm run typecheck
|
|
570
|
+
npm run lint
|
|
571
|
+
npm test
|
|
572
|
+
npm run build
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
## License
|
|
576
|
+
|
|
577
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { SubscriptionRegistry } from "../events/subscription-registry.js";
|
|
3
|
+
/**
|
|
4
|
+
* Registers `POST /event` (mounted at `/bridge/event`).
|
|
5
|
+
*
|
|
6
|
+
* Validates an event report and buffers each event under its subscription.
|
|
7
|
+
* Events for unknown subscriptions are dropped and logged — not an error for
|
|
8
|
+
* the behavior pack, which may report an event mid-unsubscribe.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerEventRoute(app: FastifyInstance, subscriptions: SubscriptionRegistry): void;
|
|
11
|
+
//# sourceMappingURL=event-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-route.d.ts","sourceRoot":"","sources":["../../src/bridge/event-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAG/E;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,aAAa,EAAE,oBAAoB,GAClC,IAAI,CAqBN"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EventReportSchema } from "../protocol/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Registers `POST /event` (mounted at `/bridge/event`).
|
|
4
|
+
*
|
|
5
|
+
* Validates an event report and buffers each event under its subscription.
|
|
6
|
+
* Events for unknown subscriptions are dropped and logged — not an error for
|
|
7
|
+
* the behavior pack, which may report an event mid-unsubscribe.
|
|
8
|
+
*/
|
|
9
|
+
export function registerEventRoute(app, subscriptions) {
|
|
10
|
+
app.post("/event", (request, reply) => {
|
|
11
|
+
const parsed = EventReportSchema.safeParse(request.body);
|
|
12
|
+
if (!parsed.success) {
|
|
13
|
+
return reply
|
|
14
|
+
.code(400)
|
|
15
|
+
.send({ error: { code: "INVALID_INPUT", message: "malformed event report" } });
|
|
16
|
+
}
|
|
17
|
+
let ingested = 0;
|
|
18
|
+
for (const event of parsed.data.events) {
|
|
19
|
+
if (subscriptions.ingest(event))
|
|
20
|
+
ingested += 1;
|
|
21
|
+
}
|
|
22
|
+
if (ingested < parsed.data.events.length) {
|
|
23
|
+
request.log.warn({ received: parsed.data.events.length, ingested }, "some reported events referenced unknown subscriptions");
|
|
24
|
+
}
|
|
25
|
+
return reply.code(202).send({ accepted: ingested });
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=event-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-route.js","sourceRoot":"","sources":["../../src/bridge/event-route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAoB,EACpB,aAAmC;IAEnC,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,KAAK;iBACT,IAAI,CAAC,GAAG,CAAC;iBACT,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,wBAAwB,EAAE,EAAE,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACvC,IAAI,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC;gBAAE,QAAQ,IAAI,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,IAAI,CACd,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,EACjD,uDAAuD,CACxD,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { SubscriptionRegistry } from "../events/subscription-registry.js";
|
|
3
|
+
/**
|
|
4
|
+
* Registers `POST /handshake` (mounted at `/bridge/handshake`).
|
|
5
|
+
*
|
|
6
|
+
* Negotiates the bridge protocol version on behavior-pack startup. A pack
|
|
7
|
+
* whose major version differs is refused with `409`. On acceptance the
|
|
8
|
+
* response replays active subscriptions so a restarted pack re-arms them.
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerHandshakeRoute(app: FastifyInstance, serverVersion: string, pollTimeoutMs: number, subscriptions: SubscriptionRegistry): void;
|
|
11
|
+
//# sourceMappingURL=handshake-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handshake-route.d.ts","sourceRoot":"","sources":["../../src/bridge/handshake-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAQ/E;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,eAAe,EACpB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,oBAAoB,GAClC,IAAI,CA2CN"}
|