mulmocast-vision 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,9 +72,62 @@ You can instruct these actions via prompts.
72
72
  - SWOT, PEST, and 3C Analysis
73
73
  - Summary, Agenda, and Closing Slides
74
74
 
75
+ ## Logging
76
+
77
+ mulmocast-vision automatically logs all operations and errors to help with debugging and monitoring.
78
+
79
+ ### Log Location
80
+
81
+ Logs are saved in `/tmp/mulmocast-vision-mcp/` with daily rotation:
82
+ - Format: `mcp_yyyymmdd.log` (e.g., `mcp_20251206.log`)
83
+ - Each day creates a new log file
84
+
85
+ ### What is Logged
86
+
87
+ - **MCP Server Operations**: Server initialization, tool calls, and results
88
+ - **File Operations**: Template reads, HTML/PNG generation, PDF creation
89
+ - **Errors**: Detailed error messages with full stack traces
90
+ - **Debug Information**: Template rendering, directory operations, and more
91
+
92
+ ### Log Format
93
+
94
+ Logs are written in JSON Lines format for easy parsing:
95
+
96
+ ```json
97
+ {
98
+ "timestamp": "2025-01-15T10:30:45.123Z",
99
+ "level": "ERROR",
100
+ "message": "Template file not found",
101
+ "data": {
102
+ "errorMessage": "getHtml: file /path/to/template.html not exists.",
103
+ "errorName": "Error",
104
+ "stack": "Error: getHtml: file...\n at htmlPlugin.getHtml...",
105
+ "templateFilePath": "/path/to/template.html",
106
+ "functionName": "createAgendaSlide"
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Custom Logger
112
+
113
+ You can replace the default logger with your own implementation (e.g., for telemetry):
114
+
115
+ ```typescript
116
+ import { setLogger, LoggerInterface } from 'mulmocast-vision/logger';
117
+
118
+ class CustomLogger implements LoggerInterface {
119
+ info(message: string, data?: unknown) {
120
+ // Your implementation
121
+ }
122
+ // ... other methods
123
+ }
124
+
125
+ setLogger(new CustomLogger());
126
+ ```
127
+
75
128
  ## For Developers
76
129
 
77
- MulmoCast Vision is open source, so you can apply various designs by modifying the HTML.
130
+ MulmoCast Vision is open source, so you can apply various designs by modifying the HTML.
78
131
  For adding styles, please refer to [Style.ja.md](https://github.com/receptron/mulmocast-vision/blob/main/Style.ja.md).
79
132
 
80
133
  ### Official Repository & Package
@@ -139,3 +192,58 @@ MCP対応ツール(例: Claude Desktop)の設定ファイルに以下を追
139
192
  - SWOT分析、PEST分析、3C分析
140
193
  - サマリースライド、アジェンダスライド、クロージングスライド
141
194
 
195
+ ---
196
+
197
+ ## ログ機能
198
+
199
+ mulmocast-visionは、デバッグや監視を支援するため、すべての操作とエラーを自動的にログに記録します。
200
+
201
+ ### ログの保存場所
202
+
203
+ ログは `/tmp/mulmocast-vision-mcp/` に日次ローテーションで保存されます:
204
+ - 形式: `mcp_yyyymmdd.log` (例: `mcp_20251206.log`)
205
+ - 日付が変わると新しいログファイルが作成されます
206
+
207
+ ### 記録される内容
208
+
209
+ - **MCPサーバー操作**: サーバーの初期化、ツール呼び出し、実行結果
210
+ - **ファイル操作**: テンプレート読み込み、HTML/PNG生成、PDF作成
211
+ - **エラー**: 詳細なエラーメッセージとスタックトレース
212
+ - **デバッグ情報**: テンプレートレンダリング、ディレクトリ操作など
213
+
214
+ ### ログフォーマット
215
+
216
+ ログはJSON Lines形式で記録され、解析が容易です:
217
+
218
+ ```json
219
+ {
220
+ "timestamp": "2025-01-15T10:30:45.123Z",
221
+ "level": "ERROR",
222
+ "message": "Template file not found",
223
+ "data": {
224
+ "errorMessage": "getHtml: file /path/to/template.html not exists.",
225
+ "errorName": "Error",
226
+ "stack": "Error: getHtml: file...\n at htmlPlugin.getHtml...",
227
+ "templateFilePath": "/path/to/template.html",
228
+ "functionName": "createAgendaSlide"
229
+ }
230
+ }
231
+ ```
232
+
233
+ ### カスタムロガー
234
+
235
+ デフォルトのロガーを独自の実装(テレメトリーなど)に置き換えることができます:
236
+
237
+ ```typescript
238
+ import { setLogger, LoggerInterface } from 'mulmocast-vision/logger';
239
+
240
+ class CustomLogger implements LoggerInterface {
241
+ info(message: string, data?: unknown) {
242
+ // 独自の実装
243
+ }
244
+ // ... その他のメソッド
245
+ }
246
+
247
+ setLogger(new CustomLogger());
248
+ ```
249
+
@@ -1,3 +1,4 @@
1
+ import nunjucks from "nunjucks";
1
2
  import { type PluginOptionParams, type ToolArgs, type CreatePageOptions } from "./type";
2
3
  export declare class htmlPlugin {
3
4
  protected outputDir: string;
@@ -6,6 +7,7 @@ export declare class htmlPlugin {
6
7
  protected templateDir: string;
7
8
  protected sessionDir: string;
8
9
  protected templateOptions: CreatePageOptions;
10
+ protected nunjucksEnv: nunjucks.Environment;
9
11
  constructor({ outputDir, rootDir, templateOptions, htmlDir, // relative path
10
12
  templateDir, }: {
11
13
  outputDir?: string;
package/lib/html_class.js CHANGED
@@ -10,6 +10,7 @@ const pdfkit_1 = __importDefault(require("pdfkit"));
10
10
  const utils_1 = require("./utils");
11
11
  const commons_1 = require("./commons");
12
12
  const nunjucks_1 = __importDefault(require("nunjucks"));
13
+ const logger_1 = require("./logger");
13
14
  class htmlPlugin {
14
15
  constructor({ outputDir, rootDir, templateOptions,
15
16
  // for html template. If templateDir exists, it takes precedence over htmlDir.
@@ -18,6 +19,8 @@ class htmlPlugin {
18
19
  }) {
19
20
  // api for mcp
20
21
  this.callNamedFunction = async (functionName, args, options) => {
22
+ const logger = (0, logger_1.getLogger)();
23
+ logger.debug(`callNamedFunction: ${functionName}`, { args, options });
21
24
  const member = this[functionName];
22
25
  if (member && typeof member === "function") {
23
26
  return member(args, { ...options, functionName });
@@ -25,79 +28,138 @@ class htmlPlugin {
25
28
  return this.generateHtml(args, { ...options, functionName });
26
29
  };
27
30
  this.generateHtml = async (args, options) => {
31
+ const logger = (0, logger_1.getLogger)();
28
32
  const { outputFileName, functionName, imageFilePath, htmlFilePath } = options ?? {};
29
33
  if (!functionName) {
30
34
  throw new Error("functionName is required");
31
35
  }
32
- const html = this.getHtml(functionName, args);
33
- const outfile = imageFilePath ?? path_1.default.resolve(this.outputDir, this.sessionDir, `${outputFileName}.png`);
34
- const htmlFile = htmlFilePath ?? path_1.default.resolve(this.outputDir, this.sessionDir, `${outputFileName}.html`);
35
- await (0, utils_1.createPage)(this.rootDir, outfile, html, { htmlFile, ...this.templateOptions });
36
- return {
37
- text: `html generated successfully to: ${outfile}`,
38
- };
36
+ logger.info("Generating HTML", { functionName, outputFileName });
37
+ try {
38
+ const html = this.getHtml(functionName, args);
39
+ const outfile = imageFilePath ?? path_1.default.resolve(this.outputDir, this.sessionDir, `${outputFileName}.png`);
40
+ const htmlFile = htmlFilePath ?? path_1.default.resolve(this.outputDir, this.sessionDir, `${outputFileName}.html`);
41
+ await (0, utils_1.createPage)(this.rootDir, outfile, html, { htmlFile, ...this.templateOptions });
42
+ logger.fileWrite(outfile);
43
+ logger.fileWrite(htmlFile);
44
+ logger.info("HTML generated successfully", { outfile, htmlFile });
45
+ return {
46
+ text: `html generated successfully to: ${outfile}`,
47
+ };
48
+ }
49
+ catch (error) {
50
+ logger.error("Failed to generate HTML", error, {
51
+ functionName,
52
+ outputFileName,
53
+ args,
54
+ outputDir: this.outputDir,
55
+ sessionDir: this.sessionDir,
56
+ });
57
+ throw error;
58
+ }
39
59
  };
40
60
  // for electron
41
61
  this.getHtml = (functionName, args) => {
62
+ const logger = (0, logger_1.getLogger)();
42
63
  const templateFileName = (0, commons_1.functionNameToTemplateName)(functionName);
43
64
  const templateFilePath = path_1.default.resolve(this.templateDir ? this.templateDir : path_1.default.resolve(this.rootDir, "html", this.htmlDir), `${templateFileName}.html`);
44
65
  if (!fs_1.default.existsSync(templateFilePath)) {
45
- throw new Error(`getHtml: file ${templateFilePath} not exists.`);
66
+ const error = new Error(`getHtml: file ${templateFilePath} not exists.`);
67
+ logger.error("Template file not found", error, {
68
+ templateFilePath,
69
+ functionName,
70
+ templateFileName,
71
+ templateDir: this.templateDir,
72
+ htmlDir: this.htmlDir,
73
+ rootDir: this.rootDir,
74
+ });
75
+ throw error;
76
+ }
77
+ logger.fileRead(templateFilePath);
78
+ logger.debug("Rendering template", { templateFileName, args });
79
+ try {
80
+ // Use the configured Nunjucks environment instead of the default
81
+ // This ensures the FileSystemLoader can find the template
82
+ return this.nunjucksEnv.render(`${templateFileName}.html`, args);
83
+ }
84
+ catch (error) {
85
+ logger.error("Template rendering failed", error, { templateFilePath, templateFileName, args });
86
+ throw error;
46
87
  }
47
- return nunjucks_1.default.render(templateFilePath, args);
48
88
  };
49
89
  // for mcp
50
90
  this.setDirectory = async (args, __options) => {
91
+ const logger = (0, logger_1.getLogger)();
51
92
  this.sessionDir = args.directoryName;
52
93
  const outputDir = path_1.default.resolve(this.outputDir, this.sessionDir);
53
- // console.error(outputDir);
94
+ logger.info("Setting directory", { sessionDir: this.sessionDir, outputDir });
54
95
  (0, utils_1.mkdir)(outputDir);
55
96
  return {
56
97
  text: `set directory: ${this.sessionDir}`,
57
98
  };
58
99
  };
59
100
  this.createPDF = async (args, __options) => {
101
+ const logger = (0, logger_1.getLogger)();
60
102
  const { filename, images } = args ?? {};
61
- const imageWidth = 1536;
62
- const imageHeight = 1024;
63
- const pageWidth = imageWidth * 0.75; // 1152pt
64
- const pageHeight = imageHeight * 0.75; // 768pt
65
- const outputDir = path_1.default.resolve(this.outputDir, this.sessionDir);
66
- const files = images ??
67
- fs_1.default
68
- .readdirSync(outputDir)
69
- .filter((f) => f.toLowerCase().endsWith(".png"))
70
- .sort(new Intl.Collator("ja", { numeric: true }).compare);
71
- if (files.length === 0) {
72
- console.error("no PNG file");
73
- return;
74
- }
75
- const doc = new pdfkit_1.default({
76
- size: [pageWidth, pageHeight],
77
- margins: {
78
- top: 0,
79
- bottom: 0,
80
- left: 0,
81
- right: 0,
82
- },
83
- });
84
- doc.pipe(fs_1.default.createWriteStream(path_1.default.resolve(outputDir, filename)));
85
- files.forEach((f, i) => {
86
- if (i > 0) {
87
- doc.addPage({
88
- size: [pageWidth, pageHeight],
89
- margins: { top: 0, bottom: 0, left: 0, right: 0 },
90
- });
103
+ logger.info("Creating PDF", { filename, imagesCount: images?.length });
104
+ try {
105
+ const imageWidth = 1536;
106
+ const imageHeight = 1024;
107
+ const pageWidth = imageWidth * 0.75; // 1152pt
108
+ const pageHeight = imageHeight * 0.75; // 768pt
109
+ const outputDir = path_1.default.resolve(this.outputDir, this.sessionDir);
110
+ const files = images ??
111
+ fs_1.default
112
+ .readdirSync(outputDir)
113
+ .filter((f) => f.toLowerCase().endsWith(".png"))
114
+ .sort(new Intl.Collator("ja", { numeric: true }).compare);
115
+ if (files.length === 0) {
116
+ const error = new Error("No PNG files found");
117
+ logger.error("No PNG files found", error, { outputDir });
118
+ console.error("no PNG file");
119
+ return;
91
120
  }
92
- doc.image(path_1.default.join(outputDir, f), 0, 0, {
93
- width: pageWidth,
94
- height: pageHeight,
121
+ logger.debug("PNG files found", { count: files.length, files });
122
+ const doc = new pdfkit_1.default({
123
+ size: [pageWidth, pageHeight],
124
+ margins: {
125
+ top: 0,
126
+ bottom: 0,
127
+ left: 0,
128
+ right: 0,
129
+ },
95
130
  });
96
- });
97
- doc.end();
98
- return {
99
- text: `pdf created: ${outputDir}`,
100
- };
131
+ const pdfPath = path_1.default.resolve(outputDir, filename);
132
+ doc.pipe(fs_1.default.createWriteStream(pdfPath));
133
+ files.forEach((f, i) => {
134
+ const imagePath = path_1.default.join(outputDir, f);
135
+ logger.fileRead(imagePath);
136
+ if (i > 0) {
137
+ doc.addPage({
138
+ size: [pageWidth, pageHeight],
139
+ margins: { top: 0, bottom: 0, left: 0, right: 0 },
140
+ });
141
+ }
142
+ doc.image(imagePath, 0, 0, {
143
+ width: pageWidth,
144
+ height: pageHeight,
145
+ });
146
+ });
147
+ doc.end();
148
+ logger.fileWrite(pdfPath);
149
+ logger.info("PDF created successfully", { pdfPath, pageCount: files.length });
150
+ return {
151
+ text: `pdf created: ${outputDir}`,
152
+ };
153
+ }
154
+ catch (error) {
155
+ logger.error("Failed to create PDF", error, {
156
+ filename,
157
+ images,
158
+ outputDir: this.outputDir,
159
+ sessionDir: this.sessionDir,
160
+ });
161
+ throw error;
162
+ }
101
163
  };
102
164
  this.dumpMulmoScript = () => { };
103
165
  this.outputDir = outputDir ?? (0, utils_1.getOutDir)();
@@ -106,6 +168,15 @@ class htmlPlugin {
106
168
  this.htmlDir = htmlDir ?? "html2";
107
169
  this.templateDir = templateDir ?? "";
108
170
  this.templateOptions = templateOptions ?? {};
171
+ // Configure Nunjucks environment with FileSystemLoader
172
+ const templatePath = this.templateDir ? this.templateDir : path_1.default.resolve(this.rootDir, "html", this.htmlDir);
173
+ const loader = new nunjucks_1.default.FileSystemLoader(templatePath, {
174
+ noCache: true, // Disable cache to ensure fresh templates
175
+ });
176
+ this.nunjucksEnv = new nunjucks_1.default.Environment(loader, {
177
+ autoescape: false, // Don't escape HTML
178
+ throwOnUndefined: false, // Don't throw on undefined variables
179
+ });
109
180
  }
110
181
  }
111
182
  exports.htmlPlugin = htmlPlugin;
@@ -0,0 +1,49 @@
1
+ type LogLevel = "INFO" | "ERROR" | "WARN" | "DEBUG";
2
+ export interface LogEntry {
3
+ timestamp: string;
4
+ level: LogLevel;
5
+ message: string;
6
+ data?: unknown;
7
+ }
8
+ export interface LoggerInterface {
9
+ info(message: string, data?: unknown): void;
10
+ error(message: string, error?: Error | unknown, data?: unknown): void;
11
+ warn(message: string, data?: unknown): void;
12
+ debug(message: string, data?: unknown): void;
13
+ fileRead(filePath: string): void;
14
+ fileWrite(filePath: string, size?: number): void;
15
+ fileDelete(filePath: string): void;
16
+ toolCall(toolName: string, args: unknown): void;
17
+ toolResult(toolName: string, success: boolean, result?: unknown): void;
18
+ }
19
+ declare class FileLogger implements LoggerInterface {
20
+ private logDir;
21
+ private logFile;
22
+ constructor(logDir?: string);
23
+ private formatTimestamp;
24
+ private writeLog;
25
+ info(message: string, data?: unknown): void;
26
+ error(message: string, error?: Error | unknown, data?: unknown): void;
27
+ warn(message: string, data?: unknown): void;
28
+ debug(message: string, data?: unknown): void;
29
+ fileRead(filePath: string): void;
30
+ fileWrite(filePath: string, size?: number): void;
31
+ fileDelete(filePath: string): void;
32
+ toolCall(toolName: string, args: unknown): void;
33
+ toolResult(toolName: string, success: boolean, result?: unknown): void;
34
+ }
35
+ declare class NoOpLogger implements LoggerInterface {
36
+ info(__message: string, __data?: unknown): void;
37
+ error(__message: string, __error?: Error | unknown, __data?: unknown): void;
38
+ warn(__message: string, __data?: unknown): void;
39
+ debug(__message: string, __data?: unknown): void;
40
+ fileRead(__filePath: string): void;
41
+ fileWrite(__filePath: string, __size?: number): void;
42
+ fileDelete(__filePath: string): void;
43
+ toolCall(__toolName: string, __args: unknown): void;
44
+ toolResult(__toolName: string, __success: boolean, __result?: unknown): void;
45
+ }
46
+ export declare const setLogger: (logger: LoggerInterface) => void;
47
+ export declare const getLogger: () => LoggerInterface;
48
+ export declare const logger: LoggerInterface;
49
+ export { FileLogger, NoOpLogger };
package/lib/logger.js ADDED
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NoOpLogger = exports.FileLogger = exports.logger = exports.getLogger = exports.setLogger = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const os_1 = __importDefault(require("os"));
10
+ // Default file-based logger implementation
11
+ class FileLogger {
12
+ constructor(logDir) {
13
+ this.logDir = logDir ?? path_1.default.join(os_1.default.tmpdir(), "mulmocast-vision-mcp");
14
+ // Generate date suffix (yyyymmdd)
15
+ const now = new Date();
16
+ const year = now.getFullYear();
17
+ const month = String(now.getMonth() + 1).padStart(2, "0");
18
+ const day = String(now.getDate()).padStart(2, "0");
19
+ const dateSuffix = `${year}${month}${day}`;
20
+ this.logFile = path_1.default.join(this.logDir, `mcp_${dateSuffix}.log`);
21
+ // Ensure log directory exists
22
+ if (!fs_1.default.existsSync(this.logDir)) {
23
+ fs_1.default.mkdirSync(this.logDir, { recursive: true });
24
+ }
25
+ }
26
+ formatTimestamp() {
27
+ return new Date().toISOString();
28
+ }
29
+ writeLog(level, message, data) {
30
+ const timestamp = this.formatTimestamp();
31
+ const logEntry = {
32
+ timestamp,
33
+ level,
34
+ message,
35
+ };
36
+ if (data !== undefined) {
37
+ logEntry.data = data;
38
+ }
39
+ const logLine = JSON.stringify(logEntry) + "\n";
40
+ try {
41
+ fs_1.default.appendFileSync(this.logFile, logLine);
42
+ }
43
+ catch (error) {
44
+ // Fallback to console.error if file write fails
45
+ console.error("Failed to write to log file:", error);
46
+ console.error(logLine);
47
+ }
48
+ }
49
+ info(message, data) {
50
+ this.writeLog("INFO", message, data);
51
+ }
52
+ error(message, error, data) {
53
+ const errorData = {};
54
+ if (error instanceof Error) {
55
+ errorData.errorMessage = error.message;
56
+ errorData.errorName = error.name;
57
+ errorData.stack = error.stack;
58
+ // Include any custom properties on the error
59
+ const errorObj = error;
60
+ Object.keys(error).forEach((key) => {
61
+ if (key !== "message" && key !== "name" && key !== "stack") {
62
+ errorData[key] = errorObj[key];
63
+ }
64
+ });
65
+ }
66
+ else if (error !== undefined) {
67
+ errorData.error = error;
68
+ }
69
+ const combinedData = data ? { ...errorData, ...data } : errorData;
70
+ this.writeLog("ERROR", message, Object.keys(combinedData).length > 0 ? combinedData : undefined);
71
+ }
72
+ warn(message, data) {
73
+ this.writeLog("WARN", message, data);
74
+ }
75
+ debug(message, data) {
76
+ this.writeLog("DEBUG", message, data);
77
+ }
78
+ fileRead(filePath) {
79
+ this.info("File read", { operation: "read", filePath });
80
+ }
81
+ fileWrite(filePath, size) {
82
+ this.info("File write", { operation: "write", filePath, size });
83
+ }
84
+ fileDelete(filePath) {
85
+ this.info("File delete", { operation: "delete", filePath });
86
+ }
87
+ toolCall(toolName, args) {
88
+ this.info("Tool called", { toolName, args });
89
+ }
90
+ toolResult(toolName, success, result) {
91
+ this.info("Tool result", { toolName, success, result });
92
+ }
93
+ }
94
+ exports.FileLogger = FileLogger;
95
+ // No-op logger for disabling logging
96
+ class NoOpLogger {
97
+ info(__message, __data) { }
98
+ error(__message, __error, __data) { }
99
+ warn(__message, __data) { }
100
+ debug(__message, __data) { }
101
+ fileRead(__filePath) { }
102
+ fileWrite(__filePath, __size) { }
103
+ fileDelete(__filePath) { }
104
+ toolCall(__toolName, __args) { }
105
+ toolResult(__toolName, __success, __result) { }
106
+ }
107
+ exports.NoOpLogger = NoOpLogger;
108
+ // Logger manager
109
+ class LoggerManager {
110
+ constructor() {
111
+ this.logger = new FileLogger();
112
+ }
113
+ setLogger(logger) {
114
+ this.logger = logger;
115
+ }
116
+ getLogger() {
117
+ return this.logger;
118
+ }
119
+ }
120
+ // Export singleton instance
121
+ const loggerManager = new LoggerManager();
122
+ const setLogger = (logger) => {
123
+ loggerManager.setLogger(logger);
124
+ };
125
+ exports.setLogger = setLogger;
126
+ const getLogger = () => {
127
+ return loggerManager.getLogger();
128
+ };
129
+ exports.getLogger = getLogger;
130
+ // Proxy object that delegates to current logger
131
+ // This ensures that the exported logger updates when setLogger() is called
132
+ exports.logger = {
133
+ info: (message, data) => loggerManager.getLogger().info(message, data),
134
+ error: (message, error, data) => loggerManager.getLogger().error(message, error, data),
135
+ warn: (message, data) => loggerManager.getLogger().warn(message, data),
136
+ debug: (message, data) => loggerManager.getLogger().debug(message, data),
137
+ fileRead: (filePath) => loggerManager.getLogger().fileRead(filePath),
138
+ fileWrite: (filePath, size) => loggerManager.getLogger().fileWrite(filePath, size),
139
+ fileDelete: (filePath) => loggerManager.getLogger().fileDelete(filePath),
140
+ toolCall: (toolName, args) => loggerManager.getLogger().toolCall(toolName, args),
141
+ toolResult: (toolName, success, result) => loggerManager.getLogger().toolResult(toolName, success, result),
142
+ };
package/lib/mcp.js CHANGED
@@ -9,7 +9,9 @@ const html_class_1 = require("./html_class");
9
9
  const commons_1 = require("./commons");
10
10
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
11
11
  const utils_1 = require("./utils");
12
+ const logger_1 = require("./logger");
12
13
  const getServer = (handler) => {
14
+ const logger = (0, logger_1.getLogger)();
13
15
  const server = new index_js_1.Server({
14
16
  name: "mulmocast-vision",
15
17
  version: "1.0.2",
@@ -18,18 +20,22 @@ const getServer = (handler) => {
18
20
  tools: {},
19
21
  },
20
22
  });
23
+ logger.info("MCP Server initialized", { name: "mulmocast-vision", version: "1.0.2" });
21
24
  // List available tools
22
25
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
26
+ logger.debug("List tools requested");
23
27
  return (0, commons_1.openAIToolsToAnthropicTools)([...tools_1.tools, ...tools_1.mcp_tools]);
24
28
  });
25
29
  // Handle tool calls
26
30
  server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
27
31
  const { name, arguments: args } = request.params;
32
+ logger.toolCall(name, args);
28
33
  console.error([...tools_1.tools, ...tools_1.mcp_tools]);
29
34
  try {
30
35
  if (args) {
31
36
  const fileName = (0, commons_1.generateUniqueId)();
32
37
  const result = await handler.callNamedFunction(name, args, { outputFileName: fileName });
38
+ logger.toolResult(name, true, result);
33
39
  return {
34
40
  content: [
35
41
  {
@@ -43,6 +49,8 @@ const getServer = (handler) => {
43
49
  }
44
50
  catch (error) {
45
51
  const errorMessage = error instanceof Error ? error.message : String(error);
52
+ logger.toolResult(name, false, { error: errorMessage });
53
+ logger.error(`Tool call failed: ${name}`, error, { toolName: name, args });
46
54
  return {
47
55
  content: [
48
56
  {
@@ -58,12 +66,22 @@ const getServer = (handler) => {
58
66
  };
59
67
  exports.getServer = getServer;
60
68
  const main = async () => {
61
- const rootDir = (0, utils_1.getRootDir)();
62
- const outputDir = (0, utils_1.getOutDir)();
63
- const htmlDir = "html2";
64
- const handler = new html_class_1.htmlPlugin({ outputDir, rootDir, htmlDir });
65
- const server = (0, exports.getServer)(handler);
66
- const transport = new stdio_js_1.StdioServerTransport();
67
- await server.connect(transport);
69
+ const logger = (0, logger_1.getLogger)();
70
+ try {
71
+ logger.info("Starting MCP server");
72
+ const rootDir = (0, utils_1.getRootDir)();
73
+ const outputDir = (0, utils_1.getOutDir)();
74
+ const htmlDir = "html2";
75
+ logger.info("Configuration loaded", { rootDir, outputDir, htmlDir });
76
+ const handler = new html_class_1.htmlPlugin({ outputDir, rootDir, htmlDir });
77
+ const server = (0, exports.getServer)(handler);
78
+ const transport = new stdio_js_1.StdioServerTransport();
79
+ await server.connect(transport);
80
+ logger.info("MCP server connected and ready");
81
+ }
82
+ catch (error) {
83
+ logger.error("Failed to start MCP server", error);
84
+ throw error;
85
+ }
68
86
  };
69
87
  main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast-vision",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Easy and stylish presentation slide generator",
5
5
  "mcpName": "io.github.isamu/mulmocast-vision",
6
6
  "main": "lib/index.js",