npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@warpfx/mcp

v0.4.1

Published

MCP server exposing the Warp FiveM dev loop to AI agents

Readme

@warpfx/mcp

MCP server that gives an AI agent direct access to the FiveM dev loop - boot the server, launch the game, drive the UI, and read back what actually happened.

Works on any FiveM server running Warp - see Install.

[!WARNING] Part of Warp, which is pre-1.0. Tool names, arguments and return shapes can change in any release. This is developer tooling for a development machine - see Safety before pointing it at anything you care about.

Install

Register it in your own project - the module you are building, not a checkout of Warp. For Claude Code that is a .mcp.json at the project root; other MCP-aware editors take the same shape under their own key.

{
  "mcpServers": {
    "warp": {
      "command": "npx",
      "args": ["-y", "@warpfx/mcp"],
      "env": {
        "WARP_FXSERVER": "C:\\FXServer\\FXServer.exe",
        "WARP_SERVER_DATA": "C:\\FXServer\\server-data"
      }
    }
  }
}

Two paths, both pointing at the FiveM server you develop against:

| Variable | What it points at | | ------------------ | ---------------------------------------------------------------------- | | WARP_FXSERVER | FXServer.exe | | WARP_SERVER_DATA | the server data folder - the one holding resources/ and server.cfg |

Everything else is derived from those. Warp itself is found at <WARP_SERVER_DATA>/resources/warp, which is where its config, log and database engine live. Set WARP_ROOT explicitly if the resource folder is named something else.

Nothing is installed into your project: npx fetches the server on demand and it talks to your running FiveM server from outside. Your module never depends on it.

Then develop the loop, not just the code:

server_start                        → your server, with your module
rcon "restart my_module"            → reload after an edit, no cold boot
client_logs filter="script error"   → what actually broke, client-side
db_query sql="SELECT * FROM my_module_things"

Two tools need nothing at all: native_lookup works with no server and no config, and server_logs reads any FiveM log you point WARP_SERVER_LOG at.

db_query reaches the whole Warp database, not only your module's tables. On your own development server that is the point; it is also the reason not to point this at a server whose data matters. See Safety.

Tools

| Tool | What it does | | ------------------------------ | ------------------------------------------------------------------------- | | server_start / server_stop | Ensure FXServer is up, console captured to the log | | server_logs | Tail the server console log, optionally filtered by regex | | client_logs | Tail the game client's log, the same output the F8 console shows | | rcon | Run a command on the FiveM server console (ensure warp, refresh, …) | | game_launch / game_close | Ensure a client is in-game, and hand the display back after | | probe_wait | Block until the game client is loaded and controllable | | probe_state | Read a connected player's position, health, vehicle and synced tables | | probe_teleport | Move a connected player to world coordinates | | game_screenshot | Capture the FiveM window, NUI included | | game_click | Click a point in the window - drives NUI - and return the resulting frame | | game_scroll | Turn the mouse wheel, to reach a control below the fold of a NUI list | | game_type | Type text into a NUI field | | game_key | Press a named key with modifiers - Tab, Enter, Escape, arrows, f-keys | | db_query | Run a read-only SELECT against the Warp database | | db_execute | INSERT/UPDATE/DELETE - destructive, guarded, explicit request only | | native_lookup | Search the canonical FiveM natives index by name or hash |

A typical session

The point of the loop is that a change gets verified in the running game, not assumed. Creating a character through the warp-multichar UI, end to end:

server_start                          → FXServer up, console → logs/server.log
server_logs filter="error"            → nothing; boot is clean
game_launch                           → client connects
probe_wait                            → blocks until in-game, returns player state

game_screenshot                       → a "Choose your life" panel
game_click x=0.086 y=0.611            → NEW CHARACTER; returns the frame after
game_type x=0.058 y=0.476 text="Ada"  → clicks that field, then types
game_key key=tab                      → next field
game_type text="Lovelace"
game_click x=0.096 y=0.652            → CREATE CHARACTER

db_query sql="SELECT * FROM multichar_characters"   → the row is really there
game_close                            → display handed back
server_stop

Every input tool returns a fresh screenshot, so each UI step is a single call rather than act-then-look. Positions are fractions of the window (x=0.14, y=0.56), not pixels - read a target off a screenshot and divide by that image's width and height, and the coordinate stays correct however the image was scaled in transit.

Setup

rcon - needs a password in server.cfg:

rcon_password "warp"

Override with RCON_HOST / RCON_PORT / RCON_PASSWORD (defaults 127.0.0.1:30120, warp).

server_start - needs WARP_FXSERVER and WARP_SERVER_DATA (see Install). Refuses to run if unset.

server_logs - no setup if you start the server with server_start, which captures the console to logs/server.log (truncated per run). Otherwise pipe it yourself:

FXServer.exe +exec server.cfg > logs/server.log 2>&1

Or point WARP_SERVER_LOG at an existing log file (e.g. a txAdmin one).

client_logs - no setup. FiveM mirrors the F8 console to a per-session file in %LOCALAPPDATA%\FiveM\FiveM.app\logs\CitizenFX_log_<timestamp>.log, so client-side console.log and script errors are readable without the game window being focused. The newest session file is resolved on every call, because each launch writes a new one.

