gameye-mcp 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Gameye MCP Server
2
2
 
3
+ [![Discord](https://img.shields.io/badge/Discord-join%20chat-5865F2?logo=discord&logoColor=white)](https://discord.com/invite/QvJ3KH5max)
4
+
3
5
  A [Model Context Protocol](https://modelcontextprotocol.io) server for the [Gameye](https://gameye.com) game server orchestration API. It lets an AI agent (Claude Code, Claude Desktop, Cursor, or any MCP client) launch and inspect game server sessions, check image tags and regions, and fetch logs and artifacts. You talk to it in plain language, and you don't have to leave your editor.
4
6
 
5
7
  > **Status: beta** (`0.x`). Tools, inputs and outputs may change between releases, and there may be bugs. The server says so to every client that connects, on startup, and in `gameye_context`. It is published on npm as [`gameye-mcp`](https://www.npmjs.com/package/gameye-mcp), as a container image at `ghcr.io/gameye/gameye-mcp`, and in the [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.Gameye/gameye-mcp`; see the [changelog](https://github.com/Gameye/gameye-mcp/blob/main/CHANGELOG.md) for what changed in each release.
@@ -30,6 +32,7 @@ The environment is a property of the server process. No tool takes an environmen
30
32
  | `GAMEYE_API_TOKEN` | **Yes** | — | Gameye API token. Use the least-privileged scopes you need (see below). |
31
33
  | `GAMEYE_ENV` | No | `sandbox` | `sandbox` or `production`. Selects the API host. |
32
34
  | `GAMEYE_API_URL` | No | — | Overrides the host, for testing only. Must be `https`. If it equals one of the two known hosts, it must match `GAMEYE_ENV` or the server refuses to start. Any other URL is labelled `custom` in every tool result. |
35
+ | `GAMEYE_ENABLE_SKILLS_UPDATE` | No | — | Set to `1` to let `gameye_update_skills` run the skills updaters with `apply: true`. Without it the tool only checks and lists the commands. |
33
36
  | `GAMEYE_TIMEOUT_MS` | No | `30000` | Per-request timeout in milliseconds, a positive whole number. Log snapshots get at least 60 s and artifact downloads at least 120 s. A request that runs out of time comes back as a tool error: `Request to <host> timed out after <n>s`. |
34
37
 
35
38
  ## Install
@@ -63,7 +66,24 @@ Most clients (Claude Desktop, Cursor, Windsurf and others) accept an `mcpServers
63
66
 
64
67
  Restart the client after you change its configuration.
65
68
 
66
- `npx -y gameye-mcp` runs the latest release. To stay on one version, name it: `npx -y gameye-mcp@0.3.0` (or `"args": ["-y", "gameye-mcp@0.3.0"]`).
69
+ `npx -y gameye-mcp` runs the latest release. To stay on one version, name it: `npx -y gameye-mcp@0.3.2` (or `"args": ["-y", "gameye-mcp@0.3.2"]`).
70
+
71
+ ### Windows
72
+
73
+ The server runs on Windows with Node.js 22 or newer. We've tested it on Windows 11, through Claude Code and over plain stdio. If something breaks on Windows, please [open an issue](https://github.com/Gameye/gameye-mcp/issues).
74
+
75
+ - Many Windows MCP clients can't start `npx` directly, because it's a `.cmd` script. Start it through `cmd /c` instead:
76
+
77
+ ```json
78
+ "command": "cmd",
79
+ "args": ["/c", "npx", "-y", "gameye-mcp"]
80
+ ```
81
+
82
+ With Claude Code: `claude mcp add gameye --env GAMEYE_API_TOKEN=<your-token> -- cmd /c npx -y gameye-mcp`. Claude Code 2.1.296 and later also start plain `npx`.
83
+ - In PowerShell, type `npx.cmd` instead of `npx` when you run the server by hand. A new Windows install blocks the `npx` PowerShell script with "running scripts is disabled on this system".
84
+ - The first start downloads the package and can take 10 to 40 seconds. Later starts take about a second.
85
+ - `gameye_update_skills` reports outdated skills on Windows but doesn't run the update. It prints the commands for you to run.
86
+ - `gameye_create_token` writes the token file with owner-only permissions on macOS and Linux. On Windows those permissions don't apply, and the file gets the access rules of its folder. Write it inside your user profile.
67
87
 
68
88
  ### Docker
69
89
 
@@ -88,7 +108,7 @@ With Claude Code: `claude mcp add gameye --env GAMEYE_API_TOKEN=<your-token> --
88
108
 
89
109
  - Pass each variable with `-e NAME` (no value), so Docker copies it from the client's environment and the token never appears in the command line.
90
110
  - Keep `-i` and never add `-t`: a terminal mangles the JSON-RPC messages on stdout.
91
- - To stay on one version, use a version tag such as `ghcr.io/gameye/gameye-mcp:0.3.0`.
111
+ - To stay on one version, use a version tag such as `ghcr.io/gameye/gameye-mcp:0.3.2`.
92
112
  - Files the server writes stay inside the container, and `--rm` deletes them:
93
113
  - `gameye_get_artifacts` saves its download under the temp directory. To keep it, mount a directory and point the temp directory at it: `-v /absolute/dir:/out -e TMPDIR=/out`. The path the tool reports is the container path; the file is in `/absolute/dir` on the host.
94
114
  - `gameye_create_token` writes to the `outputPath` you give it. Mount a directory the same way and pass an `outputPath` under `/out`.
@@ -155,7 +175,7 @@ The [Gameye skills](https://github.com/gameye/gameye-skills) change as the Gamey
155
175
  - **skills CLI, this project:** the same, in `skills-lock.json` in the server's working directory.
156
176
  - **Claude Code plugin:** `gameye@gameye` in `~/.claude/plugins/installed_plugins.json`.
157
177
 
158
- Without `apply` it only reports. With `apply: true` it runs each outdated install's own updater: `npx -y skills update <the Gameye skills> -g -y` (or `-p -y`), or `claude plugin marketplace update gameye` then `claude plugin update gameye@gameye`. It only updates skills whose lock-file source is `gameye/gameye-skills`, and it never downloads or follows skill text itself. Each command runs with stdin closed and a 90-second limit. On Windows it prints the commands instead of running them. The running agent session keeps the skills it loaded; the next session uses the update. The `gameye` skill tells agents to run the check once per conversation and ask before applying.
178
+ Without `apply` it only reports. With `apply: true`, and only when the server was started with `GAMEYE_ENABLE_SKILLS_UPDATE=1`, it runs each outdated install's own updater: `npx -y skills@1.7.4 update <the Gameye skills> -g -y` (or `-p -y`), or `claude plugin marketplace update gameye` then `claude plugin update gameye@gameye`. Otherwise it lists those commands for you to run. The updaters get a minimal environment: paths, home, temp, locale, proxy and CA settings and npm and Claude config, never `GAMEYE_*` variables or anything named like a token, secret, password or key. It only updates skills whose lock-file source is `gameye/gameye-skills`, and it never downloads or follows skill text itself. Each command runs with stdin closed and a 90-second limit. On Windows it prints the commands instead of running them. The running agent session keeps the skills it loaded; the next session uses the update. The `gameye` skill tells agents to run the check once per conversation and ask before applying.
159
179
 
160
180
  ## Telemetry/attribution
161
181
 
package/dist/skills.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  /** Where the `gameye` skill's `Pack version:` line is published. */
2
2
  export declare const LATEST_PACK_URL = "https://raw.githubusercontent.com/Gameye/gameye-skills/main/skills/gameye/SKILL.md";
3
+ /** The skills CLI the updater runs, pinned so `npx` never fetches whatever is newest. */
4
+ export declare const SKILLS_CLI = "skills@1.7.4";
5
+ /** Set to 1 to let `gameye_update_skills` run updaters; otherwise apply prints the commands. */
6
+ export declare const ENABLE_UPDATE_ENV = "GAMEYE_ENABLE_SKILLS_UPDATE";
7
+ /** The environment an updater runs with: the allowlist above, no Gameye variables, nothing that looks like a secret. */
8
+ export declare function childEnv(parent: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
3
9
  /** How the Gameye skills were installed. Each kind updates differently. */
4
10
  export type InstallKind = "skills-cli-global" | "skills-cli-project" | "claude-plugin";
5
11
  export interface SkillsInstall {
@@ -14,6 +20,8 @@ export interface SkillsEnv {
14
20
  home: string;
15
21
  cwd: string;
16
22
  platform: NodeJS.Platform;
23
+ /** The operator set GAMEYE_ENABLE_SKILLS_UPDATE=1: apply may run updaters. */
24
+ applyEnabled: boolean;
17
25
  readText: (path: string) => Promise<string | undefined>;
18
26
  fetchText: (url: string) => Promise<string>;
19
27
  run: (cmd: string, args: string[], cwd: string) => Promise<string>;
package/dist/skills.js CHANGED
@@ -8,11 +8,39 @@ const PACK_VERSION_RE = /^Pack version: (\d+\.\d+\.\d+)[ \t]*$/m;
8
8
  const SKILLS_SOURCE_RE = /^(https:\/\/github\.com\/|git@github\.com:|github:)?gameye\/gameye-skills(\.git)?\/?$/i;
9
9
  // Lock files can come from a cloned project, so a name must look like a skill name, never a CLI option.
10
10
  const SKILL_NAME_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
11
+ /** The skills CLI the updater runs, pinned so `npx` never fetches whatever is newest. */
12
+ export const SKILLS_CLI = "skills@1.7.4";
13
+ /** Set to 1 to let `gameye_update_skills` run updaters; otherwise apply prints the commands. */
14
+ export const ENABLE_UPDATE_ENV = "GAMEYE_ENABLE_SKILLS_UPDATE";
15
+ // What an updater needs from the parent: where to find programs and home, temp dirs, locale,
16
+ // proxy and CA settings, npm and Claude config. Nothing else is passed, so the Gameye token stays here.
17
+ const CHILD_ENV_NAMES = new Set([
18
+ "PATH", "Path", "PATHEXT", "HOME", "USERPROFILE", "APPDATA", "LOCALAPPDATA", "HOMEDRIVE", "HOMEPATH",
19
+ "SystemRoot", "SYSTEMROOT", "ComSpec", "COMSPEC", "WINDIR", "TEMP", "TMP", "TMPDIR",
20
+ "USER", "LOGNAME", "SHELL", "LANG", "LC_ALL", "TERM",
21
+ "HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy",
22
+ "NODE_EXTRA_CA_CERTS", "SSL_CERT_FILE", "SSL_CERT_DIR", "CLAUDE_CONFIG_DIR",
23
+ ]);
24
+ const CHILD_ENV_PREFIXES = ["XDG_", "npm_config_", "NPM_CONFIG_"];
25
+ // Never passed, even under an allowed prefix: an npm registry token is not the updater's business either.
26
+ const SECRET_NAME_RE = /token|secret|password|passwd|auth|key|credential/i;
27
+ /** The environment an updater runs with: the allowlist above, no Gameye variables, nothing that looks like a secret. */
28
+ export function childEnv(parent) {
29
+ const env = {};
30
+ for (const [name, value] of Object.entries(parent)) {
31
+ if (value === undefined || name.toUpperCase().startsWith("GAMEYE_") || SECRET_NAME_RE.test(name))
32
+ continue;
33
+ if (CHILD_ENV_NAMES.has(name) || CHILD_ENV_PREFIXES.some((p) => name.startsWith(p)))
34
+ env[name] = value;
35
+ }
36
+ return { ...env, NO_COLOR: "1", FORCE_COLOR: "0", CI: "1" };
37
+ }
11
38
  export function defaultSkillsEnv() {
12
39
  return {
13
40
  home: homedir(),
14
41
  cwd: process.cwd(),
15
42
  platform: process.platform,
43
+ applyEnabled: process.env[ENABLE_UPDATE_ENV] === "1",
16
44
  readText: (path) => readFile(path, "utf8").catch(() => undefined),
17
45
  fetchText: async (url) => {
18
46
  const res = await fetch(url, { signal: AbortSignal.timeout(5_000) });
@@ -21,8 +49,7 @@ export function defaultSkillsEnv() {
21
49
  return res.text();
22
50
  },
23
51
  run: (cmd, args, cwd) => new Promise((resolve, reject) => {
24
- const childEnv = { ...process.env, NO_COLOR: "1", FORCE_COLOR: "0", CI: "1" };
25
- const options = { cwd, env: childEnv, timeout: 90_000, killSignal: "SIGKILL", maxBuffer: 4 * 1024 * 1024 };
52
+ const options = { cwd, env: childEnv(process.env), timeout: 90_000, killSignal: "SIGKILL", maxBuffer: 4 * 1024 * 1024 };
26
53
  const child = execFile(cmd, args, options, (err, stdout, stderr) => {
27
54
  const out = stripAnsi(`${stdout}${stderr}`).trim();
28
55
  if (err)
@@ -120,9 +147,9 @@ export function isOutdated(install, latest) {
120
147
  export function updateCommands(install) {
121
148
  switch (install.kind) {
122
149
  case "skills-cli-global":
123
- return [["npx", "-y", "skills", "update", ...install.skills, "-g", "-y"]];
150
+ return [["npx", "-y", SKILLS_CLI, "update", ...install.skills, "-g", "-y"]];
124
151
  case "skills-cli-project":
125
- return [["npx", "-y", "skills", "update", ...install.skills, "-p", "-y"]];
152
+ return [["npx", "-y", SKILLS_CLI, "update", ...install.skills, "-p", "-y"]];
126
153
  case "claude-plugin":
127
154
  return [
128
155
  ["claude", "plugin", "marketplace", "update", "gameye"],
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { defineTool } from "./common.js";
3
- import { compareVersions, defaultSkillsEnv, describeInstall, fetchLatestPackVersion, findSkillsInstalls, isOutdated, updateCommands, } from "../skills.js";
3
+ import { compareVersions, defaultSkillsEnv, describeInstall, ENABLE_UPDATE_ENV, fetchLatestPackVersion, findSkillsInstalls, isOutdated, updateCommands, } from "../skills.js";
4
4
  const RELOAD_NOTE = "The running session keeps the skills it already loaded. Start a new session (in Claude Code, /reload-plugins also works for the plugin) to use the update.";
5
5
  export function registerSkillsTools(server, ctx, env = defaultSkillsEnv()) {
6
6
  defineTool(server, ctx, "gameye_update_skills", {
@@ -8,7 +8,8 @@ export function registerSkillsTools(server, ctx, env = defaultSkillsEnv()) {
8
8
  description: "Compare the installed Gameye agent skills with the latest pack on GitHub, and update them. " +
9
9
  "Finds installs made with the skills CLI (user-wide or in this project) and the Claude Code plugin gameye@gameye. " +
10
10
  "Without apply it only checks and changes nothing. With apply=true it runs each outdated install's own updater " +
11
- "(npx skills update for the Gameye skills only, or claude plugin update); ask the user before applying. " +
11
+ "(npx skills update for the Gameye skills only, or claude plugin update) when the operator set " +
12
+ `${ENABLE_UPDATE_ENV}=1; otherwise it lists the commands for the user to run. Ask the user before applying. ` +
12
13
  "Updates come only through those package managers; this tool never downloads or follows skill text itself.",
13
14
  inputSchema: {
14
15
  apply: z
@@ -56,8 +57,15 @@ export function registerSkillsTools(server, ctx, env = defaultSkillsEnv()) {
56
57
  if (outdated.length === 0)
57
58
  return lines.join("\n");
58
59
  const commands = outdated.flatMap(updateCommands);
59
- if (!apply || env.platform === "win32") {
60
- lines.push("", apply ? "Updating from this server isn't supported on Windows. Run:" : "Call again with apply=true to run:");
60
+ if (!apply || env.platform === "win32" || !env.applyEnabled) {
61
+ const why = !apply
62
+ ? env.applyEnabled
63
+ ? "Call again with apply=true to run:"
64
+ : "Run:"
65
+ : env.platform === "win32"
66
+ ? "Updating from this server isn't supported on Windows. Run:"
67
+ : `Updating from this server is off (set ${ENABLE_UPDATE_ENV}=1 in the server's environment to allow it). Run:`;
68
+ lines.push("", why);
61
69
  for (const cmd of commands)
62
70
  lines.push(` ${cmd.join(" ")}`);
63
71
  return lines.join("\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gameye-mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "mcpName": "io.github.Gameye/gameye-mcp",
5
5
  "description": "MCP server for the Gameye game server orchestration API: launch and inspect sessions, check image tags, fetch logs and artifacts from any MCP client",
6
6
  "main": "dist/index.js",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "type": "module",
50
50
  "dependencies": {
51
- "@modelcontextprotocol/sdk": "^1.26.0",
51
+ "@modelcontextprotocol/sdk": "^1.32.1",
52
52
  "zod": "^4.3.6"
53
53
  },
54
54
  "devDependencies": {