Metadata-Version: 2.5
Name: message-from-aliens-mcp
Version: 0.1.0
Summary: MCP server for reading, clicking, annotating, and inspecting glyphs in Message From Aliens
License: MIT
License-File: LICENSE
Keywords: game,mcp,model-context-protocol,reverse-engineering,windows
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Requires-Python: >=3.10
Requires-Dist: frida<18,>=17.26.2
Requires-Dist: mcp<3,>=1.30
Requires-Dist: pillow<14,>=10
Requires-Dist: windows-capture<3,>=2.0.1; sys_platform == 'win32'
Description-Content-Type: text/markdown

# Message From Aliens MCP

An MCP server for **Message From Aliens**, a game about deciphering a pictographic
alien language. Let a model read the current page, inspect character shapes,
click characters, and save your annotations.

Reading, clicking, and annotating work in the background without moving the
system mouse or activating the game window. Launching the game may bring Steam
or the new game window to the foreground.

## Requirements

- Windows x64. Linux and macOS are not supported.
- An installed copy of [Message From Aliens on Steam](https://store.steampowered.com/app/1858720/),
  with Steam available and signed in.
- [uv](https://docs.astral.sh/uv/getting-started/installation/) for the recommended
  setup, and an MCP client that supports local stdio servers.
- Python 3.10 or later; uv can provision a compatible interpreter when needed.
- Run the server as the same Windows user and at the same privilege level as
  the game.
- Screenshot mode requires Windows.Graphics.Capture support and a visible,
  non-minimized game window. Image results require an MCP client and model that
  support image content; table, ASCII, and path results are plain text.

The game integration has been verified with the Windows x64 IL2CPP build using
Unity `6000.6.6f1`. Game updates may require integration changes.

## Setup

After the package is published to PyPI, add this stdio server configuration to
your MCP client:

```json
{
  "mcpServers": {
    "message-from-aliens": {
      "command": "uvx",
      "args": ["message-from-aliens-mcp"]
    }
  }
}
```

Restart or reconnect the MCP client after changing its configuration. If it
cannot find `uvx`, use the absolute path to `uvx.exe` as `command`.

uvx installs the package and dependencies into an isolated environment on demand;
a separate `pip install` is unnecessary. To pin a published version, use
`"args": ["message-from-aliens-mcp==0.1.0"]`.

To try the server from a source checkout before publication:

```powershell
uv run message-from-aliens-mcp --help
```

For a persistent installation after publication:

```powershell
uv tool install message-from-aliens-mcp
```

The `aliens-mcp` command remains available as a compatibility alias.

## Tools

All grid coordinates are zero-based: rows `0..8` run from top to bottom, and
columns `0..23` run from left to right.

| Tool | Purpose |
| --- | --- |
| `launch_game()` | Start the game through Steam, or connect to an existing instance. |
| `look(type="table", force=False)` | Read the current 9x24 grid with annotations and layout markers. |
| `look(type="screenshot", force=False)` | Capture the game window as a PNG, with pixel dimensions and window style. |
| `click(row, col, type="left")` | Click a character with the left or right button; return the target and outcome. |
| `note(row, col, text)` | Save an annotation for every occurrence of the selected character. |
| `glyph(hash, format="image")` | Inspect a character as a PNG, ASCII art, or coordinate paths. |

### Reading and identifying characters

Table cells use `hash:annotation`, such as `abcd:my note`. Hashes contain four
lowercase letters or digits. The same character keeps its hash across pages in
the current connection. After a reconnect or game restart, call `look` again to
obtain current hashes.

The table preserves dividers and marks underlines with `\underline{...}`,
highlights with `\hl{...}`, dim text with `\dim{...}`, and frames with `[...]`.
Annotations reflect the game's live text, including automatic number and unit
translations when enabled.

Table and screenshot modes keep separate in-memory caches. Each call reads the
current state; an identical result produces a short unchanged message instead
of repeating the content. Use `force=True` to request the full result.

Screenshots capture only the game window, including its borders when present.
An occluded window can be captured without activating or resizing it. Use table
coordinates for `click` and `note`.

### Clicking and annotating

Choose coordinates from the current table. `click` accepts `type="left"` or
`type="right"` and reports its target in the same format as `look`. Call `look`
after an interaction to inspect the new page. Empty or inactive cells are
rejected. Background clicks with an unfocused window have been verified;
minimized-window clicking has not been separately verified.

If a click requests external navigation, the server returns the requested URLs
and prevents that click from opening a browser. If the game closes, the result
directs the model to `launch_game()`. The MCP server remains available.

`note` updates all occurrences across pages and saves through the game's normal
annotation handler. Text must be one line of at most 49 UTF-16 units. An empty
string clears the annotation.

### Character shapes

`glyph` accepts a hash from the current `look` and returns one selected format:

- `"image"` (default): a PNG drawn from the game's vector geometry, without a
  screenshot. Resolution adapts from 512 to 2048 pixels square.
- `"ascii"`: spaces and `#` on an adaptive grid, at least 10x10 and capped at
  121 rows by 241 columns. Display it in a monospaced font. Very close strokes
  may merge at the size cap.
- `"paths"`: JSON polylines fitted proportionally into a 100x100 coordinate
  range. The origin is top-left, x increases right, and y increases down.
  Connect consecutive points within each path only. A repeated first point
  closes the path; a single point is a dot. These are drawing paths, not a
  writing stroke order.

Character shapes and tables do not expose the game's internal word keys or
meanings.

## Troubleshooting

| Problem | Action |
| --- | --- |
| The game is not running | Call `launch_game()`. Other tools do not start it automatically. |
| Launch times out | Check that Steam is signed in and the game can launch normally, then retry. |
| The server cannot attach | Check the Windows user and privilege level of both processes. |
| Screenshot fails while minimized | Restore the game window. It can remain behind other windows. |
| Images are missing in the client | Use table mode and `glyph(format="ascii")` or `glyph(format="paths")`. |
| A hash is unknown after reconnecting | Read a fresh table with `look`. |
| Frida cannot write its temporary files | Set `ALIENS_MCP_TMP` to a writable directory in the server environment. |

## Development

From a source checkout:

```powershell
uv sync
uv run python -B -m unittest discover -s tests -v
uv run message-from-aliens-mcp --status
uv run message-from-aliens-mcp --look
```

Without CLI options, the command serves MCP over stdio. `--status` checks the
game connection; `--look` prints the current table. `--look --json` prints JSON.
`--look --raw` exposes internal word keys for development and can spoil puzzles.

See [runtime notes](docs/runtime.md) for implementation details and
[release checks](docs/releasing.md) for compatibility tests and publication.

## License

MIT; see [LICENSE](LICENSE). This is an unofficial integration. Game assets,
decompiled game code, saves, and player annotation files are not distributed.
The server instruments the running game with Frida and does not patch game files.