Override with WARP_CLIENT_LOG (a specific file) or WARP_CLIENT_LOG_DIR (the folder).

The engine writes a lot of its own noise into this log, so filter it:

client_logs filter="script error"        → client-side failures only
client_logs filter="Warp|my_resource"    → follow one module

server_logs and client_logs see different halves of the same session. A feature that looks fine server-side can still be failing in the client script, and only client_logs shows that.

game_launch - no setup, and no path to FiveM.exe required. It hands fivem://connect/<address> to explorer.exe rather than running the executable, because the game refuses to start when the process launching it has a console attached ("This application should be launched directly from the shell or a web browser"). Going through the shell holds whether or not the caller has one. explorer.exe reports no useful exit code, so probe_wait is what actually confirms the launch worked - a timeout there with no FiveM process means the fivem:// handler is not registered.

game_screenshot - Windows only, no setup. GDI window capture, so run FiveM windowed or borderless: exclusive fullscreen returns a black image.

game_click / game_scroll / game_type / game_key - Windows only, no setup. All four are synthetic OS input (same input.ps1 as the screenshot, which needs the window on top for the same reason), so the FiveM window is brought to the foreground first, and NUI only receives them while the resource holds SetNuiFocus(true, true). If nothing changed, the panel likely was not focused, or the point missed the control.

Keyboard input goes through .NET SendKeys, which is keyboard-layout aware - a literal "John" types the same on QWERTZ as on QWERTY. It cannot reach a window running elevated when the MCP server is not.

probe_* - needs the warp-probe resource ensured on the server, and a connected game client. Reached over HTTP on the same host/port as RCON; override with WARP_PROBE_URL.

db_query / db_execute - no setup. Both shell out to the engine Warp downloads into <warp>/.spacetimedb/bin/<version>/, using that folder as the CLI root, so they speak to the same data directory and identity the server uses - not to any CLI on PATH. Host, port and database name come from the Warp resource's warp.config.json (defaults 127.0.0.1:3000, warp-db). The database only runs while the server does, so server_start first.

Tables are prefixed with their module name (multichar_characters, economy_accounts); core tables are unprefixed (player).

native_lookup - no setup. Downloads natives.json + natives_cfx.json from runtime.fivem.net on first use into .cache/ (gitignored). Delete that folder to refresh.

Attaching to what is already running

Both server_start and game_launch detect and reuse rather than duplicate, so an agent can call them first thing without caring whether the developer already has a server or a client open:

  • server_start asks http://<address>/info.json. Anything answering - started here, by hand, or by txAdmin - is reused. Reload code with rcon restart <resource> instead of a cold boot. (A server started outside this tool has no captured console; point WARP_SERVER_LOG at its log to keep server_logs useful.)
  • game_launch asks warp-probe for player state, which is a stronger signal than the process existing: it means connected and resources live. A client already in-game is reused and its state returned. If FiveM is running but not in-game on that address, it says so rather than spawning a second instance - FiveM allows only one.

The teardown tools are deliberately asymmetric: server_stop and game_close only stop what this tool started. A server or client that was already running belongs to the developer and needs an explicit force: true to kill. Losing a session mid-work is worse than a slower loop.

Both track "did I start this" in memory, so it resets if the MCP server reconnects - after that, stopping needs force.

Safety

Two of these tools can do real damage, and both are development-only.

warp-probe is unauthenticated player control. Anything that can reach the server's HTTP port can read and move any connected player. Never ensure warp-probe on a public server.

db_execute writes straight to the database, bypassing module validation and any server-side logic. The sync engine still pushes the change to connected clients, because the server is subscribed to the table - so a bad write is visible immediately and is not undoable.

Reads are a separate tool from writes so the two can be permissioned apart: allow db_query freely, keep db_execute behind a prompt. db_execute refuses unless all of:

  • the statement is a single INSERT, UPDATE or DELETE - no stacked statements, no DDL,
  • confirm: true is passed,
  • a DELETE or UPDATE carries a WHERE clause - a missing one is how a one-row fix becomes a wiped table. WHERE true is the escape hatch if the whole table really is the target.

The tool description tells the agent to treat db_execute as explicit-request-only - never as cleanup, never to tidy up test data it created, never to make a test pass. The guards above are the backstop for when that instruction is ignored.

Run standalone

npx @warpfx/mcp                 # anywhere
bun packages/mcp/src/index.ts   # in this repo, no build step

Speaks MCP over stdio - stdout is the protocol channel, so it prints nothing on start.

Tests

bun packages/mcp/test.ts

Drives the server over real stdio JSON-RPC. Covers protocol wiring, tool registration, native matching, log tailing, and every failure path that must stay a clean error rather than a hang - unreachable server, unreachable probe, missing window, unconfigured paths.

The db_execute guards are tested exhaustively and all reject before the CLI is ever spawned, so the suite never touches a real database. That is deliberate: the day one of those stops rejecting, an agent can quietly destroy data.