Skip to main content
Glama

cwtools-config

Retrieve Stellaris config rules (.cwt files) for modding, including specific files or entire directories from stable or development versions. Supports listing files for quick reference.

Instructions

CWToolsのStellarisコンフィグルール(.cwt files)を取得します。最新の安定版または開発版から、config/直下およびサブディレクトリ(common/等)内の特定のファイルまたは全ファイルを取得できます。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileNo取得する特定の.cwtファイル名またはパス (例: common.cwt, common/agreements.cwt)
listOnlyNoファイル一覧のみを表示する場合はtrue
versionNo取得するバージョン: stable (最新タグ) または latest (開発版)stable

Implementation Reference

  • The main handler function for the 'cwtools-config' tool. Fetches .cwt config files from cwtools/cwtools-stellaris-config GitHub repo. Supports stable/latest versions, specific file fetch, list-only mode, with comprehensive retry logic, directory traversal, and formatted Markdown output.
    execute: async (args, { log }) => { try { log.info("Fetching CWTools Stellaris config...", { file: args.file, listOnly: args.listOnly, version: args.version, }); // 参照するブランチ/タグを決定 let ref: string | undefined; if (args.version === "stable") { ref = await getLatestTag(CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME); log.info(`Using stable version: ${ref}`); } else { log.info("Using latest development version (main branch)"); } // configディレクトリの内容を取得 const configContents = await getDirectoryContents( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, "config", ref, ); // .cwtファイルのみをフィルタ(ルートレベル) const rootCwtFiles = configContents.filter( (item) => item.type === "file" && item.name.endsWith(".cwt"), ); // サブディレクトリからも.cwtファイルを取得 const subdirectories = configContents.filter( (item) => item.type === "dir", ); const nestedCwtFiles: Array<{ download_url: string; name: string; path: string; size: number; }> = []; for (const subdir of subdirectories) { let retryCount = 0; const maxSubdirRetries = 2; while (retryCount <= maxSubdirRetries) { try { log.debug( `Reading subdirectory: ${subdir.name} (attempt ${retryCount + 1})`, ); const subdirContents = await getDirectoryContents( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${subdir.name}`, ref, ); const subdirCwtFiles = subdirContents .filter( (item) => item.type === "file" && item.name.endsWith(".cwt"), ) .map((file) => ({ download_url: file.download_url, name: file.name, path: `${subdir.name}/${file.name}`, size: file.size, })); nestedCwtFiles.push(...subdirCwtFiles); log.info( `Successfully read ${subdirCwtFiles.length} .cwt files from ${subdir.name}/`, ); // 成功したらループを抜ける break; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (retryCount < maxSubdirRetries) { const delay = 1000 * (retryCount + 1); // 1秒、2秒、3秒 log.warn( `Failed to read subdirectory ${subdir.name} (attempt ${retryCount + 1}), retrying in ${delay}ms`, { error: errorMessage, }, ); await new Promise((resolve) => setTimeout(resolve, delay)); retryCount++; } else { log.error( `Failed to read subdirectory ${subdir.name} after ${maxSubdirRetries + 1} attempts`, { error: errorMessage, }, ); break; } } } // API制限を考慮して少し待機 await new Promise((resolve) => setTimeout(resolve, 200)); } // 全ての.cwtファイルを統合 const allCwtFiles = [ ...rootCwtFiles.map((file) => ({ download_url: file.download_url, name: file.name, path: file.name, size: file.size, })), ...nestedCwtFiles, ]; // 後続の処理で使用するため、cwtFilesをallCwtFilesに置き換え const cwtFiles = allCwtFiles; if (args.listOnly) { // ファイル一覧のみを返す const fileList = cwtFiles.map((file) => ({ downloadUrl: file.download_url, name: file.name, path: file.path, size: file.size, })); return { content: [ { text: `# CWTools Stellaris Config Files (${args.version}) ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **Total .cwt files**: ${fileList.length} ## Available Config Files ${fileList.map((file) => `- **${file.path || file.name}** (${file.size} bytes)`).join("\n")} --- *Use the tool again with a specific file parameter to fetch the content of any file.*`, type: "text", }, ], }; } if (args.file) { // 特定のファイルを取得(ファイル名またはパスで検索) const targetFile = cwtFiles.find( (file) => file.name === args.file || file.path === args.file || `${file.path}` === args.file, ); if (!targetFile) { throw new Error( `File "${args.file}" not found. Available files: ${cwtFiles.map((f) => f.path || f.name).join(", ")}`, ); } const fileContent = await getFileContent( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${targetFile.path}`, ref, ); return { content: [ { text: `# ${targetFile.path || args.file} ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **File Size**: ${targetFile.size} bytes ## Content \`\`\`cwt ${fileContent} \`\`\` --- *This is a CWTools config file (.cwt) that defines validation rules for Stellaris modding.*`, type: "text", }, ], }; } // 全ファイルを取得(最大10ファイルまで) const filesToFetch = cwtFiles.slice(0, 10); const fileContents: Array<{ content: string; name: string; size: number; }> = []; for (const file of filesToFetch) { let retryCount = 0; const maxFileRetries = 2; while (retryCount <= maxFileRetries) { try { log.debug( `Fetching file: ${file.path || file.name} (attempt ${retryCount + 1})`, ); const content = await getFileContent( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${file.path}`, ref, ); fileContents.push({ content, name: file.path || file.name, size: file.size, }); log.debug( `Successfully fetched ${file.path || file.name} (${content.length} characters)`, ); break; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (retryCount < maxFileRetries) { const delay = 1000 * (retryCount + 1); log.warn( `Failed to fetch ${file.path || file.name} (attempt ${retryCount + 1}), retrying in ${delay}ms`, { error: errorMessage, }, ); await new Promise((resolve) => setTimeout(resolve, delay)); retryCount++; } else { log.error( `Failed to fetch ${file.path || file.name} after ${maxFileRetries + 1} attempts`, { error: errorMessage, }, ); break; } } } // API制限を考慮して少し待機 await new Promise((resolve) => setTimeout(resolve, 150)); } const totalFiles = cwtFiles.length; const fetchedFiles = fileContents.length; return { content: [ { text: `# CWTools Stellaris Config Files (${args.version}) ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **Total files**: ${totalFiles} (showing first ${fetchedFiles}) ${fileContents .map( (file) => `## ${file.name} (${file.size} bytes) \`\`\`cwt ${file.content} \`\`\` ---`, ) .join("\n\n")} ${totalFiles > 10 ? `\n*Note: Only showing first 10 files. Use the 'file' parameter to fetch specific files, or 'listOnly' to see all available files.*` : ""} --- *These are CWTools config files (.cwt) that define validation rules for Stellaris modding.*`, type: "text", }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log.error("Failed to fetch CWTools config", { error: errorMessage }); throw new Error(`CWToolsコンフィグの取得に失敗しました: ${errorMessage}`); } },
  • Zod schema defining input parameters for the tool: file (optional string), listOnly (boolean default false), version (enum stable/latest default stable).
    parameters: z.object({ file: z .string() .optional() .describe( "取得する特定の.cwtファイル名またはパス (例: common.cwt, common/agreements.cwt)", ), listOnly: z .boolean() .default(false) .describe("ファイル一覧のみを表示する場合はtrue"), version: z .enum(["stable", "latest"]) .default("stable") .describe("取得するバージョン: stable (最新タグ) または latest (開発版)"), }),
  • src/server.ts:438-761 (registration)
    Registers the 'cwtools-config' tool with the FastMCP server instance, including annotations, description, handler, name, and parameters schema.
    server.addTool({ annotations: { openWorldHint: true, // GitHub APIにアクセスする readOnlyHint: true, // データを変更しない title: "CWTools Stellaris Config", }, description: "CWToolsのStellarisコンフィグルール(.cwt files)を取得します。最新の安定版または開発版から、config/直下およびサブディレクトリ(common/等)内の特定のファイルまたは全ファイルを取得できます。", execute: async (args, { log }) => { try { log.info("Fetching CWTools Stellaris config...", { file: args.file, listOnly: args.listOnly, version: args.version, }); // 参照するブランチ/タグを決定 let ref: string | undefined; if (args.version === "stable") { ref = await getLatestTag(CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME); log.info(`Using stable version: ${ref}`); } else { log.info("Using latest development version (main branch)"); } // configディレクトリの内容を取得 const configContents = await getDirectoryContents( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, "config", ref, ); // .cwtファイルのみをフィルタ(ルートレベル) const rootCwtFiles = configContents.filter( (item) => item.type === "file" && item.name.endsWith(".cwt"), ); // サブディレクトリからも.cwtファイルを取得 const subdirectories = configContents.filter( (item) => item.type === "dir", ); const nestedCwtFiles: Array<{ download_url: string; name: string; path: string; size: number; }> = []; for (const subdir of subdirectories) { let retryCount = 0; const maxSubdirRetries = 2; while (retryCount <= maxSubdirRetries) { try { log.debug( `Reading subdirectory: ${subdir.name} (attempt ${retryCount + 1})`, ); const subdirContents = await getDirectoryContents( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${subdir.name}`, ref, ); const subdirCwtFiles = subdirContents .filter( (item) => item.type === "file" && item.name.endsWith(".cwt"), ) .map((file) => ({ download_url: file.download_url, name: file.name, path: `${subdir.name}/${file.name}`, size: file.size, })); nestedCwtFiles.push(...subdirCwtFiles); log.info( `Successfully read ${subdirCwtFiles.length} .cwt files from ${subdir.name}/`, ); // 成功したらループを抜ける break; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (retryCount < maxSubdirRetries) { const delay = 1000 * (retryCount + 1); // 1秒、2秒、3秒 log.warn( `Failed to read subdirectory ${subdir.name} (attempt ${retryCount + 1}), retrying in ${delay}ms`, { error: errorMessage, }, ); await new Promise((resolve) => setTimeout(resolve, delay)); retryCount++; } else { log.error( `Failed to read subdirectory ${subdir.name} after ${maxSubdirRetries + 1} attempts`, { error: errorMessage, }, ); break; } } } // API制限を考慮して少し待機 await new Promise((resolve) => setTimeout(resolve, 200)); } // 全ての.cwtファイルを統合 const allCwtFiles = [ ...rootCwtFiles.map((file) => ({ download_url: file.download_url, name: file.name, path: file.name, size: file.size, })), ...nestedCwtFiles, ]; // 後続の処理で使用するため、cwtFilesをallCwtFilesに置き換え const cwtFiles = allCwtFiles; if (args.listOnly) { // ファイル一覧のみを返す const fileList = cwtFiles.map((file) => ({ downloadUrl: file.download_url, name: file.name, path: file.path, size: file.size, })); return { content: [ { text: `# CWTools Stellaris Config Files (${args.version}) ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **Total .cwt files**: ${fileList.length} ## Available Config Files ${fileList.map((file) => `- **${file.path || file.name}** (${file.size} bytes)`).join("\n")} --- *Use the tool again with a specific file parameter to fetch the content of any file.*`, type: "text", }, ], }; } if (args.file) { // 特定のファイルを取得(ファイル名またはパスで検索) const targetFile = cwtFiles.find( (file) => file.name === args.file || file.path === args.file || `${file.path}` === args.file, ); if (!targetFile) { throw new Error( `File "${args.file}" not found. Available files: ${cwtFiles.map((f) => f.path || f.name).join(", ")}`, ); } const fileContent = await getFileContent( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${targetFile.path}`, ref, ); return { content: [ { text: `# ${targetFile.path || args.file} ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **File Size**: ${targetFile.size} bytes ## Content \`\`\`cwt ${fileContent} \`\`\` --- *This is a CWTools config file (.cwt) that defines validation rules for Stellaris modding.*`, type: "text", }, ], }; } // 全ファイルを取得(最大10ファイルまで) const filesToFetch = cwtFiles.slice(0, 10); const fileContents: Array<{ content: string; name: string; size: number; }> = []; for (const file of filesToFetch) { let retryCount = 0; const maxFileRetries = 2; while (retryCount <= maxFileRetries) { try { log.debug( `Fetching file: ${file.path || file.name} (attempt ${retryCount + 1})`, ); const content = await getFileContent( CWTOOLS_REPO_OWNER, CWTOOLS_REPO_NAME, `config/${file.path}`, ref, ); fileContents.push({ content, name: file.path || file.name, size: file.size, }); log.debug( `Successfully fetched ${file.path || file.name} (${content.length} characters)`, ); break; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); if (retryCount < maxFileRetries) { const delay = 1000 * (retryCount + 1); log.warn( `Failed to fetch ${file.path || file.name} (attempt ${retryCount + 1}), retrying in ${delay}ms`, { error: errorMessage, }, ); await new Promise((resolve) => setTimeout(resolve, delay)); retryCount++; } else { log.error( `Failed to fetch ${file.path || file.name} after ${maxFileRetries + 1} attempts`, { error: errorMessage, }, ); break; } } } // API制限を考慮して少し待機 await new Promise((resolve) => setTimeout(resolve, 150)); } const totalFiles = cwtFiles.length; const fetchedFiles = fileContents.length; return { content: [ { text: `# CWTools Stellaris Config Files (${args.version}) ${ref ? `**Version**: ${ref}` : "**Version**: Latest development"} **Repository**: ${CWTOOLS_REPO_OWNER}/${CWTOOLS_REPO_NAME} **Total files**: ${totalFiles} (showing first ${fetchedFiles}) ${fileContents .map( (file) => `## ${file.name} (${file.size} bytes) \`\`\`cwt ${file.content} \`\`\` ---`, ) .join("\n\n")} ${totalFiles > 10 ? `\n*Note: Only showing first 10 files. Use the 'file' parameter to fetch specific files, or 'listOnly' to see all available files.*` : ""} --- *These are CWTools config files (.cwt) that define validation rules for Stellaris modding.*`, type: "text", }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); log.error("Failed to fetch CWTools config", { error: errorMessage }); throw new Error(`CWToolsコンフィグの取得に失敗しました: ${errorMessage}`); } }, name: "cwtools-config", parameters: z.object({ file: z .string() .optional() .describe( "取得する特定の.cwtファイル名またはパス (例: common.cwt, common/agreements.cwt)", ), listOnly: z .boolean() .default(false) .describe("ファイル一覧のみを表示する場合はtrue"), version: z .enum(["stable", "latest"]) .default("stable") .describe("取得するバージョン: stable (最新タグ) または latest (開発版)"), }), });
  • Helper function to retrieve directory contents from GitHub API, crucial for listing config files and subdirectories in cwtools-config.
    async function getDirectoryContents( owner: string, repo: string, path: string, ref?: string, ): Promise< Array<{ download_url: string; name: string; size: number; type: string; }> > { const url = new URL( `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${path}`, ); if (ref) { url.searchParams.set("ref", ref); } const response = await fetchWithRetry(url.toString()); if (!response.ok) { throw new Error( `Failed to fetch directory contents: ${response.status} ${response.statusText}`, ); } const contents = (await response.json()) as Array<{ download_url: string; name: string; size: number; type: string; }>; if (!Array.isArray(contents)) { throw new Error("Expected directory contents to be an array"); } return contents; }
  • Helper function to fetch raw file content from GitHub API (handles base64 decoding), used to retrieve .cwt file contents.
    async function getFileContent( owner: string, repo: string, path: string, ref?: string, ): Promise<string> { const url = new URL( `${GITHUB_API_BASE}/repos/${owner}/${repo}/contents/${path}`, ); if (ref) { url.searchParams.set("ref", ref); } const response = await fetchWithRetry(url.toString()); if (!response.ok) { throw new Error( `Failed to fetch file content: ${response.status} ${response.statusText}`, ); } const fileData = (await response.json()) as { content: string; encoding: string; }; if (fileData.encoding === "base64") { return Buffer.from(fileData.content, "base64").toString("utf-8"); } return fileData.content; }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kongyo2/Stellaris-Modding-MCP-Server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server