Xeno MCP
MCP server for AI agents to interact with Roblox game clients through the Xeno executor
Ask AI about Xeno MCP
Powered by Claude ยท Grounded in docs
I know everything about Xeno MCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
xeno-mcp
An MCP server that lets AI agents interact with Roblox game clients โ execute Lua scripts, capture game output, search community scripts, and manage client connections โ all from your favorite AI tool.
Supports two modes:
- Xeno mode โ direct integration with the Xeno executor
- Generic mode โ file-based adapter that works with any executor (Solara, Velocity, etc.)
Why file-based and not DLL injection? Each executor uses its own internal API with different function signatures, memory layouts, and calling conventions โ there's no universal DLL interface. Supporting executors via DLL would mean writing and maintaining a separate proxy for every single one, and any executor update could break it. The file-based approach works with any executor out of the box as long as it supports basic UNC functions (
readfile,writefile, etc.), which virtually all of them do. It's also completely non-invasive โ no hooking into executor internals, no binary compatibility issues, and no risk of triggering anti-cheat from foreign DLL injection.
What is Xeno? โ A free, keyless Roblox script executor with multi-attach support. Grab it at xeno.now.
Table of Contents
- Architecture
- Prerequisites
- Build
- Setup โ Xeno Mode
- Setup โ Generic Mode
- MCP Configuration
- Tools
- Remote Spy
- Logs & Pagination
- HTTP API
- Server Flags
- Environment Variables
- Testing
Architecture
Two components work together:
- HTTP Server (Rust/actix-web, port 3111) โ manages client state, receives logs from injected Lua scripts, proxies to executor APIs
- MCP Bridge (TypeScript, stdio) โ translates MCP tool calls into HTTP requests and auto-starts the server
Xeno mode:
AI Agent โโstdioโโ MCP Bridge โโhttpโโ HTTP Server โโhttpโโ Xeno API โโ Roblox
Generic mode:
AI Agent โโstdioโโ MCP Bridge โโhttpโโ HTTP Server โโfileโโ Exchange Dir โโpollโโ Loader (in executor) โโ Roblox
The bridge spawns the HTTP server automatically โ you don't need to start it manually.
Prerequisites
- Windows โ Roblox executors are Windows-only
- Rust โ builds the HTTP server (
cargo) - Node.js 18+ โ runs the MCP bridge (
npm) - Git โ to clone the repo
- An executor: Xeno for Xeno mode, or any executor with UNC support for generic mode
Build
git clone https://github.com/Lypt1x/xeno-mcp.git
cd xeno-mcp
# 1. Build the Rust HTTP server
cargo build --release
# 2. Build the MCP bridge
cd mcp-bridge
npm install
npm run build
cd ..
First Rust build takes a few minutes (pulls dependencies). Subsequent builds are fast.
The server binary is at target/release/xeno-mcp.exe. The bridge output is at mcp-bridge/dist/.
Setup โ Xeno Mode
This is the default mode. Xeno has a built-in API that the server communicates with directly.
- Build the project (see Build)
- Add the MCP config to your AI agent (see MCP Configuration)
- Open Xeno and inject into a Roblox client
- Start your AI agent โ the bridge starts the server automatically
That's it. The agent will detect Xeno clients and can execute scripts immediately.
Setup โ Generic Mode
Generic mode works with any executor that supports basic UNC functions. Instead of a direct API, scripts are exchanged through the filesystem.
Requirements
Your executor must support:
readfile(path)โ read file contentslistfiles(path)โ list files in a directoryisfile(path)โ check if a path is a filedelfile(path)โ delete a filerequest({...})โ make HTTP requestsgetgenv()โ global environment table
Setup
- Build the project (see Build)
- Find your executor's workspace folder (the directory where
readfile/writefileoperate) - Add the MCP config with generic mode env vars (see MCP Configuration)
- Start your AI agent
- Open your executor, inject into Roblox, and paste this into the executor:
loadstring(game:HttpGet("http://localhost:3111/loader-script"))() - You'll see an in-game notification: "Loader connected" โ you're ready to go
What the loader does
The loader script runs inside the executor and:
- Polls
exchange/pending/for new.luascript files every 200ms - Executes scripts via
loadstring()and deletes the file - Captures all
print/warn/erroroutput and sends it to the server - Sends heartbeats every 5 seconds to keep the connection alive
- Auto-reconnects if the server restarts (retries every 5s, notifies in-game)
- Automatically disconnects when the player leaves the game
- Prevents double-injection (safe to run multiple times)
Autoexec (optional)
To skip pasting the loadstring every time you inject, save it to your executor's autoexec folder:
- Find your executor's
autoexecfolder (usually inside the workspace/root directory) - Create a file called
xeno-mcp-loader.luawith this content:loadstring(game:HttpGet("http://localhost:3111/loader-script"))() - The loader will now connect automatically every time you inject
MCP Configuration
Add the following to your AI agent's MCP config. Replace the path with your actual clone location.
Xeno Mode
Claude Desktop โ %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"xeno-mcp": {
"command": "npx",
"args": ["-y", "C:/path/to/xeno-mcp/mcp-bridge"]
}
}
}
VS Code / GitHub Copilot โ .vscode/mcp.json
{
"mcp": {
"servers": {
"xeno-mcp": {
"command": "npx",
"args": ["-y", "C:/path/to/xeno-mcp/mcp-bridge"]
}
}
}
}
Cursor โ ~/.cursor/mcp.json
{
"mcpServers": {
"xeno-mcp": {
"command": "npx",
"args": ["-y", "C:/path/to/xeno-mcp/mcp-bridge"]
}
}
}
Generic Mode
Add the XENO_MCP_MODE and GENERIC_EXECUTOR_WORKSPACE environment variables:
{
"mcpServers": {
"xeno-mcp": {
"command": "npx",
"args": ["-y", "C:/path/to/xeno-mcp/mcp-bridge"],
"env": {
"XENO_MCP_MODE": "generic",
"GENERIC_EXECUTOR_WORKSPACE": "C:\\path\\to\\executor\\Workspace"
}
}
}
}
The bridge automatically creates the exchange/pending/ and exchange/done/ subdirectories inside the workspace.
Optional: Shared Secret
To require authentication on all POST/DELETE endpoints:
{
"env": {
"XENO_MCP_SECRET": "your-secret-here"
}
}
Tools
The MCP server exposes these tools to the AI agent:
Core Tools
| Tool | Description |
|---|---|
get_health | Server status, mode, executor connectivity, connected clients |
get_clients | List connected Roblox clients (PID + username in Xeno, username in generic) |
execute_lua | Run a Lua script on connected clients. Auto-selects if only one client is connected |
attach_logger | Inject the log-forwarding script (Xeno mode only โ generic mode includes it automatically) |
get_logs | Query captured output with filters and pagination (see Logs & Pagination) |
clear_logs | Wipe all stored logs |
get_loader_script | Get the raw loader script source (generic mode, advanced use) |
ScriptBlox Integration
| Tool | Description |
|---|---|
search_scripts | Search community scripts on ScriptBlox by keyword |
browse_scripts | Browse trending, popular, or recent scripts |
get_script_details | Fetch full metadata, safety info, and raw source code for a script |
execute_scriptblox_script | Fetch and execute a ScriptBlox script on connected clients |
The agent enforces safety rules: unverified scripts require explicit user confirmation, obfuscated scripts trigger warnings, and key systems are flagged.
Remote Spy Tools
| Tool | Description |
|---|---|
attach_spy | Start the remote spy โ hooks FireServer, InvokeServer, and OnClientEvent |
detach_spy | Stop the spy and restore all hooks |
spy_subscribe | Subscribe to a remote path for full logging (bypasses dedup) |
spy_unsubscribe | Unsubscribe from a remote path (back to dedup-only) |
See Remote Spy for details.
Remote Spy
The remote spy intercepts Roblox remote calls (both incoming and outgoing) and logs them through the existing log system. It uses the dual-hook redirect pattern to avoid blocking game traffic.
Requirements
- Generic mode only โ requires UNC hook functions (
hookfunction,hookmetamethod,newcclosure, etc.) that are not available in Xeno mode - In Xeno mode, the spy tools return an error explaining the UNC requirement
- Logger should be attached first for status messages
How It Works
attach_spyinjects a Lua script that hooksFireServer,InvokeServer(viahookfunction) and__namecall(viahookmetamethod)- The
__namecallhook redirects remote calls to thehookfunction'd versions instead of callingold()directly โ this is the key pattern that avoids blocking game traffic - Passive
OnClientEvent:Connect()listeners capture incoming serverโclient events - All intercepted calls are sent to
POST /internalwithevent: "spy"and stored as log entries withsource: "remote_spy"
Deduplication
By default, the spy deduplicates โ only the first occurrence of each unique remote (by path + direction + method) is logged. This prevents flooding the log with 60+/frame calls in busy games.
To get all calls for a specific remote (including args), use spy_subscribe:
spy_subscribe("ReplicatedStorage.Remotes.SetAFK")
This makes the spy log every call to remotes matching that path. Supports partial matching โ subscribing to "Remotes" matches all remotes under that path.
Use spy_unsubscribe to return a remote to dedup-only mode.
Querying Spy Logs
Spy logs use source: "remote_spy" and tags ["spy", "in"|"out"]:
get_logs(source="remote_spy") โ all spy logs
get_logs(source="remote_spy", tag="out") โ outgoing calls only
get_logs(source="remote_spy", tag="in") โ incoming calls only
get_logs(source="remote_spy", search="SetAFK") โ specific remote
Cleanup
detach_spysends a disconnect script that restores all hooks and clears listeners- The spy auto-cleans up when the player leaves the game
- The spy guards against double-injection: re-attaching disconnects the previous spy first
Logs & Pagination
Every script execution and all game output (print, warn, error) are captured as log entries.
Log Levels
| Level | Source |
|---|---|
output | print() calls from Roblox |
warn | warn() calls from Roblox |
error | error() calls and runtime errors |
info | Internal events (loader attached, disconnected, etc.) |
script | Every executed script is logged with this level |
Pagination
Logs are returned 50 per page by default (max 1000). The response includes:
{
"logs": [...],
"total": 247,
"page": 1,
"per_page": 50,
"total_pages": 5,
"has_more": true
}
Use page (1-indexed) to navigate, or offset for manual control.
Filters
All filters can be combined:
| Parameter | Description |
|---|---|
level | Filter by level: output, warn, error, info, script |
search | Substring search in messages (case-insensitive) |
source | Filter by source (substring match) |
pid | Filter by client PID |
tag | Filter by tags (comma-separated) |
after | Only logs after this ISO 8601 timestamp |
before | Only logs before this ISO 8601 timestamp |
order | Sort: desc (newest first, default) or asc (oldest first) |
page | Page number (1-indexed) |
limit | Results per page (default: 50, max: 1000) |
offset | Manual offset (alternative to page) |
HTTP API
For direct integration without MCP:
| Method | Endpoint | Description |
|---|---|---|
GET | /health | Server status + mode + connected clients |
GET | /clients | List Roblox clients |
POST | /execute | Execute Lua: { "script": "...", "pids": ["123"] } |
POST | /attach-logger | Attach log script: { "pids": ["123"] } |
GET | /loader-script | Get the generic loader Lua script |
POST | /internal | Client โ server event channel (used by injected scripts) |
GET | /logs | Query logs with filters (see Logs & Pagination) |
DELETE | /logs | Clear all logs |
POST | /spy/attach | Start remote spy on client (generic mode only) |
POST | /spy/detach | Stop remote spy and restore hooks |
POST | /spy/subscribe | Subscribe to a remote path: { "path": "..." } |
POST | /spy/unsubscribe | Unsubscribe from a remote path: { "path": "..." } |
GET | /spy/status | Spy status: active clients and subscriptions |
All POST/DELETE endpoints require the X-Xeno-Secret header when --secret is set.
Server Flags
xeno-mcp [OPTIONS]
Options:
-p, --port <PORT> Port to listen on [default: 3111]
-b, --bind <ADDR> Bind address [default: 127.0.0.1]
--console Print incoming logs to stdout
--log-file <PATH> Append logs to a file
--secret <SECRET> Require X-Xeno-Secret header on POST/DELETE
--max-entries <N> Max log entries in memory [default: 10000]
--xeno-url <URL> Xeno API URL [default: http://localhost:3110]
--mode <MODE> Server mode: xeno or generic [default: xeno]
--exchange-dir <DIR> OS path for script exchange files [default: ./exchange]
--executor-exchange-dir <DIR> Exchange path as seen by the executor's filesystem
To run the server manually (useful for debugging):
./target/release/xeno-mcp --mode generic --exchange-dir "C:\Executor\Workspace\exchange" --executor-exchange-dir exchange --console
Environment Variables
Configure the MCP bridge via environment variables in your MCP config:
| Variable | Default | Description |
|---|---|---|
XENO_MCP_URL | http://localhost:3111 | HTTP server URL |
XENO_MCP_SECRET | โ | Shared secret for authentication |
XENO_MCP_MODE | xeno | Server mode: xeno or generic |
GENERIC_EXECUTOR_WORKSPACE | โ | Executor's workspace folder (generic mode only) |
Advanced overrides (rarely needed):
| Variable | Description |
|---|---|
GENERIC_EXECUTOR_EXCHANGE_DIR | Override the OS exchange directory path |
GENERIC_EXECUTOR_RELATIVE_DIR | Override the executor-relative exchange path |
Testing
Use the MCP Inspector to test tools interactively:
npx @modelcontextprotocol/inspector npx -y ./mcp-bridge
This opens a web UI where you can invoke each tool, inspect responses, and read resources.
