codex-imagegen-mcp 0.1.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/CHANGELOG.md +96 -0
- package/LICENSE +201 -0
- package/NOTICE +19 -0
- package/README.md +373 -0
- package/dist/src/auth/borrowed.js +77 -0
- package/dist/src/auth/borrowed.js.map +1 -0
- package/dist/src/auth/browser-login.js +179 -0
- package/dist/src/auth/browser-login.js.map +1 -0
- package/dist/src/auth/device-login.js +39 -0
- package/dist/src/auth/device-login.js.map +1 -0
- package/dist/src/auth/jwt.js +69 -0
- package/dist/src/auth/jwt.js.map +1 -0
- package/dist/src/auth/manager.js +289 -0
- package/dist/src/auth/manager.js.map +1 -0
- package/dist/src/auth/oauth.js +246 -0
- package/dist/src/auth/oauth.js.map +1 -0
- package/dist/src/auth/pages.js +39 -0
- package/dist/src/auth/pages.js.map +1 -0
- package/dist/src/auth/pkce.js +14 -0
- package/dist/src/auth/pkce.js.map +1 -0
- package/dist/src/auth/store.js +75 -0
- package/dist/src/auth/store.js.map +1 -0
- package/dist/src/backend/images-client.js +223 -0
- package/dist/src/backend/images-client.js.map +1 -0
- package/dist/src/backend/ratelimits.js +183 -0
- package/dist/src/backend/ratelimits.js.map +1 -0
- package/dist/src/cli.js +407 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.js +87 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.js +52 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/doctor.js +122 -0
- package/dist/src/doctor.js.map +1 -0
- package/dist/src/errors.js +76 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/generation.js +183 -0
- package/dist/src/generation.js.map +1 -0
- package/dist/src/history.js +47 -0
- package/dist/src/history.js.map +1 -0
- package/dist/src/images/chroma.js +200 -0
- package/dist/src/images/chroma.js.map +1 -0
- package/dist/src/images/codec.js +159 -0
- package/dist/src/images/codec.js.map +1 -0
- package/dist/src/images/inputs.js +83 -0
- package/dist/src/images/inputs.js.map +1 -0
- package/dist/src/images/output.js +100 -0
- package/dist/src/images/output.js.map +1 -0
- package/dist/src/images/preview.js +20 -0
- package/dist/src/images/preview.js.map +1 -0
- package/dist/src/images/resize.js +135 -0
- package/dist/src/images/resize.js.map +1 -0
- package/dist/src/install/opencode.js +138 -0
- package/dist/src/install/opencode.js.map +1 -0
- package/dist/src/install/skill.js +128 -0
- package/dist/src/install/skill.js.map +1 -0
- package/dist/src/install/snippets.js +127 -0
- package/dist/src/install/snippets.js.map +1 -0
- package/dist/src/log.js +58 -0
- package/dist/src/log.js.map +1 -0
- package/dist/src/remove-background.js +101 -0
- package/dist/src/remove-background.js.map +1 -0
- package/dist/src/server/context.js +2 -0
- package/dist/src/server/context.js.map +1 -0
- package/dist/src/server/index.js +94 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/instructions.js +20 -0
- package/dist/src/server/instructions.js.map +1 -0
- package/dist/src/server/login-coordinator.js +73 -0
- package/dist/src/server/login-coordinator.js.map +1 -0
- package/dist/src/server/progress.js +33 -0
- package/dist/src/server/progress.js.map +1 -0
- package/dist/src/server/prompts.js +45 -0
- package/dist/src/server/prompts.js.map +1 -0
- package/dist/src/server/resources.js +73 -0
- package/dist/src/server/resources.js.map +1 -0
- package/dist/src/server/tools.js +338 -0
- package/dist/src/server/tools.js.map +1 -0
- package/dist/src/server/workspace.js +45 -0
- package/dist/src/server/workspace.js.map +1 -0
- package/dist/src/status.js +86 -0
- package/dist/src/status.js.map +1 -0
- package/dist/src/util/format.js +36 -0
- package/dist/src/util/format.js.map +1 -0
- package/dist/src/util/fs.js +117 -0
- package/dist/src/util/fs.js.map +1 -0
- package/dist/src/util/http.js +65 -0
- package/dist/src/util/http.js.map +1 -0
- package/dist/src/util/invocation.js +43 -0
- package/dist/src/util/invocation.js.map +1 -0
- package/dist/src/util/open.js +41 -0
- package/dist/src/util/open.js.map +1 -0
- package/docs/ARCHITECTURE.md +123 -0
- package/docs/AUTH.md +242 -0
- package/docs/BACKEND.md +169 -0
- package/docs/CLIENTS.md +154 -0
- package/docs/DEVELOPMENT.md +171 -0
- package/docs/README.md +84 -0
- package/docs/TOOLS.md +221 -0
- package/package.json +67 -0
- package/skill/imagegen/LICENSE.txt +201 -0
- package/skill/imagegen/SKILL.md +189 -0
- package/skill/imagegen/references/prompting.md +112 -0
- package/skill/imagegen/references/sample-prompts.md +418 -0
- package/skill/imagegen/references/tools.md +90 -0
package/dist/src/log.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const ORDER = { debug: 10, info: 20, warn: 30, error: 40, silent: 100 };
|
|
4
|
+
const MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
5
|
+
function serializeMeta(meta) {
|
|
6
|
+
if (!meta || Object.keys(meta).length === 0)
|
|
7
|
+
return "";
|
|
8
|
+
try {
|
|
9
|
+
return ` ${JSON.stringify(meta, (_k, v) => (v instanceof Error ? { name: v.name, message: v.message } : v))}`;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return " [unserializable meta]";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function createLogger(options) {
|
|
16
|
+
const threshold = ORDER[options.level];
|
|
17
|
+
let fileOk = Boolean(options.file);
|
|
18
|
+
if (options.file) {
|
|
19
|
+
try {
|
|
20
|
+
fs.mkdirSync(path.dirname(options.file), { recursive: true, mode: 0o700 });
|
|
21
|
+
const st = fs.statSync(options.file, { throwIfNoEntry: false });
|
|
22
|
+
if (st && st.size > MAX_LOG_BYTES)
|
|
23
|
+
fs.renameSync(options.file, `${options.file}.1`);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
fileOk = false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const write = (level, message, meta) => {
|
|
30
|
+
if (ORDER[level] < threshold)
|
|
31
|
+
return;
|
|
32
|
+
const line = `${new Date().toISOString()} [${level}] ${message}${serializeMeta(meta)}\n`;
|
|
33
|
+
if (options.stderr) {
|
|
34
|
+
try {
|
|
35
|
+
process.stderr.write(line);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
/* ignore */
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (fileOk && options.file) {
|
|
42
|
+
try {
|
|
43
|
+
fs.appendFileSync(options.file, line, { mode: 0o600 });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
fileOk = false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
debug: (m, meta) => write("debug", m, meta),
|
|
52
|
+
info: (m, meta) => write("info", m, meta),
|
|
53
|
+
warn: (m, meta) => write("warn", m, meta),
|
|
54
|
+
error: (m, meta) => write("error", m, meta),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export const silentLogger = { debug() { }, info() { }, warn() { }, error() { } };
|
|
58
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { expandHome } from "./config.js";
|
|
4
|
+
import { ImagegenError } from "./errors.js";
|
|
5
|
+
import { removeChromaKey, parseHexColor, toHexColor } from "./images/chroma.js";
|
|
6
|
+
import { decodeImage, encodePng } from "./images/codec.js";
|
|
7
|
+
import { newImageId, writeImageFile } from "./images/output.js";
|
|
8
|
+
import { buildPreview } from "./images/preview.js";
|
|
9
|
+
export async function runRemoveBackground(deps, req, ctx) {
|
|
10
|
+
const inputPath = path.resolve(ctx.baseDir, expandHome(req.inputPath.trim()));
|
|
11
|
+
let bytes;
|
|
12
|
+
try {
|
|
13
|
+
bytes = await fs.readFile(inputPath);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
throw new ImagegenError("invalid_input", `Input image not found: ${inputPath}`);
|
|
17
|
+
}
|
|
18
|
+
const image = decodeImage(bytes);
|
|
19
|
+
let outputPath;
|
|
20
|
+
if (req.outputPath?.trim()) {
|
|
21
|
+
outputPath = path.resolve(ctx.baseDir, expandHome(req.outputPath.trim()));
|
|
22
|
+
if (path.extname(outputPath).toLowerCase() !== ".png") {
|
|
23
|
+
throw new ImagegenError("invalid_input", "output_path must end in .png so the alpha channel is preserved.");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const ext = path.extname(inputPath);
|
|
28
|
+
outputPath = `${inputPath.slice(0, inputPath.length - ext.length)}-transparent.png`;
|
|
29
|
+
}
|
|
30
|
+
if (outputPath === inputPath && !req.overwrite) {
|
|
31
|
+
throw new ImagegenError("invalid_input", "output_path is the input file; pass overwrite=true to replace it.");
|
|
32
|
+
}
|
|
33
|
+
const options = { softMatte: req.softMatte, spillCleanup: req.despill };
|
|
34
|
+
if (req.keyColor?.trim()) {
|
|
35
|
+
options.keyColor = parseHexColor(req.keyColor);
|
|
36
|
+
options.autoKey = "none";
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
options.autoKey = "border";
|
|
40
|
+
}
|
|
41
|
+
if (req.tolerance !== undefined)
|
|
42
|
+
options.tolerance = req.tolerance;
|
|
43
|
+
if (req.transparentThreshold !== undefined)
|
|
44
|
+
options.transparentThreshold = req.transparentThreshold;
|
|
45
|
+
if (req.opaqueThreshold !== undefined)
|
|
46
|
+
options.opaqueThreshold = req.opaqueThreshold;
|
|
47
|
+
if (req.edgeContract !== undefined)
|
|
48
|
+
options.edgeContract = req.edgeContract;
|
|
49
|
+
if (req.edgeFeather !== undefined)
|
|
50
|
+
options.edgeFeather = req.edgeFeather;
|
|
51
|
+
const result = removeChromaKey(image, options);
|
|
52
|
+
const png = encodePng(result.image);
|
|
53
|
+
const finalPath = await writeImageFile(outputPath, png, req.overwrite);
|
|
54
|
+
const warnings = [];
|
|
55
|
+
const transparentPercent = (100 * result.transparent) / result.total;
|
|
56
|
+
const partialPercent = (100 * result.partial) / result.total;
|
|
57
|
+
if (result.keyedPixels === 0) {
|
|
58
|
+
warnings.push(`No pixels matched the key color ${toHexColor(result.keyColor)}. Is the background a flat, uniform color? Pass key_color explicitly or raise tolerance.`);
|
|
59
|
+
}
|
|
60
|
+
else if (transparentPercent > 97) {
|
|
61
|
+
warnings.push("Almost the whole image became transparent — the subject may be too close to the key color. Lower opaque_threshold/tolerance or pass key_color.");
|
|
62
|
+
}
|
|
63
|
+
const out = {
|
|
64
|
+
id: newImageId(),
|
|
65
|
+
inputPath,
|
|
66
|
+
outputPath: finalPath,
|
|
67
|
+
width: result.image.width,
|
|
68
|
+
height: result.image.height,
|
|
69
|
+
bytes: png.length,
|
|
70
|
+
keyColor: toHexColor(result.keyColor),
|
|
71
|
+
transparentPercent,
|
|
72
|
+
partialPercent,
|
|
73
|
+
warnings,
|
|
74
|
+
};
|
|
75
|
+
if (req.preview) {
|
|
76
|
+
try {
|
|
77
|
+
const preview = buildPreview(png);
|
|
78
|
+
if (preview)
|
|
79
|
+
out.preview = preview;
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
deps.logger.warn("preview failed", { message: err instanceof Error ? err.message : String(err) });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await deps.history
|
|
86
|
+
.append({
|
|
87
|
+
id: out.id,
|
|
88
|
+
created_at: new Date().toISOString(),
|
|
89
|
+
tool: "remove_background",
|
|
90
|
+
path: finalPath,
|
|
91
|
+
mime_type: "image/png",
|
|
92
|
+
bytes: png.length,
|
|
93
|
+
width: out.width,
|
|
94
|
+
height: out.height,
|
|
95
|
+
inputs: [inputPath],
|
|
96
|
+
background: "transparent",
|
|
97
|
+
})
|
|
98
|
+
.catch((err) => deps.logger.warn("history append failed", { message: String(err) }));
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=remove-background.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-background.js","sourceRoot":"","sources":["../../src/remove-background.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/server/context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { RootsListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { AuthManager, authOptionsFromConfig } from "../auth/manager.js";
|
|
5
|
+
import { ImagesClient } from "../backend/images-client.js";
|
|
6
|
+
import { loadConfig } from "../config.js";
|
|
7
|
+
import { PACKAGE_NAME, VERSION } from "../constants.js";
|
|
8
|
+
import { History } from "../history.js";
|
|
9
|
+
import { createLogger } from "../log.js";
|
|
10
|
+
import { SERVER_INSTRUCTIONS } from "./instructions.js";
|
|
11
|
+
import { LoginCoordinator } from "./login-coordinator.js";
|
|
12
|
+
import { registerPrompts } from "./prompts.js";
|
|
13
|
+
import { registerResources } from "./resources.js";
|
|
14
|
+
import { registerTools } from "./tools.js";
|
|
15
|
+
import { Workspace } from "./workspace.js";
|
|
16
|
+
export function createDeps(config, logger, fetchImpl) {
|
|
17
|
+
const auth = new AuthManager(authOptionsFromConfig(config, logger, fetchImpl));
|
|
18
|
+
const imagesOptions = {
|
|
19
|
+
baseUrl: config.baseUrl,
|
|
20
|
+
usageUrl: config.usageUrl,
|
|
21
|
+
originator: config.originator,
|
|
22
|
+
userAgent: config.userAgent,
|
|
23
|
+
timeoutMs: config.requestTimeoutMs,
|
|
24
|
+
logger,
|
|
25
|
+
};
|
|
26
|
+
if (fetchImpl)
|
|
27
|
+
imagesOptions.fetchImpl = fetchImpl;
|
|
28
|
+
const images = new ImagesClient(auth, imagesOptions);
|
|
29
|
+
return {
|
|
30
|
+
config,
|
|
31
|
+
logger,
|
|
32
|
+
auth,
|
|
33
|
+
images,
|
|
34
|
+
history: new History(config.historyFile),
|
|
35
|
+
login: new LoginCoordinator({ config, auth, logger }),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Build the MCP server (transport-agnostic, so tests can connect it in-memory). */
|
|
39
|
+
export function createImagegenServer(deps) {
|
|
40
|
+
const server = new McpServer({ name: PACKAGE_NAME, title: "Codex ImageGen", version: VERSION }, { instructions: SERVER_INSTRUCTIONS });
|
|
41
|
+
const workspace = new Workspace(server.server, deps.logger);
|
|
42
|
+
server.server.setNotificationHandler(RootsListChangedNotificationSchema, async () => workspace.invalidate());
|
|
43
|
+
const ctx = { ...deps, workspace };
|
|
44
|
+
registerTools(server, ctx);
|
|
45
|
+
registerResources(server, ctx);
|
|
46
|
+
registerPrompts(server);
|
|
47
|
+
return server;
|
|
48
|
+
}
|
|
49
|
+
/** Entry point for `serve`: stdio transport with graceful shutdown. */
|
|
50
|
+
export async function runStdioServer() {
|
|
51
|
+
// stdout carries the protocol; make sure nothing else (e.g. a dependency) can write to it.
|
|
52
|
+
console.log = console.error;
|
|
53
|
+
console.info = console.error;
|
|
54
|
+
console.debug = console.error;
|
|
55
|
+
const config = loadConfig();
|
|
56
|
+
const logger = createLogger({ level: config.logLevel, file: config.logFile, stderr: true });
|
|
57
|
+
const deps = createDeps(config, logger);
|
|
58
|
+
const server = createImagegenServer(deps);
|
|
59
|
+
const transport = new StdioServerTransport();
|
|
60
|
+
let closing = false;
|
|
61
|
+
const shutdown = async (reason, code = 0) => {
|
|
62
|
+
if (closing)
|
|
63
|
+
return;
|
|
64
|
+
closing = true;
|
|
65
|
+
logger.info("shutting down", { reason });
|
|
66
|
+
deps.login.cancel();
|
|
67
|
+
setTimeout(() => process.exit(code), 2_000).unref();
|
|
68
|
+
try {
|
|
69
|
+
await server.close();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* ignore */
|
|
73
|
+
}
|
|
74
|
+
process.exit(code);
|
|
75
|
+
};
|
|
76
|
+
server.server.onerror = (err) => logger.warn("protocol error", { message: err.message });
|
|
77
|
+
server.server.onclose = () => void shutdown("transport closed");
|
|
78
|
+
// The SDK transport does not react to stdin EOF; MCP clients stop servers by closing stdin.
|
|
79
|
+
process.stdin.once("end", () => void shutdown("stdin ended"));
|
|
80
|
+
process.stdin.once("close", () => void shutdown("stdin closed"));
|
|
81
|
+
process.stdout.on("error", (err) => void shutdown(`stdout ${err.code ?? err.message}`, err.code === "EPIPE" ? 0 : 1));
|
|
82
|
+
process.once("SIGINT", () => void shutdown("SIGINT"));
|
|
83
|
+
process.once("SIGTERM", () => void shutdown("SIGTERM"));
|
|
84
|
+
process.on("uncaughtException", (err) => {
|
|
85
|
+
logger.error("uncaught exception", { message: err.stack ?? err.message });
|
|
86
|
+
void shutdown("uncaughtException", 1);
|
|
87
|
+
});
|
|
88
|
+
process.on("unhandledRejection", (reason) => {
|
|
89
|
+
logger.error("unhandled rejection", { message: reason instanceof Error ? (reason.stack ?? reason.message) : String(reason) });
|
|
90
|
+
});
|
|
91
|
+
await server.connect(transport);
|
|
92
|
+
logger.info("server started", { version: VERSION, pid: process.pid, mode: config.credentialMode, home: config.home, baseUrl: config.baseUrl });
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sent in the MCP `initialize` result. opencode injects it into the system prompt (inside
|
|
3
|
+
* <mcp_instructions>), so it is kept short; detailed guidance lives in the imagegen skill.
|
|
4
|
+
*/
|
|
5
|
+
export const SERVER_INSTRUCTIONS = `Image generation and editing through the user's ChatGPT plan — the same image service OpenAI Codex's built-in image tool uses (no API key).
|
|
6
|
+
|
|
7
|
+
Tools:
|
|
8
|
+
- generate_image: new image from a prompt. edit_image: modify images or use them as references (1-5 inputs; refer to them as Image 1, Image 2…).
|
|
9
|
+
- remove_background: local chroma-key cutout of a flat backdrop (no quota).
|
|
10
|
+
- auth_status: sign-in + quota. sign_in: start a ChatGPT sign-in and relay the link/code to the user.
|
|
11
|
+
|
|
12
|
+
Rules of thumb:
|
|
13
|
+
- Write structured prompts (use case, subject, style, composition, lighting, palette, exact text in quotes, constraints, avoid). For edits, state what changes and what must stay the same.
|
|
14
|
+
- The service picks pixel size and quality; set aspect_ratio (or describe the orientation) instead. Use background="transparent" for assets that need real alpha.
|
|
15
|
+
- One call per distinct asset; n (1-4) is only for variants of one prompt. Each image counts against the user's ChatGPT usage limits.
|
|
16
|
+
- Files are saved to disk and the path is returned. For project assets pass output_path inside the workspace; existing files are never overwritten unless overwrite=true.
|
|
17
|
+
- Check the attached preview before finishing, and report saved paths.
|
|
18
|
+
- If a tool says the user is not signed in, call sign_in (or ask the user to run the login command it names). On a usage-limit error, stop and tell the user when it resets.
|
|
19
|
+
- For detailed prompting guidance, load the "imagegen" skill if available, or read the imagegen://skill/SKILL.md resource.`;
|
|
20
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../../src/server/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;2HAcwF,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { startBrowserLogin } from "../auth/browser-login.js";
|
|
2
|
+
import { startDeviceLogin } from "../auth/device-login.js";
|
|
3
|
+
import { toImagegenError } from "../errors.js";
|
|
4
|
+
import { openInBrowser } from "../util/open.js";
|
|
5
|
+
/**
|
|
6
|
+
* Runs at most one sign-in at a time inside a long-lived server process, so the `sign_in` tool can
|
|
7
|
+
* hand the user a link immediately while the OAuth round-trip completes in the background.
|
|
8
|
+
*/
|
|
9
|
+
export class LoginCoordinator {
|
|
10
|
+
deps;
|
|
11
|
+
pending;
|
|
12
|
+
last;
|
|
13
|
+
constructor(deps) {
|
|
14
|
+
this.deps = deps;
|
|
15
|
+
}
|
|
16
|
+
get pendingLogin() {
|
|
17
|
+
return this.pending?.info;
|
|
18
|
+
}
|
|
19
|
+
get lastOutcome() {
|
|
20
|
+
return this.last;
|
|
21
|
+
}
|
|
22
|
+
async start(method, options) {
|
|
23
|
+
if (this.pending && this.pending.info.method === method) {
|
|
24
|
+
return { info: this.pending.info, reused: true, browserOpened: false };
|
|
25
|
+
}
|
|
26
|
+
this.cancel();
|
|
27
|
+
const { config, auth, logger } = this.deps;
|
|
28
|
+
const oauth = auth.oauthClient;
|
|
29
|
+
let info;
|
|
30
|
+
let result;
|
|
31
|
+
let cancel;
|
|
32
|
+
if (method === "browser") {
|
|
33
|
+
const login = await startBrowserLogin({ ...oauth, originator: config.originator });
|
|
34
|
+
info = { method, url: login.url, startedAt: Date.now(), expiresAt: Date.now() + 10 * 60_000 };
|
|
35
|
+
result = login.result;
|
|
36
|
+
cancel = login.cancel;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const login = await startDeviceLogin(oauth);
|
|
40
|
+
info = { method, url: login.verificationUrl, userCode: login.userCode, startedAt: Date.now(), expiresAt: login.expiresAt };
|
|
41
|
+
result = login.result;
|
|
42
|
+
cancel = login.cancel;
|
|
43
|
+
}
|
|
44
|
+
const entry = { info, cancel };
|
|
45
|
+
this.pending = entry;
|
|
46
|
+
logger.info("sign-in started", { method });
|
|
47
|
+
result
|
|
48
|
+
.then((tokens) => auth.saveLogin(tokens, method))
|
|
49
|
+
.then(({ identity }) => {
|
|
50
|
+
this.last = { ok: true, message: `Signed in${identity.email ? ` as ${identity.email}` : ""}${identity.planType ? ` (ChatGPT ${identity.planType})` : ""}.`, at: Date.now() };
|
|
51
|
+
logger.info("sign-in completed", { method, plan: identity.planType });
|
|
52
|
+
})
|
|
53
|
+
.catch((err) => {
|
|
54
|
+
const e = toImagegenError(err, "login_failed");
|
|
55
|
+
this.last = { ok: false, message: e.message, at: Date.now() };
|
|
56
|
+
logger.warn("sign-in failed", { method, kind: e.kind, message: e.message });
|
|
57
|
+
})
|
|
58
|
+
.finally(() => {
|
|
59
|
+
if (this.pending === entry)
|
|
60
|
+
this.pending = undefined;
|
|
61
|
+
});
|
|
62
|
+
let browserOpened = false;
|
|
63
|
+
if (method === "browser" && options.openBrowser && !config.noBrowser)
|
|
64
|
+
browserOpened = await openInBrowser(info.url);
|
|
65
|
+
return { info, reused: false, browserOpened };
|
|
66
|
+
}
|
|
67
|
+
cancel() {
|
|
68
|
+
const p = this.pending;
|
|
69
|
+
this.pending = undefined;
|
|
70
|
+
p?.cancel();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=login-coordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login-coordinator.js","sourceRoot":"","sources":["../../../src/server/login-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heartbeat progress notifications while a long request runs. Clients such as opencode reset
|
|
3
|
+
* their per-request timeout on every progress notification (resetTimeoutOnProgress), so a
|
|
4
|
+
* 30-60 s image generation never trips a 60 s default timeout. No-op if the client did not send a
|
|
5
|
+
* progress token.
|
|
6
|
+
*/
|
|
7
|
+
export function startProgress(extra, label, intervalMs = 5_000) {
|
|
8
|
+
const token = extra._meta?.progressToken;
|
|
9
|
+
if (token === undefined)
|
|
10
|
+
return { update() { }, stop() { } };
|
|
11
|
+
const started = Date.now();
|
|
12
|
+
let progress = 0;
|
|
13
|
+
let stopped = false;
|
|
14
|
+
const send = (message) => {
|
|
15
|
+
if (stopped || extra.signal.aborted)
|
|
16
|
+
return;
|
|
17
|
+
progress += 1;
|
|
18
|
+
extra
|
|
19
|
+
.sendNotification({ method: "notifications/progress", params: { progressToken: token, progress, message } })
|
|
20
|
+
.catch(() => undefined);
|
|
21
|
+
};
|
|
22
|
+
send(`${label}…`);
|
|
23
|
+
const timer = setInterval(() => send(`${label}… ${Math.round((Date.now() - started) / 1000)}s`), intervalMs);
|
|
24
|
+
timer.unref();
|
|
25
|
+
return {
|
|
26
|
+
update: send,
|
|
27
|
+
stop() {
|
|
28
|
+
stopped = true;
|
|
29
|
+
clearInterval(timer);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/server/progress.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,KAAa,EAAE,UAAU,GAAG,KAAK;IAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,KAAI,CAAC,EAAE,IAAI,KAAI,CAAC,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE;QAC/B,IAAI,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO;QAC5C,QAAQ,IAAI,CAAC,CAAC;QACd,KAAK;aACF,gBAAgB,CAAC,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;aAC3G,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC,CAAC;IACF,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAClB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC;IAC7G,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,IAAI;YACF,OAAO,GAAG,IAAI,CAAC;YACf,aAAa,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as z from "zod/v4";
|
|
2
|
+
const CHECKLIST = [
|
|
3
|
+
"Follow the imagegen skill if it is available (otherwise read the imagegen://skill/SKILL.md resource).",
|
|
4
|
+
"Classify the request (use case + asset type) and write a structured prompt: Use case, Asset type, Primary request, Scene/backdrop, Subject, Style/medium, Composition/framing, Lighting/mood, Color palette, Text (verbatim), Constraints, Avoid.",
|
|
5
|
+
"Keep the user's details; only add detail that materially improves the result.",
|
|
6
|
+
"Pick aspect_ratio from the intended use; use background=\"transparent\" when the asset needs alpha.",
|
|
7
|
+
"Inspect the returned preview; iterate with one targeted change if something is off.",
|
|
8
|
+
"Save project assets inside the workspace (output_path) without overwriting existing files, and report the final path(s).",
|
|
9
|
+
];
|
|
10
|
+
export function registerPrompts(server) {
|
|
11
|
+
server.registerPrompt("generate", {
|
|
12
|
+
title: "Generate an image",
|
|
13
|
+
description: "Create a new image with the imagegen tools using the recommended workflow.",
|
|
14
|
+
argsSchema: { description: z.string().describe("What to create, including where it will be used.") },
|
|
15
|
+
}, ({ description }) => ({
|
|
16
|
+
messages: [
|
|
17
|
+
{
|
|
18
|
+
role: "user",
|
|
19
|
+
content: {
|
|
20
|
+
type: "text",
|
|
21
|
+
text: `Generate an image with the imagegen MCP tools (generate_image).\n\nRequest: ${description}\n\nHow:\n${CHECKLIST.map((c) => `- ${c}`).join("\n")}`,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
}));
|
|
26
|
+
server.registerPrompt("edit", {
|
|
27
|
+
title: "Edit an image",
|
|
28
|
+
description: "Edit an existing image with the imagegen tools, preserving everything that should not change.",
|
|
29
|
+
argsSchema: {
|
|
30
|
+
image: z.string().describe("Path (or URL) of the image to edit."),
|
|
31
|
+
change: z.string().describe("What should change."),
|
|
32
|
+
},
|
|
33
|
+
}, ({ image, change }) => ({
|
|
34
|
+
messages: [
|
|
35
|
+
{
|
|
36
|
+
role: "user",
|
|
37
|
+
content: {
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `Edit this image with the imagegen MCP tools (edit_image): ${image}\n\nChange: ${change}\n\nHow:\n- In the prompt, refer to it as Image 1 and state both the change and the invariants ("change only X; keep Y unchanged").\n${CHECKLIST.slice(3).map((c) => `- ${c}`).join("\n")}`,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/server/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAE5B,MAAM,SAAS,GAAG;IAChB,uGAAuG;IACvG,mPAAmP;IACnP,+EAA+E;IAC/E,qGAAqG;IACrG,qFAAqF;IACrF,0HAA0H;CAC3H,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,cAAc,CACnB,UAAU,EACV;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,4EAA4E;QACzF,UAAU,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC,EAAE;KACrG,EACD,CAAC,EAAE,WAAW,EAAE,EAAmB,EAAE,CAAC,CAAC;QACrC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,+EAA+E,WAAW,aAAa,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBACzJ;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,MAAM,EACN;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,+FAA+F;QAC5G,UAAU,EAAE;YACV,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YACjE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;SACnD;KACF,EACD,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAmB,EAAE,CAAC,CAAC;QACvC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,6DAA6D,KAAK,eAAe,MAAM,wIAAwI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;iBAC1R;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import fsp from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { SKILL_SOURCE_DIR } from "../constants.js";
|
|
7
|
+
import { buildPreview } from "../images/preview.js";
|
|
8
|
+
const MAX_BLOB_BYTES = 8 * 1024 * 1024;
|
|
9
|
+
/** SKILL.md plus references/*.md of the bundled skill, as [relativePath, absolutePath]. */
|
|
10
|
+
export function skillFiles(dir = SKILL_SOURCE_DIR) {
|
|
11
|
+
const files = [];
|
|
12
|
+
const main = path.join(dir, "SKILL.md");
|
|
13
|
+
if (fs.existsSync(main))
|
|
14
|
+
files.push(["SKILL.md", main]);
|
|
15
|
+
const refs = path.join(dir, "references");
|
|
16
|
+
if (fs.existsSync(refs)) {
|
|
17
|
+
for (const name of fs.readdirSync(refs).sort()) {
|
|
18
|
+
if (name.endsWith(".md"))
|
|
19
|
+
files.push([`references/${name}`, path.join(refs, name)]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
export function registerResources(server, ctx) {
|
|
25
|
+
server.registerResource("history", "imagegen://history", {
|
|
26
|
+
title: "Recent images",
|
|
27
|
+
description: "JSON list of the 50 most recent images generated, edited or cut out by this server (newest first), with paths and prompts.",
|
|
28
|
+
mimeType: "application/json",
|
|
29
|
+
}, async (uri) => ({
|
|
30
|
+
contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(await ctx.history.list(50), null, 2) }],
|
|
31
|
+
}));
|
|
32
|
+
server.registerResource("image", new ResourceTemplate("imagegen://images/{id}", {
|
|
33
|
+
list: async () => ({
|
|
34
|
+
resources: (await ctx.history.list(25)).map((e) => ({
|
|
35
|
+
uri: `imagegen://images/${e.id}`,
|
|
36
|
+
name: path.basename(e.path),
|
|
37
|
+
mimeType: e.mime_type,
|
|
38
|
+
...(e.prompt ? { description: e.prompt.slice(0, 160) } : {}),
|
|
39
|
+
})),
|
|
40
|
+
}),
|
|
41
|
+
}), { title: "Generated image", description: "A previously saved image, by id (see imagegen://history).", mimeType: "image/png" }, async (uri, variables) => {
|
|
42
|
+
const id = String(variables.id ?? "");
|
|
43
|
+
const entry = await ctx.history.get(id);
|
|
44
|
+
if (!entry)
|
|
45
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown image id: ${id}`);
|
|
46
|
+
let bytes;
|
|
47
|
+
try {
|
|
48
|
+
bytes = await fsp.readFile(entry.path);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new McpError(ErrorCode.InvalidParams, `The file for ${id} no longer exists: ${entry.path}`);
|
|
52
|
+
}
|
|
53
|
+
if (bytes.length <= MAX_BLOB_BYTES) {
|
|
54
|
+
return { contents: [{ uri: uri.href, mimeType: entry.mime_type, blob: bytes.toString("base64") }] };
|
|
55
|
+
}
|
|
56
|
+
const preview = buildPreview(bytes, 2048);
|
|
57
|
+
if (!preview)
|
|
58
|
+
throw new McpError(ErrorCode.InternalError, `Image ${id} is too large to return (${bytes.length} bytes).`);
|
|
59
|
+
return { contents: [{ uri: uri.href, mimeType: preview.mimeType, blob: preview.data }] };
|
|
60
|
+
});
|
|
61
|
+
for (const [relative, absolute] of skillFiles()) {
|
|
62
|
+
server.registerResource(`skill:${relative}`, `imagegen://skill/${relative}`, {
|
|
63
|
+
title: relative === "SKILL.md" ? "imagegen skill (how to use these tools well)" : `imagegen skill: ${relative}`,
|
|
64
|
+
description: relative === "SKILL.md"
|
|
65
|
+
? "Workflow and prompting guidance for image generation. Read this if your client does not load Agent Skills."
|
|
66
|
+
: "Reference material for the imagegen skill.",
|
|
67
|
+
mimeType: "text/markdown",
|
|
68
|
+
}, async (uri) => ({
|
|
69
|
+
contents: [{ uri: uri.href, mimeType: "text/markdown", text: await fsp.readFile(absolute, "utf8") }],
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../../src/server/resources.ts"],"names":[],"mappings":"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"}
|