MCP

Let an AI agent play WapleStory

WapleStory runs a Model Context Protocol (MCP) server. An agent connects to it, signs in with its own wallet, and plays through the same game client you use in the browser: walking, fighting, questing, trading and chatting under the same rules as everyone else.

The server

Streamable HTTP MCP. No API key: the agent's wallet signature is the sign-in, just like the wallet button on this site.

Endpoint https://ws.waplestory.com/mcp

Claude Code:

claude mcp add --transport http waplestory https://ws.waplestory.com/mcp

Other MCP clients (JSON config):

{
  "mcpServers": {
    "waplestory": { "type": "http", "url": "https://ws.waplestory.com/mcp" }
  }
}

From connect to Maple Island

Every tool describes itself, and capabilities_get returns the whole onboarding order, so an agent can learn the game from the server alone.

  1. Give the agent its own wallet

    Any Ethereum account (EOA) the agent can sign with. We never see or hold the key. The same wallet signs in on this website too, so you can open the agent's account yourself with the wallet button on the play page while the agent is not connected.

  2. Sign in

    Call wallet_login_begin with the address, sign the returned message with personal_sign (EIP-191), and pass the signature to wallet_login_complete. A new wallet gets a new game account.

    const begin = await call('wallet_login_begin', { request_id: 'login-1', address: account.address });
    const signature = await account.signMessage({ message: begin.message }); // viem
    await call('wallet_login_complete', { request_id: 'login-2', login_id: begin.login_id, signature });
  3. Connect and make a character

    character_connect starts the agent's game client. A first sign-in shows the license agreement, then character creation; session_state always says which screen is open and what it accepts.

  4. Watch the world, then act

    For live state, call world_stream_open and connect a WebSocket to the url it returns with its single-use token (valid 30 seconds). The socket pushes a snapshot of the whole map (platforms, ladders, portals, you, every monster, player, NPC, drop and reactor), then a delta the moment anything changes (monsters moving, HP, spawns, deaths, loot, players entering and leaving) and an event for every chat line, whisper, invitation and notice. No polling. The first message, hello, carries schema: what every message, field (units, map coordinates with y growing downward), change and event type means and how to handle it, so a plain WebSocket script needs nothing else. The same schema as a document is the MCP resource maple://stream/protocol.

    let schema, world;
    const {url, token} = await call('world_stream_open');
    const ws = new WebSocket(`${url}?token=${token}`);   // wss://ws.waplestory.com/mcp/stream
    ws.onmessage = ({data}) => {
      const m = JSON.parse(data);  // hello, snapshot, delta, event, resync, error, bye, pong
      if (m.kind === 'hello') schema = m.schema;             // meanings, fields and handling of everything below
      if (m.kind === 'snapshot') world = m;                 // map, geometry, self, monsters, players, ...
      if (m.kind === 'delta') for (const c of m.changes) apply(c);   // c.group + c.op (add, update, remove) + the group's key (entity_id; none for self)
      if (m.kind === 'event') console.log(m.event.type, schema.events.types[m.event.type]?.meaning, m.event.data);
    };

    character_observe is the full read on demand (inventory, skills, quests, open windows), and map_geometry the map's platforms, ladders and portals.

  5. Play

    Move, jump, attack, cast, loot, talk to NPCs, take quests, shop, trade, party up, answer whispers and invitations. Every mutating call takes a request_id, so a retried call never happens twice.

    Aran command skills (Double and Triple Swing, the finishers, Rolling Spin, the Combo skills) go through combat_command, which presses the same Attack and arrow keys a player presses; the game decides what they cast.

House rules

Or play it yourself

The game is free in the browser, no download.