#!/usr/bin/env node
/**
* MT Content Refactor MCP Server
*
* Movable Type のコンテンツを一括でリファクタリングするための MCP サーバー
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
// Connection tools
import {
handleListConnections,
handleAddConnection,
handleUseConnection,
handleRemoveConnection,
handleTestConnection,
addConnectionSchema,
useConnectionSchema,
removeConnectionSchema,
testConnectionSchema,
} from './tools/connection-tools.js';
// Content tools
import {
handleListSites,
handleListEntries,
handleGetEntry,
handleListPages,
handleGetPage,
handleListContentTypes,
handleListContentData,
handleGetContentData,
listSitesSchema,
listEntriesSchema,
getEntrySchema,
listPagesSchema,
getPageSchema,
listContentTypesSchema,
listContentDataSchema,
getContentDataSchema,
} from './tools/content-tools.js';
// Backup tools
import {
handleCreateBackup,
handleGetBackupItems,
handleSetTransform,
handleSetBulkTransform,
handleGenerateDiffReport,
handleApplyChanges,
handleRestore,
handleListSessions,
handleLoadSession,
handleDeleteSession,
createBackupSchema,
setTransformSchema,
setBulkTransformSchema,
generateReportSchema,
applyChangesSchema,
restoreSchema,
sessionIdSchema,
} from './tools/backup-tools.js';
// Zod schema to JSON Schema converter
function zodToJsonSchema(schema: any): any {
const shape = schema._def?.shape?.() || schema.shape;
if (!shape) {
return { type: 'object', properties: {} };
}
const properties: Record<string, any> = {};
const required: string[] = [];
for (const [key, value] of Object.entries(shape)) {
const field = value as any;
const def = field._def;
let prop: any = {};
if (def?.typeName === 'ZodString') {
prop.type = 'string';
} else if (def?.typeName === 'ZodNumber') {
prop.type = 'number';
} else if (def?.typeName === 'ZodBoolean') {
prop.type = 'boolean';
} else if (def?.typeName === 'ZodEnum') {
prop.type = 'string';
prop.enum = def.values;
} else if (def?.typeName === 'ZodArray') {
prop.type = 'array';
prop.items = { type: 'object' };
} else if (def?.typeName === 'ZodOptional') {
const innerDef = def.innerType._def;
if (innerDef?.typeName === 'ZodString') {
prop.type = 'string';
} else if (innerDef?.typeName === 'ZodNumber') {
prop.type = 'number';
} else if (innerDef?.typeName === 'ZodBoolean') {
prop.type = 'boolean';
}
} else if (def?.typeName === 'ZodDefault') {
const innerDef = def.innerType._def;
if (innerDef?.typeName === 'ZodNumber') {
prop.type = 'number';
prop.default = def.defaultValue();
} else if (innerDef?.typeName === 'ZodString') {
prop.type = 'string';
prop.default = def.defaultValue();
} else if (innerDef?.typeName === 'ZodBoolean') {
prop.type = 'boolean';
prop.default = def.defaultValue();
} else if (innerDef?.typeName === 'ZodEnum') {
prop.type = 'string';
prop.enum = innerDef.values;
prop.default = def.defaultValue();
}
}
if (def?.description) {
prop.description = def.description;
} else if (def?.innerType?._def?.description) {
prop.description = def.innerType._def.description;
}
properties[key] = prop;
// Check if required
if (def?.typeName !== 'ZodOptional' && def?.typeName !== 'ZodDefault') {
required.push(key);
}
}
return {
type: 'object',
properties,
required: required.length > 0 ? required : undefined,
};
}
// ツール定義
const tools = [
// 接続管理
{
name: 'mt_list_connections',
description: '登録済みのMT接続一覧を表示します',
inputSchema: { type: 'object', properties: {} },
},
{
name: 'mt_add_connection',
description: '新しいMT接続を追加します',
inputSchema: zodToJsonSchema(addConnectionSchema),
},
{
name: 'mt_use_connection',
description: '指定した接続をアクティブにします',
inputSchema: zodToJsonSchema(useConnectionSchema),
},
{
name: 'mt_remove_connection',
description: '接続を削除します',
inputSchema: zodToJsonSchema(removeConnectionSchema),
},
{
name: 'mt_test_connection',
description: '接続をテストします',
inputSchema: zodToJsonSchema(testConnectionSchema),
},
// コンテンツ取得
{
name: 'mt_list_sites',
description: 'サイト一覧を取得します',
inputSchema: zodToJsonSchema(listSitesSchema),
},
{
name: 'mt_list_entries',
description: '記事一覧を取得します',
inputSchema: zodToJsonSchema(listEntriesSchema),
},
{
name: 'mt_get_entry',
description: '記事の詳細を取得します',
inputSchema: zodToJsonSchema(getEntrySchema),
},
{
name: 'mt_list_pages',
description: 'ウェブページ一覧を取得します',
inputSchema: zodToJsonSchema(listPagesSchema),
},
{
name: 'mt_get_page',
description: 'ウェブページの詳細を取得します',
inputSchema: zodToJsonSchema(getPageSchema),
},
{
name: 'mt_list_content_types',
description: 'コンテンツタイプ一覧を取得します',
inputSchema: zodToJsonSchema(listContentTypesSchema),
},
{
name: 'mt_list_content_data',
description: 'コンテンツデータ一覧を取得します',
inputSchema: zodToJsonSchema(listContentDataSchema),
},
{
name: 'mt_get_content_data',
description: 'コンテンツデータの詳細を取得します',
inputSchema: zodToJsonSchema(getContentDataSchema),
},
// バックアップ・変換
{
name: 'mt_create_backup',
description: 'サイトのコンテンツをバックアップします。変換前に必ず実行してください。',
inputSchema: zodToJsonSchema(createBackupSchema),
},
{
name: 'mt_get_backup_items',
description: 'バックアップしたアイテムの一覧を表示します',
inputSchema: { type: 'object', properties: {} },
},
{
name: 'mt_set_transform',
description: '個別のアイテムに変換後のHTMLを設定します',
inputSchema: zodToJsonSchema(setTransformSchema),
},
{
name: 'mt_set_bulk_transform',
description: '複数のアイテムに一括で変換後のHTMLを設定します',
inputSchema: zodToJsonSchema(setBulkTransformSchema),
},
{
name: 'mt_generate_diff_report',
description: '変換前後の差分レポートを生成します',
inputSchema: zodToJsonSchema(generateReportSchema),
},
{
name: 'mt_apply_changes',
description: '変換結果をMTに適用します',
inputSchema: zodToJsonSchema(applyChangesSchema),
},
{
name: 'mt_restore',
description: 'バックアップから元の状態にリストアします',
inputSchema: zodToJsonSchema(restoreSchema),
},
// セッション管理
{
name: 'mt_list_sessions',
description: 'バックアップセッション一覧を表示します',
inputSchema: { type: 'object', properties: {} },
},
{
name: 'mt_load_session',
description: '過去のバックアップセッションを読み込みます',
inputSchema: zodToJsonSchema(sessionIdSchema),
},
{
name: 'mt_delete_session',
description: 'バックアップセッションを削除します',
inputSchema: zodToJsonSchema(sessionIdSchema),
},
];
// サーバーを作成
const server = new Server(
{
name: 'mt-content-refactor',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
// ツール一覧ハンドラ
server.setRequestHandler(ListToolsRequestSchema, async () => {
return { tools };
});
// ツール実行ハンドラ
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
// 接続管理
case 'mt_list_connections':
return handleListConnections();
case 'mt_add_connection':
return handleAddConnection(addConnectionSchema.parse(args));
case 'mt_use_connection':
return handleUseConnection(useConnectionSchema.parse(args));
case 'mt_remove_connection':
return handleRemoveConnection(removeConnectionSchema.parse(args));
case 'mt_test_connection':
return handleTestConnection(testConnectionSchema.parse(args));
// コンテンツ取得
case 'mt_list_sites':
return handleListSites();
case 'mt_list_entries':
return handleListEntries(listEntriesSchema.parse(args));
case 'mt_get_entry':
return handleGetEntry(getEntrySchema.parse(args));
case 'mt_list_pages':
return handleListPages(listPagesSchema.parse(args));
case 'mt_get_page':
return handleGetPage(getPageSchema.parse(args));
case 'mt_list_content_types':
return handleListContentTypes(listContentTypesSchema.parse(args));
case 'mt_list_content_data':
return handleListContentData(listContentDataSchema.parse(args));
case 'mt_get_content_data':
return handleGetContentData(getContentDataSchema.parse(args));
// バックアップ・変換
case 'mt_create_backup':
return handleCreateBackup(createBackupSchema.parse(args));
case 'mt_get_backup_items':
return handleGetBackupItems();
case 'mt_set_transform':
return handleSetTransform(setTransformSchema.parse(args));
case 'mt_set_bulk_transform':
return handleSetBulkTransform(setBulkTransformSchema.parse(args));
case 'mt_generate_diff_report':
return handleGenerateDiffReport(generateReportSchema.parse(args));
case 'mt_apply_changes':
return handleApplyChanges(applyChangesSchema.parse(args));
case 'mt_restore':
return handleRestore(restoreSchema.parse(args));
// セッション管理
case 'mt_list_sessions':
return handleListSessions();
case 'mt_load_session':
return handleLoadSession(sessionIdSchema.parse(args));
case 'mt_delete_session':
return handleDeleteSession(sessionIdSchema.parse(args));
default:
return {
content: [{
type: 'text',
text: `Unknown tool: ${name}`,
}],
isError: true,
};
}
} catch (error) {
return {
content: [{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
}],
isError: true,
};
}
});
// サーバーを起動
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('MT Content Refactor MCP server running on stdio');
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});