mulmocast 0.0.25 → 0.0.26

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.
@@ -2,7 +2,7 @@ import { GraphAILogger } from "graphai";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
  import clipboardy from "clipboardy";
5
- import { getBaseDirPath, getFullPath, readMulmoScriptFile, fetchMulmoScriptFile, getOutputStudioFilePath, resolveDirPath, mkdir, getOutputMultilingualFilePath, } from "../utils/file.js";
5
+ import { getBaseDirPath, getFullPath, readMulmoScriptFile, fetchMulmoScriptFile, getOutputStudioFilePath, resolveDirPath, mkdir, getOutputMultilingualFilePath, generateTimestampedFileName, } from "../utils/file.js";
6
6
  import { isHttp } from "../utils/utils.js";
7
7
  import { createOrUpdateStudioData } from "../utils/preprocess.js";
8
8
  import { outDirName, imageDirName, audioDirName } from "../utils/const.js";
@@ -29,9 +29,7 @@ export const getFileObject = (args) => {
29
29
  const { fileOrUrl, fileName } = (() => {
30
30
  if (file === "__clipboard") {
31
31
  // We generate a new unique script file from clipboard text in the output directory
32
- const now = new Date();
33
- const pad = (n) => n.toString().padStart(2, "0");
34
- const fileName = `script_${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
32
+ const fileName = generateTimestampedFileName("script");
35
33
  const clipboardText = clipboardy.readSync();
36
34
  const fileOrUrl = resolveDirPath(outDirPath, `${fileName}.json`);
37
35
  mkdir(outDirPath);
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ import "dotenv/config";
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import { fileURLToPath } from "url";
9
+ import { GraphAILogger } from "graphai";
10
+ import { audio, images, movie, captions, pdf } from "../actions/index.js";
11
+ import { initializeContext, runTranslateIfNeeded } from "../cli/helpers.js";
12
+ import { outDirName } from "../utils/const.js";
13
+ import { resolveDirPath, mkdir, generateTimestampedFileName } from "../utils/file.js";
14
+ import { mulmoScriptSchema } from "../types/schema.js";
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+ // Load MulmoScript JSON Schema from file
18
+ const MULMO_SCRIPT_JSON_SCHEMA = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../../assets/schemas/html_prompt.json"), "utf8"));
19
+ const server = new Server({
20
+ name: "mulmocast-mcp",
21
+ version: "0.1.0",
22
+ }, {
23
+ capabilities: {
24
+ tools: {},
25
+ },
26
+ });
27
+ // Helper function to save MulmoScript content to output directory
28
+ const saveMulmoScriptToOutput = async (mulmoScript) => {
29
+ const baseDirPath = process.cwd();
30
+ const outputDirPath = path.resolve(baseDirPath, outDirName);
31
+ // Create timestamp-based filename similar to __clipboard handling
32
+ const fileName = generateTimestampedFileName("mcp_script");
33
+ // Ensure output directory exists
34
+ mkdir(outputDirPath);
35
+ // Save MulmoScript to file
36
+ const filePath = resolveDirPath(outputDirPath, `${fileName}.json`);
37
+ fs.writeFileSync(filePath, JSON.stringify(mulmoScript, null, 2), "utf8");
38
+ return filePath;
39
+ };
40
+ // List available tools
41
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
42
+ return {
43
+ tools: [
44
+ {
45
+ name: "generate",
46
+ description: "Generate movie or PDF from MulmoScript content",
47
+ inputSchema: {
48
+ type: "object",
49
+ properties: {
50
+ cmd: {
51
+ type: "string",
52
+ enum: ["movie", "pdf"],
53
+ description: "Command to execute: 'movie' to generate video, 'pdf' to generate PDF",
54
+ },
55
+ mulmoScript: MULMO_SCRIPT_JSON_SCHEMA,
56
+ options: {
57
+ type: "object",
58
+ description: "Optional generation parameters",
59
+ properties: {
60
+ pdfMode: { type: "string", enum: ["slide", "talk", "handout"], description: "PDF generation mode (for PDF only)" },
61
+ pdfSize: { type: "string", enum: ["A4", "Letter", "Legal"], description: "PDF page size (for PDF only)" },
62
+ lang: { type: "string", description: "Language for translation" },
63
+ caption: { type: "string", description: "Caption language" },
64
+ force: { type: "boolean", description: "Force regeneration" },
65
+ verbose: { type: "boolean", description: "Enable verbose logging" },
66
+ },
67
+ additionalProperties: false,
68
+ },
69
+ },
70
+ required: ["cmd", "mulmoScript"],
71
+ additionalProperties: false,
72
+ },
73
+ },
74
+ ],
75
+ };
76
+ });
77
+ // Handle tool calls
78
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
79
+ const { name, arguments: args } = request.params;
80
+ try {
81
+ if (name !== "generate") {
82
+ throw new Error(`Unknown tool: ${name}`);
83
+ }
84
+ const { cmd, mulmoScript, options = {}, } = args;
85
+ // Validate MulmoScript schema
86
+ const validatedScript = mulmoScriptSchema.parse(mulmoScript);
87
+ // Save MulmoScript to output directory
88
+ const filePath = await saveMulmoScriptToOutput(validatedScript);
89
+ // Create argv-like object for CLI compatibility
90
+ const argv = {
91
+ file: filePath,
92
+ l: options.lang,
93
+ c: options.caption,
94
+ f: options.force || false,
95
+ v: options.verbose || false,
96
+ pdf_mode: options.pdfMode || "handout",
97
+ pdf_size: options.pdfSize || "Letter",
98
+ _: [],
99
+ $0: "mcp-server",
100
+ };
101
+ // Initialize context using the saved file
102
+ const context = await initializeContext(argv);
103
+ if (!context) {
104
+ throw new Error("Failed to initialize context from MulmoScript");
105
+ }
106
+ // Run translation if needed
107
+ await runTranslateIfNeeded(context, argv);
108
+ // Execute the requested command
109
+ switch (cmd) {
110
+ case "movie":
111
+ // Generate movie (audio + images + captions + movie)
112
+ await audio(context).then(images).then(captions).then(movie);
113
+ return {
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: `Movie generated successfully from MulmoScript. Output saved to: ${context.fileDirs.outDirPath}`,
118
+ },
119
+ ],
120
+ };
121
+ case "pdf":
122
+ // Generate images first, then PDF
123
+ await images(context);
124
+ await pdf(context, options.pdfMode || "handout", options.pdfSize || "Letter");
125
+ return {
126
+ content: [
127
+ {
128
+ type: "text",
129
+ text: `PDF generated successfully from MulmoScript. Output saved to: ${context.fileDirs.outDirPath}`,
130
+ },
131
+ ],
132
+ };
133
+ default:
134
+ throw new Error(`Unknown command: ${cmd}. Supported commands: movie, pdf`);
135
+ }
136
+ }
137
+ catch (error) {
138
+ const errorMessage = error instanceof Error ? error.message : String(error);
139
+ return {
140
+ content: [
141
+ {
142
+ type: "text",
143
+ text: `Error: ${errorMessage}`,
144
+ },
145
+ ],
146
+ isError: true,
147
+ };
148
+ }
149
+ });
150
+ // Start the server
151
+ async function main() {
152
+ const transport = new StdioServerTransport();
153
+ await server.connect(transport);
154
+ GraphAILogger.error("MulmoCast MCP Server running on stdio");
155
+ }
156
+ main().catch((error) => {
157
+ GraphAILogger.error("Failed to start MCP server:", error);
158
+ process.exit(1);
159
+ });
@@ -41,3 +41,4 @@ export declare const readTemplatePrompt: (templateName: string) => string;
41
41
  export declare const getAvailableTemplates: () => MulmoScriptTemplateFile[];
42
42
  export declare const writingMessage: (filePath: string) => void;
43
43
  export declare const readAndParseJson: <S extends ZodSchema<any>>(filePath: string, schema: S) => ReturnType<S["parse"]>;
44
+ export declare const generateTimestampedFileName: (prefix: string) => string;
package/lib/utils/file.js CHANGED
@@ -182,3 +182,8 @@ export const readAndParseJson = (filePath, schema) => {
182
182
  const json = JSON.parse(fileContent);
183
183
  return schema.parse(json);
184
184
  };
185
+ export const generateTimestampedFileName = (prefix) => {
186
+ const now = new Date();
187
+ const pad = (n) => n.toString().padStart(2, "0");
188
+ return `${prefix}_${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
189
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -48,7 +48,8 @@
48
48
  "latest": "yarn upgrade-interactive --latest",
49
49
  "format": "prettier --write '{src,scripts,assets/templates,assets/styles,draft,ideason,scripts_mag2,proto,test,graphai,output,docs/scripts}/**/*.{ts,json,yaml}'",
50
50
  "deep_research": "npx tsx ./src/tools/deep_research.ts",
51
- "fake_data": "npx tsx test/fake/sample.ts"
51
+ "fake_data": "npx tsx test/fake/sample.ts",
52
+ "mcp_server": "npx tsx ./src/mcp/server.ts"
52
53
  },
53
54
  "repository": "git+ssh://git@github.com/receptron/mulmocast-cli.git",
54
55
  "author": "snakajima",
@@ -68,6 +69,7 @@
68
69
  "@graphai/stream_agent_filter": "^2.0.2",
69
70
  "@graphai/vanilla": "^2.0.4",
70
71
  "@graphai/vanilla_node_agents": "^2.0.1",
72
+ "@modelcontextprotocol/sdk": "^1.13.1",
71
73
  "@tavily/core": "^0.5.8",
72
74
  "canvas": "^3.1.2",
73
75
  "clipboardy": "^4.0.0",