@cmpose/mcp 0.4.0 → 0.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/README.md +13 -2
- package/package.json +2 -2
- package/src/gameGenerate.js +20 -1
- package/src/server.js +16 -6
package/README.md
CHANGED
|
@@ -76,6 +76,13 @@ saving, deep links, and in-app review and update check.
|
|
|
76
76
|
- **IDs:** `ids` takes your real AdMob (`admob`), RevenueCat (`revenueCat`) and Play Games +
|
|
77
77
|
Game Center (`gameServices`) IDs, each group with its flag; `game_describe` lists the fields.
|
|
78
78
|
A group you leave out keeps the test IDs / placeholders and is reported as a warning.
|
|
79
|
+
- **Look (`theme`):** one of the template's style families (`bright`, `neon`, `pastel`, `bold`,
|
|
80
|
+
`nature`, `clean`; palette, shapes, motion and a font pair), listed by `game_describe` under
|
|
81
|
+
`themes` with what each suits. `theme: { family, primary, accent, fontPair }`, every field
|
|
82
|
+
optional: `primary` and `accent` (`#RRGGBB`) recolour the family with their lightness shifted
|
|
83
|
+
until text and buttons keep their contrast; a colour that still cannot pass keeps the
|
|
84
|
+
family's and is reported as a warning. Without `theme` the project gets `clean`, exactly as
|
|
85
|
+
the template ships it.
|
|
79
86
|
- **Your names everywhere:** package (application identifier), company name, app name, min SDK
|
|
80
87
|
(25 to 36) and iOS deployment target (15.0 to 26.2).
|
|
81
88
|
|
|
@@ -98,14 +105,18 @@ as one Docker container behind nginx. `sharing` adds spaces, roles and invitatio
|
|
|
98
105
|
It returns the project path, the template version it used, warnings (e.g. test ad IDs to
|
|
99
106
|
replace) and next steps.
|
|
100
107
|
- `game_describe`: the Unity game generator's engine and editor version, template types,
|
|
101
|
-
renders, flags and their dependencies, ID groups, defaults
|
|
108
|
+
renders, flags and their dependencies, ID groups, defaults, limits and the pinned template's
|
|
109
|
+
theme families (`themes`: `default` and each family's `id`, `title`, `suits` and `fontPairs`;
|
|
110
|
+
the first call downloads the template). Agents call it first.
|
|
102
111
|
- `game_generate`: creates the game. Required: `projectName` (1 to 30 letters or digits,
|
|
103
112
|
starting with a letter), `appName` (up to 30 characters), `packageName` (e.g.
|
|
104
113
|
`com.acme.skyhopper`, at least 3 segments, up to 50 characters) and an absolute `outputDir`.
|
|
105
114
|
Optional: `companyName` (like `projectName`; by default the package's second segment,
|
|
106
115
|
capitalized), `templateType`, `render`, `flags`, `features` (module names: 1 to 20 lowercase
|
|
107
116
|
letters or digits, starting with a letter), `minSdk` (25 to 36), `iosVersion` (15.0 to 26.2,
|
|
108
|
-
written as `major.minor`), `ids`, `templateRef`. It never overwrites a non-empty
|
|
117
|
+
written as `major.minor`), `ids`, `theme`, `templateRef`. It never overwrites a non-empty
|
|
118
|
+
folder. The result names the applied theme (`theme`) and lists colour fallbacks among the
|
|
119
|
+
warnings.
|
|
109
120
|
- `backend_describe`: the backend generator's options, `appName` rules, the project anatomy and
|
|
110
121
|
the conventions to follow when adding code (protected routes, the 404 rule, where features
|
|
111
122
|
go, the security checklist, the local runner and the deploy parts). Agents call it first.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmpose/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"mcpName": "io.github.Keremturker/cmpose",
|
|
5
5
|
"description": "MCP server that generates buildable Compose Multiplatform (Android + iOS) projects and Unity game projects locally from any AI agent",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test": "node --test test/*.test.js"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@cmpose/core": "0.
|
|
46
|
+
"@cmpose/core": "0.5.1",
|
|
47
47
|
"@modelcontextprotocol/sdk": "1.32.1",
|
|
48
48
|
"fs-extra": "^11.3.2",
|
|
49
49
|
"zod": "3.25.76"
|
package/src/gameGenerate.js
CHANGED
|
@@ -59,12 +59,14 @@ async function runGameGenerate(args, { cacheDir, remoteUrl, onProgress = () => {
|
|
|
59
59
|
render: summary.render,
|
|
60
60
|
flags: summary.flags,
|
|
61
61
|
features: summary.features,
|
|
62
|
+
theme: summary.theme,
|
|
62
63
|
warnings: summary.warnings,
|
|
63
64
|
nextSteps: NEXT_STEPS_GAME
|
|
64
65
|
};
|
|
65
66
|
const text = [
|
|
66
67
|
`Generated ${value.projectName} at ${target}`,
|
|
67
68
|
`Template: ${source.repo}@${source.ref} (${String(source.commit).slice(0, 7)})`,
|
|
69
|
+
...(result.theme ? [`Theme: ${result.theme.family} (${result.theme.fontPair})`] : []),
|
|
68
70
|
...result.warnings.map((w) => `Warning: ${w}`),
|
|
69
71
|
'Next steps:', ...NEXT_STEPS_GAME.map((s) => `- ${s}`)
|
|
70
72
|
].join('\n');
|
|
@@ -75,4 +77,21 @@ async function runGameGenerate(args, { cacheDir, remoteUrl, onProgress = () => {
|
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
// game_describe with the pinned template's theme families (fetched into the cache on first use).
|
|
81
|
+
// A template that cannot be fetched or read still describes the generator: no families, and why.
|
|
82
|
+
async function runGameDescribe({ cacheDir, remoteUrl } = {}) {
|
|
83
|
+
let themes = null;
|
|
84
|
+
let unavailable = null;
|
|
85
|
+
try {
|
|
86
|
+
const cache = await core.templateCache.ensure({ ...core.pins.game, cacheDir, remoteUrl });
|
|
87
|
+
themes = await core.game.readThemes(cache.dir);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
if (!(err instanceof core.TemplateFetchError || err instanceof TypeError || err instanceof core.game.ThemesFileError)) throw err;
|
|
90
|
+
unavailable = `Theme families unavailable: ${err.message}`;
|
|
91
|
+
}
|
|
92
|
+
const facts = core.game.describeGame({ themes });
|
|
93
|
+
if (unavailable) facts.themes.unavailable = unavailable;
|
|
94
|
+
return { content: [{ type: 'text', text: JSON.stringify(facts, null, 2) }], structuredContent: facts };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { runGameGenerate, runGameDescribe, NEXT_STEPS_GAME };
|
package/src/server.js
CHANGED
|
@@ -7,7 +7,7 @@ const core = require('@cmpose/core');
|
|
|
7
7
|
const pkg = require('../package.json');
|
|
8
8
|
const { describe } = require('./describe');
|
|
9
9
|
const { runGenerate } = require('./generate');
|
|
10
|
-
const { runGameGenerate } = require('./gameGenerate');
|
|
10
|
+
const { runGameGenerate, runGameDescribe } = require('./gameGenerate');
|
|
11
11
|
const { runBackendGenerate } = require('./backendGenerate');
|
|
12
12
|
|
|
13
13
|
const GENERATE_DESCRIPTION = 'Generate a Compose Multiplatform (Android + iOS) project on this machine. ' +
|
|
@@ -17,6 +17,11 @@ const GENERATE_DESCRIPTION = 'Generate a Compose Multiplatform (Android + iOS) p
|
|
|
17
17
|
const GAME_GENERATE_DESCRIPTION = 'Generate a Unity 6 (Android + iOS) mobile game project on this machine. ' +
|
|
18
18
|
'Call game_describe first for the flags, defaults and validation rules. ' +
|
|
19
19
|
'showcase has every flag on; flags and features apply to blank only. ' +
|
|
20
|
+
'theme picks one of the style families game_describe lists under themes (palette, shapes, motion, fonts; ' +
|
|
21
|
+
'match the family whose suits fits the game) and optionally a fontPair of that family. primary and accent ' +
|
|
22
|
+
'(#RRGGBB) recolour the family: their lightness is shifted until text and buttons keep their contrast, and a ' +
|
|
23
|
+
'colour that still cannot pass falls back to the family default with a warning. Without theme the template ' +
|
|
24
|
+
'default family (clean) is used. ' +
|
|
20
25
|
'Writes <outputDir>/<projectName>; never overwrites an existing non-empty folder.';
|
|
21
26
|
|
|
22
27
|
const BACKEND_GENERATE_DESCRIPTION = 'Generate a standalone Kotlin/Ktor backend (Docker-ready) on this machine. ' +
|
|
@@ -70,12 +75,9 @@ function createServer({ cacheDir, remoteUrl, backendTemplateDir = process.env.CM
|
|
|
70
75
|
}));
|
|
71
76
|
|
|
72
77
|
server.registerTool('game_describe', {
|
|
73
|
-
description: 'Describe the Unity game generator: engine and editor version, template types, renders, flags and their dependencies, ID groups, defaults, validation limits
|
|
78
|
+
description: 'Describe the Unity game generator: engine and editor version, template types, renders, flags and their dependencies, ID groups, defaults, validation limits, the pinned game template and its theme families (themes: default, and each family\'s id, title, suits and fontPairs).',
|
|
74
79
|
inputSchema: {}
|
|
75
|
-
}, async () => {
|
|
76
|
-
const facts = core.game.describeGame();
|
|
77
|
-
return { content: [{ type: 'text', text: JSON.stringify(facts, null, 2) }], structuredContent: facts };
|
|
78
|
-
});
|
|
80
|
+
}, async () => runGameDescribe({ cacheDir, remoteUrl }));
|
|
79
81
|
|
|
80
82
|
server.registerTool('game_generate', {
|
|
81
83
|
description: GAME_GENERATE_DESCRIPTION,
|
|
@@ -96,6 +98,14 @@ function createServer({ cacheDir, remoteUrl, backendTemplateDir = process.env.CM
|
|
|
96
98
|
ids: z.record(z.string(), z.record(z.string(), z.string())).optional()
|
|
97
99
|
.describe('Real IDs by group (admob, revenueCat, gameServices; fields in game_describe), each needing its flag. ' +
|
|
98
100
|
'A group left out keeps the test IDs / placeholders, reported as a warning'),
|
|
101
|
+
// passthrough: unknown fields reach validateGame, which refuses them by name
|
|
102
|
+
theme: z.object({
|
|
103
|
+
family: z.string().optional().describe('A family id from game_describe themes.families (default: themes.default)'),
|
|
104
|
+
primary: z.string().optional().describe('#RRGGBB primary colour; lightness is adjusted to keep contrast'),
|
|
105
|
+
accent: z.string().optional().describe('#RRGGBB accent colour; lightness is adjusted to keep contrast'),
|
|
106
|
+
fontPair: z.string().optional().describe("One of the family's fontPairs (default: its first)")
|
|
107
|
+
}).passthrough().optional()
|
|
108
|
+
.describe('Style family and optional colour shifts; without it the template default family is used'),
|
|
99
109
|
templateRef: z.string().optional().describe('Override the pinned game template tag')
|
|
100
110
|
}
|
|
101
111
|
}, async (args, extra) => runGameGenerate(args, {
|