index.ts•5.21 kB
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
McpError,
ErrorCode,
} from '@modelcontextprotocol/sdk/types.js';
import { SatoriTemplates } from './satori-templates.js';
import {
SatoriGenerateRequest,
SatoriStructureType
} from './types.js';
class SatoriSyntaxMcpServer {
private server: Server;
constructor() {
this.server = new Server(
{
name: 'satorify-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.setupToolHandlers();
this.setupErrorHandling();
}
private setupErrorHandling(): void {
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
private setupToolHandlers(): void {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'generate_satori_syntax',
description: 'さとり構文を生成します(140文字のX投稿用)',
inputSchema: {
type: 'object',
properties: {
structure_type: {
type: 'string',
enum: ['A', 'B', 'C', 'D', 'E'],
description: '構文タイプ(A: 基本形、B: 常識の否定、C: 一般的なニュース、D: 衝撃的なニュース、E: ステップ紹介)',
},
target_audience: {
type: 'string',
description: 'ターゲット層(例: 副業を始めたい人、AIに興味がある人)',
},
message_content: {
type: 'string',
description: '伝えたいメッセージの内容',
},
expected_action: {
type: 'string',
description: '期待する行動(例: サービスを試す、投稿をシェアする)',
},
news_content: {
type: 'string',
description: 'ニュース内容(構文CとDで使用、オプション)',
},
},
required: ['structure_type', 'target_audience', 'message_content', 'expected_action'],
},
},
{
name: 'get_satori_structure_types',
description: 'さとり構文の利用可能な構文タイプ一覧を取得します',
inputSchema: {
type: 'object',
properties: {},
},
},
],
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'generate_satori_syntax':
return await this.generateSatoriSyntax(args as any);
case 'get_satori_structure_types':
return await this.getSatoriStructureTypes();
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error) {
if (error instanceof McpError) {
throw error;
}
throw new McpError(
ErrorCode.InternalError,
`Error in ${name}: ${error instanceof Error ? error.message : String(error)}`
);
}
});
}
private async generateSatoriSyntax(request: SatoriGenerateRequest): Promise<{ content: Array<{ type: string; text: string }> }> {
const prompt = SatoriTemplates.generateSatoriPrompt(request);
const structureTypeInfo = SatoriTemplates.getStructureTypeDescription(request.structure_type);
return {
content: [
{
type: 'text',
text: `さとり構文生成プロンプト(構文タイプ ${request.structure_type}: ${structureTypeInfo}):\\n\\n${prompt}\\n\\n**注意:** このプロンプトを使用しているLLM(Claude、ChatGPT、Geminiなど)で実行して、さとり構文を生成してください。MCPサーバー自体はプロンプトの提供のみを行います。`,
},
],
};
}
private async getSatoriStructureTypes(): Promise<{ content: Array<{ type: string; text: string }> }> {
const structureTypes = SatoriTemplates.getAvailableStructureTypes();
const typeList = structureTypes
.map(({ type, description }) => `**${type}**: ${description}`)
.join('\\n');
return {
content: [
{
type: 'text',
text: `さとり構文の利用可能な構文タイプ:\\n\\n${typeList}\\n\\n各構文タイプの詳細は generate_satori_syntax ツールで確認できます。`,
},
],
};
}
async run(): Promise<void> {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Satori Syntax MCP server running on stdio');
}
}
const server = new SatoriSyntaxMcpServer();
server.run().catch(console.error);