97ac0f71f5
https://assetstore.unity.com/packages/tools/generative-ai/synaptic-ai-pro-natural-language-control-for-unity-336030
195 lines
5.3 KiB
JavaScript
195 lines
5.3 KiB
JavaScript
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
const {
|
|
ListToolsRequestSchema,
|
|
CallToolRequestSchema,
|
|
ListResourcesRequestSchema,
|
|
ReadResourceRequestSchema
|
|
} = require('@modelcontextprotocol/sdk/types.js');
|
|
|
|
// Zodスキーマを MCP JSON Schema に変換
|
|
function convertZodSchemaToMCP(zodSchema) {
|
|
if (!zodSchema || !zodSchema._def) return {};
|
|
|
|
const def = zodSchema._def;
|
|
|
|
if (def.typeName === 'ZodObject') {
|
|
const properties = {};
|
|
const required = [];
|
|
|
|
for (const [key, value] of Object.entries(def.shape())) {
|
|
properties[key] = convertZodSchemaToMCP(value);
|
|
if (!value.isOptional()) {
|
|
required.push(key);
|
|
}
|
|
}
|
|
|
|
return {
|
|
type: 'object',
|
|
properties,
|
|
required: required.length > 0 ? required : undefined
|
|
};
|
|
}
|
|
|
|
if (def.typeName === 'ZodString') {
|
|
return { type: 'string' };
|
|
}
|
|
|
|
if (def.typeName === 'ZodNumber') {
|
|
return { type: 'number' };
|
|
}
|
|
|
|
if (def.typeName === 'ZodBoolean') {
|
|
return { type: 'boolean' };
|
|
}
|
|
|
|
if (def.typeName === 'ZodArray') {
|
|
return {
|
|
type: 'array',
|
|
items: convertZodSchemaToMCP(def.type)
|
|
};
|
|
}
|
|
|
|
if (def.typeName === 'ZodEnum') {
|
|
return {
|
|
type: 'string',
|
|
enum: def.values
|
|
};
|
|
}
|
|
|
|
if (def.typeName === 'ZodOptional') {
|
|
return convertZodSchemaToMCP(def.innerType);
|
|
}
|
|
|
|
if (def.typeName === 'ZodDefault') {
|
|
const schema = convertZodSchemaToMCP(def.innerType);
|
|
schema.default = def.defaultValue();
|
|
return schema;
|
|
}
|
|
|
|
if (def.typeName === 'ZodAny') {
|
|
return {}; // Any type - no restrictions
|
|
}
|
|
|
|
if (def.typeName === 'ZodRecord') {
|
|
return { type: 'object' };
|
|
}
|
|
|
|
return { type: 'string' };
|
|
}
|
|
|
|
function createServer() {
|
|
const registeredTools = {};
|
|
const registeredResources = {};
|
|
|
|
const server = new Server(
|
|
{
|
|
name: 'unity-mcp',
|
|
version: '1.1.0',
|
|
},
|
|
{
|
|
capabilities: {
|
|
resources: {},
|
|
tools: {},
|
|
},
|
|
}
|
|
);
|
|
|
|
|
|
// ツール一覧を返すハンドラー
|
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
return {
|
|
tools: Object.entries(registeredTools).map(([name, tool]) => ({
|
|
name,
|
|
description: tool.description,
|
|
inputSchema: tool.inputSchema
|
|
}))
|
|
};
|
|
});
|
|
|
|
// ツール実行ハンドラー
|
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
|
|
if (!registeredTools[name]) {
|
|
throw new Error(`Unknown tool: ${name}`);
|
|
}
|
|
|
|
const tool = registeredTools[name];
|
|
|
|
try {
|
|
// Zodでバリデーション
|
|
if (tool.zodSchema) {
|
|
tool.zodSchema.parse(args);
|
|
}
|
|
|
|
const result = await tool.handler(args);
|
|
return result;
|
|
} catch (error) {
|
|
// エラーログを標準エラー出力に出さない(JSON-RPC通信を妨害するため)
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// リソース一覧を返すハンドラー
|
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
return {
|
|
resources: Object.entries(registeredResources).map(([uri, resource]) => ({
|
|
uri,
|
|
name: resource.name,
|
|
description: resource.description,
|
|
mimeType: resource.mimeType
|
|
}))
|
|
};
|
|
});
|
|
|
|
// リソース読み取りハンドラー
|
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
const { uri } = request.params;
|
|
|
|
if (!registeredResources[uri]) {
|
|
throw new Error(`Unknown resource: ${uri}`);
|
|
}
|
|
|
|
const resource = registeredResources[uri];
|
|
const result = await resource.handler();
|
|
return result;
|
|
});
|
|
|
|
// ツール登録メソッド
|
|
server.registerTool = function(name, config, handler) {
|
|
const inputSchema = convertZodSchemaToMCP(config.inputSchema);
|
|
|
|
registeredTools[name] = {
|
|
description: config.description || config.title,
|
|
inputSchema,
|
|
zodSchema: config.inputSchema,
|
|
handler
|
|
};
|
|
|
|
// ログを標準エラー出力に出さない
|
|
};
|
|
|
|
// リソース登録メソッド
|
|
server.registerResource = function(uri, config, handler) {
|
|
registeredResources[uri] = {
|
|
name: config.title,
|
|
description: config.description,
|
|
mimeType: config.mimeType,
|
|
handler
|
|
};
|
|
|
|
// ログを標準エラー出力に出さない
|
|
};
|
|
|
|
// サーバー起動メソッド
|
|
server.start = async function() {
|
|
const transport = new StdioServerTransport();
|
|
await this.connect(transport);
|
|
// ログを標準エラー出力に出さない
|
|
};
|
|
|
|
return server;
|
|
}
|
|
|
|
module.exports = { createServer }; |