summer-engine 3.4.1 → 3.5.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +5 -1
- package/.codex-plugin/plugin.json +5 -1
- package/.cursor-plugin/plugin.json +5 -1
- package/.factory-plugin/plugin.json +5 -1
- package/CHANGELOG.md +31 -0
- package/README.md +5 -1
- package/dist/cli/commands/setup.js +24 -4
- package/dist/core/capabilities/capture-gameplay.d.ts +72 -7
- package/dist/core/capabilities/capture-gameplay.js +386 -25
- package/dist/core/capabilities/export-engine-version.d.ts +7 -0
- package/dist/core/capabilities/export-engine-version.js +9 -0
- package/dist/core/capabilities/export-game.d.ts +4 -0
- package/dist/core/capabilities/export-game.js +50 -7
- package/dist/core/capabilities/image-generation.d.ts +12 -2
- package/dist/core/capabilities/image-generation.js +31 -2
- package/dist/core/capabilities/publish-build.d.ts +4 -0
- package/dist/core/capabilities/publish-build.js +84 -37
- package/dist/core/capabilities/runtime-control.d.ts +2 -2
- package/dist/core/capabilities/summer-bundle.d.ts +9 -0
- package/dist/core/capabilities/summer-bundle.js +19 -0
- package/dist/core/capabilities/tool-dispatch.js +13 -2
- package/dist/core/library-read.d.ts +7 -0
- package/dist/core/library-read.js +59 -7
- package/dist/core/library-search.d.ts +2 -0
- package/dist/installer/agent-config.d.ts +26 -1
- package/dist/installer/agent-config.js +180 -5
- package/dist/installer/agent-table.d.ts +13 -0
- package/dist/installer/agent-table.js +120 -0
- package/dist/mcp/tools/creator-tools.js +32 -3
- package/dist/mcp/tools/generate-tools.js +11 -30
- package/dist/mcp/tools/library-tools.d.ts +2 -1
- package/dist/mcp/tools/library-tools.js +1 -0
- package/gemini-extension.json +5 -1
- package/integrations/README.md +6 -0
- package/library/references/mcp-tools-reference/mcp-tools-reference.md +1 -1
- package/library/skills/README.md +11 -1
- package/library/skills/export-and-ship/SKILL.md +1 -1
- package/library/skills/export-and-ship/resource.yaml +2 -1
- package/library/skills/grow-analytics/SKILL.md +21 -0
- package/library/skills/grow-analytics/resource.yaml +27 -0
- package/library/skills/publish-your-game/SKILL.md +21 -0
- package/library/skills/publish-your-game/resource.yaml +29 -0
- package/library/skills/store-art/SKILL.md +23 -0
- package/library/skills/store-art/resource.yaml +30 -0
- package/library/skills/store-listing/SKILL.md +21 -0
- package/library/skills/store-listing/resource.yaml +25 -0
- package/library/skills/summer-analytics/resource.yaml +1 -0
- package/library/tools/capture-gameplay/resource.yaml +66 -1
- package/library/tools/export-game/resource.yaml +3 -0
- package/library/tools/generate-image/resource.yaml +4 -2
- package/package.json +1 -1
- package/registry/generated/counts.json +2 -2
- package/registry/generated/gemini-extension.json +5 -1
- package/registry/generated/index.json +153 -10
- package/registry/generated/marketplace.claude.json +1 -1
- package/registry/generated/plugin.claude.json +5 -1
- package/registry/generated/plugin.codex.json +5 -1
- package/registry/generated/plugin.cursor.json +5 -1
- package/registry/generated/plugin.factory.json +5 -1
- package/registry/generated/skills-index.md +11 -1
- package/registry/generated/skills-registry.json +52 -0
- package/registry/schemas/skill.schema.json +5 -0
|
@@ -73,6 +73,180 @@ export async function configureAgentMcp(options) {
|
|
|
73
73
|
nextSteps: [`Updated ${target.path}.`, spec.restart],
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
+
/** The Summer Games player MCP: friends, parties, messages and the player's
|
|
77
|
+
* inbox, as the signed-in player. A remote server; the agent signs in to it
|
|
78
|
+
* with OAuth in the browser, so setup writes no credential. */
|
|
79
|
+
export const SUMMER_GAMES_MCP_SERVER_NAME = "summer-games";
|
|
80
|
+
export const SUMMER_GAMES_MCP_URL = "https://mcp.summer.games/mcp";
|
|
81
|
+
/**
|
|
82
|
+
* Adds the Summer Games MCP next to summer-engine in the same config file, in
|
|
83
|
+
* the agent's own entry shape (remoteMcp in agent-table.ts). An entry that
|
|
84
|
+
* already points at the same URL, under any name, counts as added and is left
|
|
85
|
+
* as it is. Returns null for agents without remoteMcp.
|
|
86
|
+
*/
|
|
87
|
+
export async function configureSummerGamesMcp(options) {
|
|
88
|
+
const spec = agentSpec(options.agent);
|
|
89
|
+
if (!spec.remoteMcp)
|
|
90
|
+
return null;
|
|
91
|
+
const env = options.env ?? process.env;
|
|
92
|
+
const target = resolveConfigTarget(spec, options.scope, resolve(options.cwd ?? process.cwd()), env);
|
|
93
|
+
const write = !options.dryRun;
|
|
94
|
+
const url = SUMMER_GAMES_MCP_URL;
|
|
95
|
+
const name = SUMMER_GAMES_MCP_SERVER_NAME;
|
|
96
|
+
const entry = spec.remoteMcp.entry(url);
|
|
97
|
+
const key = topLevelKey(spec.format);
|
|
98
|
+
let existing;
|
|
99
|
+
let changed = false;
|
|
100
|
+
switch (spec.format) {
|
|
101
|
+
case "toml":
|
|
102
|
+
case "toml-array": {
|
|
103
|
+
const current = await readTextFileIfExists(target.path);
|
|
104
|
+
existing = spec.format === "toml" ? findTomlServerByUrl(current, url) : findTomlArrayServerByUrl(current, url);
|
|
105
|
+
if (existing)
|
|
106
|
+
break;
|
|
107
|
+
const next = spec.format === "toml"
|
|
108
|
+
? upsertTomlTable(current, renderTomlTable(`[mcp_servers.${name}]`, entry), name)
|
|
109
|
+
: upsertTomlArrayBlock(current, renderTomlTable("[[mcp_servers]]", entry), name);
|
|
110
|
+
changed = current !== next;
|
|
111
|
+
if (write && changed)
|
|
112
|
+
await writeTextFile(target.path, next);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case "yaml-goose":
|
|
116
|
+
case "yaml-hermes": {
|
|
117
|
+
const current = await readTextFileIfExists(target.path);
|
|
118
|
+
const parsed = current.trim() === "" ? {} : parseDocument(current).toJS();
|
|
119
|
+
existing = isJsonObject(parsed) ? findServerByUrl([parsed[key]], url) : undefined;
|
|
120
|
+
if (existing)
|
|
121
|
+
break;
|
|
122
|
+
({ changed } = await upsertYamlConfig(target.path, [key, name], entry, write));
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case "json-gemini":
|
|
126
|
+
throw new Error("The Gemini extension manifest has no Summer Games entry.");
|
|
127
|
+
default: {
|
|
128
|
+
const current = await readJsonConfig(target.path);
|
|
129
|
+
const maps = [current[key]];
|
|
130
|
+
// Claude Code's ~/.claude.json also keeps per-project servers (`claude
|
|
131
|
+
// mcp add` without --scope user) under projects.<dir>.mcpServers.
|
|
132
|
+
if (isJsonObject(current.projects)) {
|
|
133
|
+
for (const project of Object.values(current.projects)) {
|
|
134
|
+
if (isJsonObject(project))
|
|
135
|
+
maps.push(project.mcpServers);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
existing = findServerByUrl(maps, url);
|
|
139
|
+
if (existing)
|
|
140
|
+
break;
|
|
141
|
+
const next = copyJsonObject(current);
|
|
142
|
+
next[key] = mergeNamedObject(next[key], name, entry, key);
|
|
143
|
+
const nextRendered = renderJsonFile(next);
|
|
144
|
+
changed = renderJsonFile(current) !== nextRendered;
|
|
145
|
+
if (write && changed)
|
|
146
|
+
await writeTextFile(target.path, nextRendered);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const serverName = existing ?? name;
|
|
150
|
+
return {
|
|
151
|
+
serverName,
|
|
152
|
+
url,
|
|
153
|
+
path: target.path,
|
|
154
|
+
changed,
|
|
155
|
+
wrote: write && changed,
|
|
156
|
+
...(existing && existing !== name ? { existingName: existing } : {}),
|
|
157
|
+
signIn: spec.remoteMcp.signIn(serverName),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function sameMcpUrl(a, b) {
|
|
161
|
+
if (typeof a !== "string")
|
|
162
|
+
return false;
|
|
163
|
+
const normalize = (value) => {
|
|
164
|
+
try {
|
|
165
|
+
const parsed = new URL(value.trim());
|
|
166
|
+
return `${parsed.protocol}//${parsed.host}${parsed.pathname.replace(/\/+$/, "")}`.toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return value.trim().toLowerCase();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
return normalize(a) === normalize(b);
|
|
173
|
+
}
|
|
174
|
+
/** Agents name a remote server's address url, serverUrl (Windsurf,
|
|
175
|
+
* Antigravity), httpUrl (Qwen Code) or uri (Goose). */
|
|
176
|
+
const REMOTE_URL_FIELDS = ["url", "serverUrl", "httpUrl", "uri"];
|
|
177
|
+
/** The name of a server with this URL in any of these name -> entry maps. */
|
|
178
|
+
function findServerByUrl(maps, url) {
|
|
179
|
+
for (const map of maps) {
|
|
180
|
+
if (!isJsonObject(map))
|
|
181
|
+
continue;
|
|
182
|
+
for (const [name, entry] of Object.entries(map)) {
|
|
183
|
+
if (isJsonObject(entry) && REMOTE_URL_FIELDS.some((field) => sameMcpUrl(entry[field], url)))
|
|
184
|
+
return name;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
/** The name of a [[mcp_servers]] block (Mistral Vibe) whose url is this URL. */
|
|
190
|
+
function findTomlArrayServerByUrl(content, url) {
|
|
191
|
+
let block;
|
|
192
|
+
const done = () => (block?.matches ? block.name : undefined);
|
|
193
|
+
for (const line of content.split(/\r?\n/)) {
|
|
194
|
+
if (/^\s*\[/.test(line)) {
|
|
195
|
+
if (done())
|
|
196
|
+
return done();
|
|
197
|
+
block = /^\s*\[\[mcp_servers\]\]\s*(?:#.*)?$/.test(line) ? { matches: false } : undefined;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (!block)
|
|
201
|
+
continue;
|
|
202
|
+
const field = /^\s*(name|url)\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(line);
|
|
203
|
+
if (!field)
|
|
204
|
+
continue;
|
|
205
|
+
const value = field[2] ?? field[3];
|
|
206
|
+
if (field[1] === "name")
|
|
207
|
+
block.name = value;
|
|
208
|
+
else if (sameMcpUrl(value, url))
|
|
209
|
+
block.matches = true;
|
|
210
|
+
}
|
|
211
|
+
return done();
|
|
212
|
+
}
|
|
213
|
+
/** A TOML table: the header line, then key = value for each entry field. */
|
|
214
|
+
function renderTomlTable(header, entry) {
|
|
215
|
+
return `${[header, ...Object.entries(entry).map(([field, value]) => `${field} = ${tomlValue(value)}`)].join("\n")}\n`;
|
|
216
|
+
}
|
|
217
|
+
function tomlValue(value) {
|
|
218
|
+
if (typeof value === "string")
|
|
219
|
+
return tomlString(value);
|
|
220
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
221
|
+
return String(value);
|
|
222
|
+
if (Array.isArray(value))
|
|
223
|
+
return `[${value.map(tomlValue).join(", ")}]`;
|
|
224
|
+
if (isJsonObject(value)) {
|
|
225
|
+
const fields = Object.entries(value).map(([field, inner]) => `${field} = ${tomlValue(inner)}`);
|
|
226
|
+
return fields.length === 0 ? "{}" : `{ ${fields.join(", ")} }`;
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`Cannot write ${JSON.stringify(value)} as TOML.`);
|
|
229
|
+
}
|
|
230
|
+
/** The name of a [mcp_servers.<name>] table whose url is this URL. */
|
|
231
|
+
function findTomlServerByUrl(content, url) {
|
|
232
|
+
let table;
|
|
233
|
+
for (const line of content.split(/\r?\n/)) {
|
|
234
|
+
const header = /^\s*\[([^\[\]]+)\]\s*(?:#.*)?$/.exec(line);
|
|
235
|
+
if (header) {
|
|
236
|
+
const server = /^mcp_servers\.(?:"([^"]+)"|([A-Za-z0-9_-]+))$/.exec(header[1].trim());
|
|
237
|
+
table = server ? (server[1] ?? server[2]) : undefined;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (/^\s*\[/.test(line)) {
|
|
241
|
+
table = undefined;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const value = /^\s*url\s*=\s*(?:"([^"]*)"|'([^']*)')/.exec(line);
|
|
245
|
+
if (table && value && sameMcpUrl(value[1] ?? value[2], url))
|
|
246
|
+
return table;
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
76
250
|
async function upsertConfig(format, path, server, write) {
|
|
77
251
|
switch (format) {
|
|
78
252
|
case "toml":
|
|
@@ -320,10 +494,10 @@ async function upsertTomlArrayConfig(path, server, write) {
|
|
|
320
494
|
}
|
|
321
495
|
return { changed };
|
|
322
496
|
}
|
|
323
|
-
export function upsertTomlArrayBlock(content, block) {
|
|
497
|
+
export function upsertTomlArrayBlock(content, block, name = SUMMER_MCP_SERVER_NAME) {
|
|
324
498
|
const lines = content.split(/\r?\n/);
|
|
325
499
|
const header = /^\s*\[\[mcp_servers\]\]\s*(?:#.*)?$/;
|
|
326
|
-
const nameLine = new RegExp(`^\\s*name\\s*=\\s*"${
|
|
500
|
+
const nameLine = new RegExp(`^\\s*name\\s*=\\s*"${name}"\\s*(?:#.*)?$`);
|
|
327
501
|
let start = -1;
|
|
328
502
|
let end = lines.length;
|
|
329
503
|
for (let index = 0; index < lines.length; index += 1) {
|
|
@@ -470,10 +644,11 @@ async function readTextFileIfExists(path) {
|
|
|
470
644
|
throw new Error(`Could not read ${path}: ${formatError(error)}`);
|
|
471
645
|
}
|
|
472
646
|
}
|
|
473
|
-
function upsertTomlTable(content, table) {
|
|
647
|
+
function upsertTomlTable(content, table, name = SUMMER_MCP_SERVER_NAME) {
|
|
474
648
|
const lines = content.split(/\r?\n/);
|
|
475
|
-
const
|
|
476
|
-
const
|
|
649
|
+
const key = name.replace(/[.*+?^${}()|[\]\\-]/g, "\\$&");
|
|
650
|
+
const serverHeader = new RegExp(`^\\s*\\[mcp_servers\\.(?:"${key}"|${key})(?:\\.|\\])`);
|
|
651
|
+
const start = lines.findIndex((line) => new RegExp(`^\\s*\\[mcp_servers\\.(?:"${key}"|${key})\\]\\s*(?:#.*)?$`).test(line));
|
|
477
652
|
if (start === -1) {
|
|
478
653
|
const trimmed = content.endsWith("\n") || content === "" ? content : `${content}\n`;
|
|
479
654
|
return `${trimmed}${trimmed === "" ? "" : "\n"}${table}`;
|
|
@@ -70,6 +70,19 @@ export interface AgentSpec {
|
|
|
70
70
|
/** Env var that overrides the MCP config path (tests, unusual installs). */
|
|
71
71
|
envOverride: string;
|
|
72
72
|
format: McpFormat;
|
|
73
|
+
/**
|
|
74
|
+
* The Summer Games player MCP (a remote server that signs in with OAuth on
|
|
75
|
+
* its own) in this agent's file, under the same key as summer-engine.
|
|
76
|
+
* entry is the server's value; for TOML it is written as key = value lines.
|
|
77
|
+
* signIn tells the person how to sign in once, for the entry's name.
|
|
78
|
+
* Absent: setup links the engine only (no OAuth sign-in for remote servers,
|
|
79
|
+
* no file entry for them, or a sign-in api.summer.games has not been checked
|
|
80
|
+
* to accept).
|
|
81
|
+
*/
|
|
82
|
+
remoteMcp?: {
|
|
83
|
+
entry: (url: string) => Record<string, unknown>;
|
|
84
|
+
signIn: (name: string) => string;
|
|
85
|
+
};
|
|
73
86
|
mcp: {
|
|
74
87
|
/** null: user-level servers are managed in the app's UI; a user request writes the project file with a warning. */
|
|
75
88
|
user: ((ctx: PathContext) => string) | null;
|
|
@@ -108,6 +108,10 @@ const SPECS = [
|
|
|
108
108
|
status: "active",
|
|
109
109
|
envOverride: "SUMMER_CLAUDE_CONFIG_FILE",
|
|
110
110
|
format: "json-stdio",
|
|
111
|
+
remoteMcp: {
|
|
112
|
+
entry: (url) => ({ type: "http", url }),
|
|
113
|
+
signIn: (name) => `In Claude Code, run /mcp, choose ${name} and sign in.`,
|
|
114
|
+
},
|
|
111
115
|
mcp: { user: home(".claude.json"), project: project(".mcp.json") },
|
|
112
116
|
restart: "Restart Claude Code or run /mcp in a new session.",
|
|
113
117
|
skills: skillDirs(home(".claude", "skills"), project(".claude", "skills")),
|
|
@@ -119,6 +123,7 @@ const SPECS = [
|
|
|
119
123
|
status: "active",
|
|
120
124
|
envOverride: "SUMMER_CLAUDE_DESKTOP_CONFIG_FILE",
|
|
121
125
|
format: "json",
|
|
126
|
+
// No Summer Games entry: Claude Desktop's file takes local servers only; remote ones are added as Connectors in its settings.
|
|
122
127
|
mcp: {
|
|
123
128
|
user: (ctx) => join(appConfigRoot(ctx), "Claude", "claude_desktop_config.json"),
|
|
124
129
|
project: null,
|
|
@@ -134,6 +139,10 @@ const SPECS = [
|
|
|
134
139
|
status: "active",
|
|
135
140
|
envOverride: "SUMMER_CODEX_CONFIG_FILE",
|
|
136
141
|
format: "toml",
|
|
142
|
+
remoteMcp: {
|
|
143
|
+
entry: (url) => ({ url }),
|
|
144
|
+
signIn: (name) => `In Codex, run /mcp login ${name} (or \`codex mcp login ${name}\` in a terminal) and sign in.`,
|
|
145
|
+
},
|
|
137
146
|
mcp: {
|
|
138
147
|
user: home(".codex", "config.toml"),
|
|
139
148
|
project: project(".codex", "config.toml"),
|
|
@@ -149,6 +158,10 @@ const SPECS = [
|
|
|
149
158
|
status: "active",
|
|
150
159
|
envOverride: "SUMMER_CURSOR_MCP_CONFIG_FILE",
|
|
151
160
|
format: "json-stdio",
|
|
161
|
+
remoteMcp: {
|
|
162
|
+
entry: (url) => ({ url }),
|
|
163
|
+
signIn: (name) => `In Cursor Settings, open MCP and click Connect (or Authenticate) next to ${name}.`,
|
|
164
|
+
},
|
|
152
165
|
mcp: { user: home(".cursor", "mcp.json"), project: project(".cursor", "mcp.json") },
|
|
153
166
|
restart: "Restart Cursor and enable the summer-engine MCP server if prompted.",
|
|
154
167
|
skills: sharedSkills({
|
|
@@ -164,6 +177,10 @@ const SPECS = [
|
|
|
164
177
|
status: "active",
|
|
165
178
|
envOverride: "SUMMER_WINDSURF_MCP_CONFIG_FILE",
|
|
166
179
|
format: "json",
|
|
180
|
+
remoteMcp: {
|
|
181
|
+
entry: (url) => ({ serverUrl: url }),
|
|
182
|
+
signIn: (name) => `Devin Desktop opens summer.games in your browser the first time ${name} connects; sign in there.`,
|
|
183
|
+
},
|
|
167
184
|
mcp: {
|
|
168
185
|
user: home(".codeium", "windsurf", "mcp_config.json"),
|
|
169
186
|
project: null,
|
|
@@ -178,6 +195,10 @@ const SPECS = [
|
|
|
178
195
|
status: "active",
|
|
179
196
|
envOverride: "SUMMER_ANTIGRAVITY_CONFIG_FILE",
|
|
180
197
|
format: "json",
|
|
198
|
+
remoteMcp: {
|
|
199
|
+
entry: (url) => ({ serverUrl: url }),
|
|
200
|
+
signIn: (name) => `In Antigravity, open Settings > Customizations, choose Authenticate next to ${name}, sign in on summer.games, then paste the code back and choose Submit.`,
|
|
201
|
+
},
|
|
181
202
|
mcp: {
|
|
182
203
|
user: home(".gemini", "config", "mcp_config.json"),
|
|
183
204
|
project: project(".agents", "mcp_config.json"),
|
|
@@ -193,6 +214,7 @@ const SPECS = [
|
|
|
193
214
|
legacyNote: "Gemini CLI was retired for individual accounts on 2026-06-18 and replaced by Antigravity. Use `summer setup antigravity` unless you are on a Workspace/enterprise Gemini CLI.",
|
|
194
215
|
envOverride: "SUMMER_GEMINI_CONFIG_FILE",
|
|
195
216
|
format: "json-gemini",
|
|
217
|
+
// No Summer Games entry: legacy target; use antigravity.
|
|
196
218
|
mcp: {
|
|
197
219
|
user: home(".gemini", "extensions", "summer-engine", "gemini-extension.json"),
|
|
198
220
|
project: null,
|
|
@@ -207,6 +229,10 @@ const SPECS = [
|
|
|
207
229
|
status: "active",
|
|
208
230
|
envOverride: "SUMMER_CLINE_CONFIG_FILE",
|
|
209
231
|
format: "json",
|
|
232
|
+
remoteMcp: {
|
|
233
|
+
entry: (url) => ({ type: "streamableHttp", url }),
|
|
234
|
+
signIn: (name) => `In Cline, open MCP Servers and click Authenticate next to ${name}.`,
|
|
235
|
+
},
|
|
210
236
|
mcp: {
|
|
211
237
|
user: (ctx) => vsCodeGlobalStorage(ctx, "saoudrizwan.claude-dev", "cline_mcp_settings.json"),
|
|
212
238
|
project: null,
|
|
@@ -221,6 +247,10 @@ const SPECS = [
|
|
|
221
247
|
status: "active",
|
|
222
248
|
envOverride: "SUMMER_CLINE_CLI_CONFIG_FILE",
|
|
223
249
|
format: "json",
|
|
250
|
+
remoteMcp: {
|
|
251
|
+
entry: (url) => ({ type: "streamableHttp", url }),
|
|
252
|
+
signIn: (name) => `Run \`cline mcp\`, pick ${name} and choose Authorize OAuth.`,
|
|
253
|
+
},
|
|
224
254
|
mcp: { user: home(".cline", "data", "settings", "cline_mcp_settings.json"), project: null },
|
|
225
255
|
restart: "Restart the Cline CLI so it reloads its MCP settings.",
|
|
226
256
|
skills: skillDirs(home(".cline", "skills"), project(".cline", "skills")),
|
|
@@ -233,6 +263,7 @@ const SPECS = [
|
|
|
233
263
|
legacyNote: "Roo Code shut down on 2026-05-15. The extension may still run, but it is no longer maintained; consider Cline or Kilo Code.",
|
|
234
264
|
envOverride: "SUMMER_ROO_CODE_CONFIG_FILE",
|
|
235
265
|
format: "json",
|
|
266
|
+
// No Summer Games entry: Roo Code has no OAuth sign-in for remote MCP servers.
|
|
236
267
|
mcp: {
|
|
237
268
|
user: (ctx) => vsCodeGlobalStorage(ctx, "rooveterinaryinc.roo-cline", "cline_mcp_settings.json"),
|
|
238
269
|
project: null,
|
|
@@ -252,6 +283,10 @@ const SPECS = [
|
|
|
252
283
|
status: "active",
|
|
253
284
|
envOverride: "SUMMER_KILO_CODE_CONFIG_FILE",
|
|
254
285
|
format: "json-opencode",
|
|
286
|
+
remoteMcp: {
|
|
287
|
+
entry: (url) => ({ type: "remote", url }),
|
|
288
|
+
signIn: (name) => `In Kilo, click the sign-in notice for ${name} (Kilo CLI: \`kilo mcp auth ${name}\`).`,
|
|
289
|
+
},
|
|
255
290
|
mcp: {
|
|
256
291
|
user: (ctx) => join(xdgOrAppData(ctx), "kilo", "kilo.json"),
|
|
257
292
|
project: project("kilo.json"),
|
|
@@ -266,6 +301,10 @@ const SPECS = [
|
|
|
266
301
|
status: "active",
|
|
267
302
|
envOverride: "SUMMER_GITHUB_COPILOT_CONFIG_FILE",
|
|
268
303
|
format: "json-copilot",
|
|
304
|
+
remoteMcp: {
|
|
305
|
+
entry: (url) => ({ type: "http", url, tools: ["*"] }),
|
|
306
|
+
signIn: (name) => `Copilot CLI opens summer.games to sign in when ${name} first connects; /mcp signs in again.`,
|
|
307
|
+
},
|
|
269
308
|
mcp: { user: home(".copilot", "mcp-config.json"), project: project(".mcp.json") },
|
|
270
309
|
restart: "Restart Copilot CLI, or run /mcp reload and /skills reload in the active session.",
|
|
271
310
|
skills: skillDirs(home(".copilot", "skills"), project(".github", "skills")),
|
|
@@ -277,6 +316,10 @@ const SPECS = [
|
|
|
277
316
|
status: "active",
|
|
278
317
|
envOverride: "SUMMER_VSCODE_COPILOT_CONFIG_FILE",
|
|
279
318
|
format: "json-vscode",
|
|
319
|
+
remoteMcp: {
|
|
320
|
+
entry: (url) => ({ type: "http", url }),
|
|
321
|
+
signIn: (name) => `In VS Code, click Allow when ${name} asks to authenticate, then sign in on summer.games.`,
|
|
322
|
+
},
|
|
280
323
|
mcp: { user: (ctx) => join(vsCodeUserDir(ctx), "mcp.json"), project: project(".vscode", "mcp.json") },
|
|
281
324
|
restart: "Restart VS Code or run MCP: List Servers, then start summer-engine in Copilot Agent mode.",
|
|
282
325
|
skills: sharedSkills({ legacyDirs: { user: home(".copilot", "skills"), project: project(".github", "skills") } }),
|
|
@@ -288,6 +331,7 @@ const SPECS = [
|
|
|
288
331
|
status: "active",
|
|
289
332
|
envOverride: "SUMMER_VISUAL_STUDIO_CONFIG_FILE",
|
|
290
333
|
format: "json-vscode",
|
|
334
|
+
// No Summer Games entry: Visual Studio's OAuth redirect for MCP is not documented; not checked against api.summer.games.
|
|
291
335
|
mcp: { user: home(".mcp.json"), project: project(".mcp.json") },
|
|
292
336
|
restart: "Restart Visual Studio, open Copilot Chat in Agent mode, and enable summer-engine in the tools picker.",
|
|
293
337
|
skills: null,
|
|
@@ -300,6 +344,10 @@ const SPECS = [
|
|
|
300
344
|
status: "active",
|
|
301
345
|
envOverride: "SUMMER_COPILOT_JETBRAINS_CONFIG_FILE",
|
|
302
346
|
format: "json-servers",
|
|
347
|
+
remoteMcp: {
|
|
348
|
+
entry: (url) => ({ url }),
|
|
349
|
+
signIn: (name) => `In your JetBrains IDE, click OK when ${name} asks to authenticate, then sign in on summer.games.`,
|
|
350
|
+
},
|
|
303
351
|
mcp: {
|
|
304
352
|
user: (ctx) => join(xdgOrAppData(ctx), "github-copilot", "intellij", "mcp.json"),
|
|
305
353
|
project: null,
|
|
@@ -315,6 +363,10 @@ const SPECS = [
|
|
|
315
363
|
status: "active",
|
|
316
364
|
envOverride: "SUMMER_OPENCODE_CONFIG_FILE",
|
|
317
365
|
format: "json-opencode",
|
|
366
|
+
remoteMcp: {
|
|
367
|
+
entry: (url) => ({ type: "remote", url }),
|
|
368
|
+
signIn: (name) => `Run \`opencode mcp auth ${name}\`; it opens summer.games to sign in.`,
|
|
369
|
+
},
|
|
318
370
|
mcp: {
|
|
319
371
|
user: (ctx) => join(xdgOrAppData(ctx), "opencode", "opencode.json"),
|
|
320
372
|
project: project("opencode.json"),
|
|
@@ -333,6 +385,10 @@ const SPECS = [
|
|
|
333
385
|
status: "active",
|
|
334
386
|
envOverride: "SUMMER_ZED_CONFIG_FILE",
|
|
335
387
|
format: "json-zed",
|
|
388
|
+
remoteMcp: {
|
|
389
|
+
entry: (url) => ({ url }),
|
|
390
|
+
signIn: (name) => `In Zed, open the agent settings and click Authenticate next to ${name}.`,
|
|
391
|
+
},
|
|
336
392
|
mcp: {
|
|
337
393
|
user: (ctx) => join(xdgOrAppData(ctx), "zed", "settings.json"),
|
|
338
394
|
project: null,
|
|
@@ -347,6 +403,10 @@ const SPECS = [
|
|
|
347
403
|
status: "active",
|
|
348
404
|
envOverride: "SUMMER_KIRO_CONFIG_FILE",
|
|
349
405
|
format: "json",
|
|
406
|
+
remoteMcp: {
|
|
407
|
+
entry: (url) => ({ url }),
|
|
408
|
+
signIn: (name) => `Kiro opens summer.games to sign in when ${name} connects (Kiro CLI: /mcp auth).`,
|
|
409
|
+
},
|
|
350
410
|
mcp: { user: home(".kiro", "settings", "mcp.json"), project: project(".kiro", "settings", "mcp.json") },
|
|
351
411
|
restart: "Kiro reloads MCP config on save; open the MCP Servers view to confirm summer-engine is connected.",
|
|
352
412
|
skills: skillDirs(home(".kiro", "skills"), project(".kiro", "skills")),
|
|
@@ -358,6 +418,19 @@ const SPECS = [
|
|
|
358
418
|
status: "active",
|
|
359
419
|
envOverride: "SUMMER_GOOSE_CONFIG_FILE",
|
|
360
420
|
format: "yaml-goose",
|
|
421
|
+
remoteMcp: {
|
|
422
|
+
entry: (url) => ({
|
|
423
|
+
type: "streamable_http",
|
|
424
|
+
name: "summer-games",
|
|
425
|
+
description: "Summer Games: friends, parties and messages as you",
|
|
426
|
+
uri: url,
|
|
427
|
+
enabled: true,
|
|
428
|
+
timeout: 300,
|
|
429
|
+
env_keys: [],
|
|
430
|
+
envs: {},
|
|
431
|
+
}),
|
|
432
|
+
signIn: (name) => `Goose opens summer.games to sign in when the ${name} extension starts.`,
|
|
433
|
+
},
|
|
361
434
|
mcp: {
|
|
362
435
|
user: (ctx) => ctx.os === "win32"
|
|
363
436
|
? join(appData(ctx), "Block", "goose", "config", "config.yaml")
|
|
@@ -374,6 +447,10 @@ const SPECS = [
|
|
|
374
447
|
status: "active",
|
|
375
448
|
envOverride: "SUMMER_HERMES_CONFIG_FILE",
|
|
376
449
|
format: "yaml-hermes",
|
|
450
|
+
remoteMcp: {
|
|
451
|
+
entry: (url) => ({ url, auth: "oauth" }),
|
|
452
|
+
signIn: (name) => `Run \`hermes mcp login ${name}\`, or sign in on summer.games when Hermes first connects.`,
|
|
453
|
+
},
|
|
377
454
|
mcp: { user: home(".hermes", "config.yaml"), project: null },
|
|
378
455
|
restart: "Run /reload-mcp in Hermes Agent (or restart it).",
|
|
379
456
|
skills: skillDirs(home(".hermes", "skills"), SHARED_SKILLS_PROJECT, {
|
|
@@ -388,6 +465,10 @@ const SPECS = [
|
|
|
388
465
|
status: "active",
|
|
389
466
|
envOverride: "SUMMER_TRAE_CONFIG_FILE",
|
|
390
467
|
format: "json",
|
|
468
|
+
remoteMcp: {
|
|
469
|
+
entry: (url) => ({ url }),
|
|
470
|
+
signIn: (name) => `Trae opens summer.games to sign in when ${name} connects.`,
|
|
471
|
+
},
|
|
391
472
|
mcp: {
|
|
392
473
|
user: null,
|
|
393
474
|
project: project(".trae", "mcp.json"),
|
|
@@ -404,6 +485,10 @@ const SPECS = [
|
|
|
404
485
|
status: "active",
|
|
405
486
|
envOverride: "SUMMER_QWEN_CODE_CONFIG_FILE",
|
|
406
487
|
format: "json",
|
|
488
|
+
remoteMcp: {
|
|
489
|
+
entry: (url) => ({ httpUrl: url }),
|
|
490
|
+
signIn: (name) => `In Qwen Code, run /mcp auth ${name} and sign in.`,
|
|
491
|
+
},
|
|
407
492
|
mcp: { user: home(".qwen", "settings.json"), project: project(".qwen", "settings.json") },
|
|
408
493
|
restart: "Restart Qwen Code or run /mcp in a new session.",
|
|
409
494
|
skills: skillDirs(home(".qwen", "skills"), project(".qwen", "skills")),
|
|
@@ -415,6 +500,10 @@ const SPECS = [
|
|
|
415
500
|
status: "active",
|
|
416
501
|
envOverride: "SUMMER_KIMI_CODE_CONFIG_FILE",
|
|
417
502
|
format: "json",
|
|
503
|
+
remoteMcp: {
|
|
504
|
+
entry: (url) => ({ url, auth: "oauth" }),
|
|
505
|
+
signIn: (name) => `Run \`kimi mcp auth ${name}\`; it opens summer.games to sign in.`,
|
|
506
|
+
},
|
|
418
507
|
mcp: { user: home(".kimi-code", "mcp.json"), project: project(".kimi-code", "mcp.json") },
|
|
419
508
|
restart: "Restart Kimi Code CLI so it reconnects its MCP servers.",
|
|
420
509
|
skills: sharedSkills({ legacyDirs: { user: home(".kimi-code", "skills"), project: project(".kimi-code", "skills") } }),
|
|
@@ -426,6 +515,10 @@ const SPECS = [
|
|
|
426
515
|
status: "active",
|
|
427
516
|
envOverride: "SUMMER_CRUSH_CONFIG_FILE",
|
|
428
517
|
format: "json-crush",
|
|
518
|
+
remoteMcp: {
|
|
519
|
+
entry: (url) => ({ type: "http", url, oauth: true }),
|
|
520
|
+
signIn: (name) => `Crush opens summer.games to sign in when ${name} connects.`,
|
|
521
|
+
},
|
|
429
522
|
mcp: {
|
|
430
523
|
user: home(".config", "crush", "crushrc"),
|
|
431
524
|
project: project(".crushrc"),
|
|
@@ -440,6 +533,10 @@ const SPECS = [
|
|
|
440
533
|
status: "active",
|
|
441
534
|
envOverride: "SUMMER_AMP_CONFIG_FILE",
|
|
442
535
|
format: "json-amp",
|
|
536
|
+
remoteMcp: {
|
|
537
|
+
entry: (url) => ({ url }),
|
|
538
|
+
signIn: (name) => `Amp opens summer.games to sign in for ${name} when it starts.`,
|
|
539
|
+
},
|
|
443
540
|
mcp: { user: (ctx) => join(xdgOrAppData(ctx), "amp", "settings.json"), project: null },
|
|
444
541
|
restart: "Restart Amp so it reloads settings.json.",
|
|
445
542
|
skills: sharedSkills({ legacyDirs: { user: (ctx) => join(xdgOrAppData(ctx), "amp", "skills"), project: null } }),
|
|
@@ -451,6 +548,10 @@ const SPECS = [
|
|
|
451
548
|
status: "active",
|
|
452
549
|
envOverride: "SUMMER_FACTORY_CONFIG_FILE",
|
|
453
550
|
format: "json-stdio",
|
|
551
|
+
remoteMcp: {
|
|
552
|
+
entry: (url) => ({ type: "http", url }),
|
|
553
|
+
signIn: (name) => `In Droid, run /mcp, choose ${name} and Authenticate.`,
|
|
554
|
+
},
|
|
454
555
|
mcp: { user: home(".factory", "mcp.json"), project: project(".factory", "mcp.json") },
|
|
455
556
|
restart: "Restart droid or run /mcp in the active session.",
|
|
456
557
|
skills: sharedSkills({ legacyDirs: { user: home(".factory", "skills"), project: project(".factory", "skills") } }),
|
|
@@ -462,6 +563,10 @@ const SPECS = [
|
|
|
462
563
|
status: "active",
|
|
463
564
|
envOverride: "SUMMER_JUNIE_CONFIG_FILE",
|
|
464
565
|
format: "json",
|
|
566
|
+
remoteMcp: {
|
|
567
|
+
entry: (url) => ({ url }),
|
|
568
|
+
signIn: (name) => `In Junie, run /mcp, open ${name} and choose Authorize.`,
|
|
569
|
+
},
|
|
465
570
|
mcp: { user: home(".junie", "mcp", "mcp.json"), project: project(".junie", "mcp", "mcp.json") },
|
|
466
571
|
restart: "Restart the JetBrains IDE so Junie reloads its MCP config.",
|
|
467
572
|
skills: null,
|
|
@@ -474,6 +579,10 @@ const SPECS = [
|
|
|
474
579
|
status: "active",
|
|
475
580
|
envOverride: "SUMMER_WARP_CONFIG_FILE",
|
|
476
581
|
format: "json",
|
|
582
|
+
remoteMcp: {
|
|
583
|
+
entry: (url) => ({ url }),
|
|
584
|
+
signIn: (name) => `Warp opens summer.games to sign in when ${name} starts.`,
|
|
585
|
+
},
|
|
477
586
|
mcp: { user: home(".warp", ".mcp.json"), project: project(".warp", ".mcp.json") },
|
|
478
587
|
restart: "Warp detects the file and spawns the server; check Settings > AI > MCP servers.",
|
|
479
588
|
skills: sharedSkills({ legacyDirs: { user: home(".warp", "skills"), project: project(".warp", "skills") } }),
|
|
@@ -485,6 +594,7 @@ const SPECS = [
|
|
|
485
594
|
status: "active",
|
|
486
595
|
envOverride: "SUMMER_ROVO_DEV_CONFIG_FILE",
|
|
487
596
|
format: "json-transport",
|
|
597
|
+
// No Summer Games entry: Rovo Dev CLI has no OAuth sign-in for remote MCP servers (headers only).
|
|
488
598
|
mcp: { user: home(".rovodev", "mcp.json"), project: null },
|
|
489
599
|
restart: "Restart Rovo Dev CLI so it reconnects its MCP servers.",
|
|
490
600
|
skills: sharedSkills({ legacyDirs: { user: home(".rovodev", "skills"), project: project(".rovodev", "skills") } }),
|
|
@@ -496,6 +606,7 @@ const SPECS = [
|
|
|
496
606
|
status: "active",
|
|
497
607
|
envOverride: "SUMMER_QODER_CONFIG_FILE",
|
|
498
608
|
format: "json",
|
|
609
|
+
// No Summer Games entry: Qoder's remote-server fields in settings.json are not documented.
|
|
499
610
|
mcp: { user: home(".qoder", "settings.json"), project: project(".mcp.json") },
|
|
500
611
|
restart: "Restart Qoder CLI so it reloads its MCP settings (the Qoder IDE manages servers in its UI).",
|
|
501
612
|
skills: skillDirs(home(".qoder", "skills"), project(".qoder", "skills")),
|
|
@@ -507,6 +618,10 @@ const SPECS = [
|
|
|
507
618
|
status: "active",
|
|
508
619
|
envOverride: "SUMMER_GROK_BUILD_CONFIG_FILE",
|
|
509
620
|
format: "toml",
|
|
621
|
+
remoteMcp: {
|
|
622
|
+
entry: (url) => ({ url }),
|
|
623
|
+
signIn: (name) => `In Grok Build, run /mcps, select ${name} and press i to sign in.`,
|
|
624
|
+
},
|
|
510
625
|
mcp: { user: home(".grok", "config.toml"), project: project(".grok", "config.toml") },
|
|
511
626
|
restart: "Restart Grok Build so it reloads config.toml (it also reads ~/.claude.json and .cursor/mcp.json).",
|
|
512
627
|
skills: sharedSkills({ legacyDirs: { user: home(".grok", "skills"), project: project(".grok", "skills") } }),
|
|
@@ -518,6 +633,10 @@ const SPECS = [
|
|
|
518
633
|
status: "active",
|
|
519
634
|
envOverride: "SUMMER_MISTRAL_VIBE_CONFIG_FILE",
|
|
520
635
|
format: "toml-array",
|
|
636
|
+
remoteMcp: {
|
|
637
|
+
entry: (url) => ({ name: "summer-games", transport: "streamable-http", url, auth: { type: "oauth", scopes: [] } }),
|
|
638
|
+
signIn: (name) => `In Vibe, run /mcp login ${name}.`,
|
|
639
|
+
},
|
|
521
640
|
mcp: { user: home(".vibe", "config.toml"), project: project(".vibe", "config.toml") },
|
|
522
641
|
restart: "Restart Vibe so it reloads config.toml.",
|
|
523
642
|
skills: skillDirs(home(".vibe", "skills"), SHARED_SKILLS_PROJECT, { legacyDirs: { user: home(".vibe", "skills"), project: project(".vibe", "skills") } }),
|
|
@@ -529,6 +648,7 @@ const SPECS = [
|
|
|
529
648
|
status: "active",
|
|
530
649
|
envOverride: "SUMMER_LM_STUDIO_CONFIG_FILE",
|
|
531
650
|
format: "json",
|
|
651
|
+
// No Summer Games entry: LM Studio's MCP client registration is closed and unverified.
|
|
532
652
|
mcp: { user: home(".lmstudio", "mcp.json"), project: null },
|
|
533
653
|
restart: "Open LM Studio, toggle on the summer-engine MCP server in the Program tab, and raise the loaded model's context length to 32k or higher.",
|
|
534
654
|
skills: null,
|
|
@@ -40,7 +40,7 @@ async function creatorResult(operation) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
export function registerCreatorTools(server) {
|
|
43
|
-
server.tool("summer_export_game", "Export the game in the exact file the Summer Games store takes, with the installed Summer Engine headless (no window). format \"bundle\" (default): the summer.games .zip the Summer apps run on iPhone, Android, macOS and Windows; targets picks the platforms (a game without a server: ios and android only); upload it with summer_publish_build. format \"download\" with one target: web (an HTML5 .zip on Summer's WebGPU Forward+ web template, played on summer.games), macos (.app zip, macos-universal) or windows (.exe zip, windows-x64); these need the export template from summer_export_templates and are uploaded as store versions. Needs Summer Engine 0.7.0 or newer: an older engine is refused before anything is written (code engine_too_old). Works without the editor running. Returns path, sha256, size, the manifest or store platform, and warnings.", {
|
|
43
|
+
server.tool("summer_export_game", "Export the game in the exact file the Summer Games store takes, with the installed Summer Engine headless (no window). format \"bundle\" (default): the summer.games .zip the Summer apps run on iPhone, Android, macOS and Windows; targets picks the platforms (a game without a server: ios and android only); upload it with summer_publish_build. format \"download\" with one target: web (an HTML5 .zip on Summer's WebGPU Forward+ web template, played on summer.games), macos (.app zip, macos-universal) or windows (.exe zip, windows-x64); these need the export template from summer_export_templates and are uploaded as store versions. Needs Summer Engine 0.7.0 or newer: an older engine is refused before anything is written (code engine_too_old). A target the installed engine cannot build (android needs 0.7.1) is left out: the other targets export, and skippedTargets plus a warning name it. A game with a server declares its platforms in summer.build.json; when they differ from the exported targets a warning says so (summer_publish_build would be refused), and alignDeclaration:true aligns them. Works without the editor running. Returns path, sha256, size, the manifest or store platform, and warnings.", {
|
|
44
44
|
project: z.string().optional().describe("Project folder with project.godot. Defaults to the MCP's bound project, then the working directory."),
|
|
45
45
|
out: z.string().optional().describe("Output .zip path. Defaults to <project>/.summer/exports/."),
|
|
46
46
|
targets: z
|
|
@@ -53,7 +53,11 @@ export function registerCreatorTools(server) {
|
|
|
53
53
|
.describe("bundle (default): the summer.games store build. download: a web build or native download; the default when targets is [\"web\"]."),
|
|
54
54
|
debug: z.boolean().default(false).describe("Export a debug build (--export-debug)."),
|
|
55
55
|
timeoutSeconds: z.number().int().min(10).max(7200).optional().describe("Stop the engine after this many seconds (default 900; a first export imports every asset)."),
|
|
56
|
-
|
|
56
|
+
alignDeclaration: z
|
|
57
|
+
.boolean()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("A game with a server: set summer.build.json targetPlatforms to targets before exporting. The store refuses an upload whose declaration differs from the exported platforms (declaration_mismatch) and that spends the version."),
|
|
60
|
+
}, async ({ project, out, targets, format, debug, timeoutSeconds, alignDeclaration }) => creatorResult(() => exportGame({ project, out, targets, format, debug, alignDeclaration, ...(timeoutSeconds ? { timeoutMs: timeoutSeconds * 1000 } : {}) })));
|
|
57
61
|
server.tool("summer_export_templates", "List, download and install Summer Engine export templates from Summer's CDN into the folder the installed engine reads, checking each file's sha256. Needed only for summer_export_game format \"download\": web (Summer's WebGPU Forward+ template), macos, windows. Store bundles (format \"bundle\") need no template. action list shows what is installed and published; action install fetches the platforms asked (default web).", {
|
|
58
62
|
action: z.enum(["list", "install"]).describe("list: installed and published templates. install: download and install."),
|
|
59
63
|
platforms: z
|
|
@@ -66,7 +70,7 @@ export function registerCreatorTools(server) {
|
|
|
66
70
|
.optional()
|
|
67
71
|
.describe("The installed Summer Engine version (Help > About, e.g. 0.7.1). Read automatically on macOS; needed on Windows and Linux."),
|
|
68
72
|
}, async ({ action, platforms, includeDebug, summerVersion }) => creatorResult(() => exportTemplates({ action, platforms, includeDebug, summerVersion })));
|
|
69
|
-
server.tool("summer_capture_gameplay", "Capture real gameplay frames without a running editor: starts the game in Summer Engine's offscreen verify instance (a real renderer, a window parked offscreen with no focus, never on screen), lets it run waitSeconds, and saves PNG frames of what the game draws, HUD included. Use for store screenshots (1920x1080 landscape or 1080x1920 portrait). With an editor open, summer_screenshot target game also works. Returns each frame's path, width and height; look at them before using them.", {
|
|
73
|
+
server.tool("summer_capture_gameplay", "Capture real gameplay frames without a running editor: starts the game in Summer Engine's offscreen verify instance (--summer-offscreen: a real renderer, a window parked offscreen with no focus, never on screen), lets it run waitSeconds, runs steps, and saves PNG frames of what the game draws, HUD included. Use for store screenshots (1920x1080 landscape or 1080x1920 portrait). The main scene is often a title menu: pass the game's own flags in args (after \"--\", e.g. [\"--autostart\"]), a gameplay scene, or steps that play like a player: [{press:\"Play\"}, {wait:3000}, {key:\"Space\"}, {action:\"jump\"}, {click:[960,540]}, {drag:{from:[400,800],to:[1400,800]}}, {shot:true}]. With a shot step, only shot steps save frames; without one, frames are saved after the steps. A step that cannot run (no such button, key or action) becomes a warning. With an editor open, summer_screenshot target game also works. Returns each frame's path, width and height; look at them before using them.", {
|
|
70
74
|
project: z.string().optional().describe("Project folder with project.godot. Defaults to the MCP's bound project, then the working directory."),
|
|
71
75
|
scene: z.string().optional().describe("Scene to start (res://... or uid://...). Default: the project's main scene, which is often a title menu; pass the gameplay scene for gameplay frames."),
|
|
72
76
|
resolution: z.string().optional().describe("Window size WIDTHxHEIGHT (default 1920x1080; 1080x1920 for portrait)."),
|
|
@@ -74,6 +78,31 @@ export function registerCreatorTools(server) {
|
|
|
74
78
|
waitSeconds: z.number().min(0).max(120).optional().describe("Seconds the game runs before the first frame (default 3)."),
|
|
75
79
|
intervalSeconds: z.number().min(0.1).max(60).optional().describe("Seconds between frames (default 1)."),
|
|
76
80
|
out: z.string().optional().describe("Output folder. Defaults to <project>/.summer/captures/<time>/ (ignored by git)."),
|
|
81
|
+
args: z
|
|
82
|
+
.array(z.string())
|
|
83
|
+
.max(32)
|
|
84
|
+
.optional()
|
|
85
|
+
.describe('The game\'s own command-line flags, passed after "--" (OS.get_cmdline_user_args()), e.g. ["--autostart", "--solo"] to skip the title screen.'),
|
|
86
|
+
steps: z
|
|
87
|
+
.array(z
|
|
88
|
+
.object({
|
|
89
|
+
press: z.string().optional().describe("Press the visible button with this text (or node name); waits up to timeoutSeconds (default 10) for it."),
|
|
90
|
+
timeoutSeconds: z.number().min(0).max(60).optional(),
|
|
91
|
+
key: z.string().optional().describe("Press a key by Godot name: Space, Enter, Escape, A, Up."),
|
|
92
|
+
action: z.string().optional().describe("Press an input action from the project's InputMap, e.g. jump."),
|
|
93
|
+
holdMs: z.number().min(0).max(10000).optional().describe("How long key or action is held (default 100)."),
|
|
94
|
+
click: z.tuple([z.number(), z.number()]).optional().describe("Left-click at [x, y] in frame pixels."),
|
|
95
|
+
drag: z
|
|
96
|
+
.object({ from: z.tuple([z.number(), z.number()]), to: z.tuple([z.number(), z.number()]), ms: z.number().min(0).max(10000).optional() })
|
|
97
|
+
.optional()
|
|
98
|
+
.describe("Drag with the left button from [x, y] to [x, y] over ms (default 300)."),
|
|
99
|
+
wait: z.number().min(0).max(60000).optional().describe("Wait this many milliseconds."),
|
|
100
|
+
shot: z.boolean().optional().describe("true: save a frame now."),
|
|
101
|
+
})
|
|
102
|
+
.strict())
|
|
103
|
+
.max(50)
|
|
104
|
+
.optional()
|
|
105
|
+
.describe("What to do after waitSeconds, in order; exactly one of press, key, action, click, drag, wait, shot per step."),
|
|
77
106
|
}, async (args) => creatorResult(() => captureGameplay(args)));
|
|
78
107
|
server.tool("summer_publish_build", "Upload an export from summer_export_game to the creator's game on summer.games, through the same store upload Studio uses, straight from disk. A store bundle (format bundle): declare, upload parts, seal, wait until Summer makes the Build, name its client pack, and with publish=true approve it. A web build or native download (format download): upload it as the game's store version for its platform (web, macos-universal, windows-x64, linux-x64; read from the last export) and wait until Summer has checked it. First call with confirm=false: it checks that the game exists for this account and warns when its store page does not list the export's platforms, then returns the target (game name and id, file, digest, size, version) to show the user; set confirm only after they approve. Needs \"summer login --store\". A retry with the same file and clientVersion continues the same upload. Nothing here makes a game live: the owner approves publishing (summer_store_submit).", {
|
|
79
108
|
gameId: z.string().optional().describe("The store game id (from summer_store_list_games, or the Studio store page URL). Without it the call fails with game_required and lists your store games, or says why the store did not list them."),
|