@intlayer/mcp 8.12.5-canary.0 → 9.0.0-canary.1
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/dist/esm/client/client.mjs +1 -1
- package/dist/esm/server/server.mjs +4 -4
- package/dist/esm/tools/cli.mjs +27 -1
- package/dist/esm/tools/cli.mjs.map +1 -1
- package/dist/esm/tools/docs.mjs +37 -0
- package/dist/esm/tools/docs.mjs.map +1 -1
- package/dist/esm/tools/index.mjs +3 -3
- package/dist/esm/tools/installLSP.mjs +1 -1
- package/dist/esm/tools/installSkills.mjs +2 -2
- package/dist/types/tools/cli.d.ts.map +1 -1
- package/dist/types/tools/docs.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { createMCPClient } from "@ai-sdk/mcp";
|
|
1
2
|
import { dirname as dirname$1 } from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import { isESModule } from "@intlayer/config/utils";
|
|
4
|
-
import { createMCPClient } from "@ai-sdk/mcp";
|
|
5
5
|
|
|
6
6
|
//#region src/client/client.ts
|
|
7
7
|
const dirname = isESModule ? dirname$1(fileURLToPath(import.meta.url)) : __dirname;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { loadAPITools } from "../tools/api.mjs";
|
|
2
|
-
import { loadCLITools } from "../tools/cli.mjs";
|
|
3
|
-
import { loadDocsTools } from "../tools/docs.mjs";
|
|
4
1
|
import { loadInstallLSPTool } from "../tools/installLSP.mjs";
|
|
2
|
+
import { loadCLITools } from "../tools/cli.mjs";
|
|
3
|
+
import { loadAPITools } from "../tools/api.mjs";
|
|
5
4
|
import { loadInstallSkillsTool } from "../tools/installSkills.mjs";
|
|
6
|
-
import {
|
|
5
|
+
import { loadDocsTools } from "../tools/docs.mjs";
|
|
7
6
|
import { dirname as dirname$1, resolve } from "node:path";
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
8
|
import { isESModule } from "@intlayer/config/utils";
|
|
10
9
|
import z from "zod";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
11
|
|
|
12
12
|
//#region src/server/server.ts
|
|
13
13
|
const dirname = isESModule ? dirname$1(fileURLToPath(import.meta.url)) : __dirname;
|
package/dist/esm/tools/cli.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { relative } from "node:path";
|
|
2
|
-
import z from "zod";
|
|
3
2
|
import { listProjects } from "@intlayer/chokidar/cli";
|
|
3
|
+
import z from "zod";
|
|
4
|
+
import { scanWebsite } from "@intlayer/chokidar/scan";
|
|
4
5
|
import { build, extract, fill, init, listContentDeclarationRows, listMissingTranslations, pull, push } from "@intlayer/cli";
|
|
5
6
|
import { ALL_LOCALES } from "@intlayer/types/allLocales";
|
|
6
7
|
|
|
@@ -275,6 +276,31 @@ const loadCLITools = async (server) => {
|
|
|
275
276
|
}] };
|
|
276
277
|
}
|
|
277
278
|
});
|
|
279
|
+
server.registerTool("intlayer-scan", {
|
|
280
|
+
title: "Scan Website",
|
|
281
|
+
description: "Scan a website to measure its page size and audit its i18n / SEO health (html lang/dir, canonical, hreflang, x-default, localized internal links, robots.txt, sitemap.xml, and unused bundle locale content). Returns a 0-100 score and per-check results.",
|
|
282
|
+
inputSchema: {
|
|
283
|
+
url: z.string().describe("Absolute URL of the website to scan"),
|
|
284
|
+
deep: z.boolean().optional().describe("Attempt a deeper render-based scan using a locally installed puppeteer. Falls back to a basic fetch scan when puppeteer is not installed.")
|
|
285
|
+
},
|
|
286
|
+
annotations: {
|
|
287
|
+
readOnlyHint: true,
|
|
288
|
+
openWorldHint: true
|
|
289
|
+
}
|
|
290
|
+
}, async ({ url, deep }) => {
|
|
291
|
+
try {
|
|
292
|
+
const result = await scanWebsite(url, { deep });
|
|
293
|
+
return { content: [{
|
|
294
|
+
type: "text",
|
|
295
|
+
text: JSON.stringify(result, null, 2)
|
|
296
|
+
}] };
|
|
297
|
+
} catch (error) {
|
|
298
|
+
return { content: [{
|
|
299
|
+
type: "text",
|
|
300
|
+
text: `Scan failed: ${error instanceof Error ? error.message : "An unknown error occurred"}`
|
|
301
|
+
}] };
|
|
302
|
+
}
|
|
303
|
+
});
|
|
278
304
|
server.registerTool("intlayer-projects-list", {
|
|
279
305
|
title: "List Projects",
|
|
280
306
|
description: "List all Intlayer projects in the directory. Search for configuration files to find all Intlayer projects.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../../../src/tools/cli.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport { listProjects } from '@intlayer/chokidar/cli';\nimport {\n build,\n extract,\n fill,\n init,\n listContentDeclarationRows,\n listMissingTranslations,\n pull,\n push,\n} from '@intlayer/cli';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport z from 'zod';\nimport type { McpServer } from './docs';\n\nconst configOptionsSchema = z\n .object({\n baseDir: z.string().optional().describe('Base directory for the project'),\n env: z.string().optional().describe('Environment name'),\n envFile: z.string().optional().describe('Path to the environment file'),\n override: z\n .object({\n editor: z\n .object({\n clientId: z.string().optional().describe('Intlayer CMS client ID'),\n clientSecret: z\n .string()\n .optional()\n .describe('Intlayer CMS client secret'),\n backendURL: z\n .string()\n .optional()\n .describe('Intlayer CMS backend URL'),\n })\n .optional(),\n internationalization: z\n .object({\n locales: z\n .array(z.nativeEnum(ALL_LOCALES))\n .optional()\n .describe('Available locales'),\n defaultLocale: z\n .nativeEnum(ALL_LOCALES)\n .optional()\n .describe('Default locale'),\n })\n .optional(),\n log: z\n .object({\n mode: z\n .enum(['default', 'verbose', 'disabled'])\n .optional()\n .describe('Log mode'),\n prefix: z.string().optional().describe('Log prefix'),\n })\n .optional(),\n })\n .optional()\n .describe(\n 'Config override - use when running remotely or without a local config file'\n ),\n })\n .optional()\n .describe(\n 'Configuration options. Required when running remotely or when no intlayer config file is present'\n );\n\ntype LoadCLITools = (server: McpServer) => Promise<void>;\n\nexport const loadCLITools: LoadCLITools = async (server) => {\n server.registerTool(\n 'intlayer-init',\n {\n title: 'Initialize Intlayer',\n description: 'Initialize Intlayer in the project',\n inputSchema: {\n projectRoot: z.string().describe('Project root directory'),\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async ({ projectRoot }) => {\n try {\n await init(projectRoot);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Initialization successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Initialization failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-build',\n {\n title: 'Build Dictionaries',\n description:\n 'Build the dictionaries. List all content declarations files `.content.{ts,tsx,js,json,...}` to update the content callable using the `useIntlayer` hook.',\n inputSchema: {\n watch: z.boolean().optional().describe('Watch for changes'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async ({ watch, configOptions }) => {\n try {\n await build({ watch, configOptions });\n\n return {\n content: [\n {\n type: 'text',\n text: 'Build successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Build failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-fill',\n {\n title: 'Fill Translations',\n description:\n 'Fill the dictionaries with missing translations / review translations using Intlayer servers',\n inputSchema: {\n sourceLocale: z\n .nativeEnum(ALL_LOCALES)\n .optional()\n .describe('Source locale'),\n outputLocales: z\n .union([\n z.nativeEnum(ALL_LOCALES),\n z.array(z.nativeEnum(ALL_LOCALES)),\n ])\n .optional()\n .describe('Output locales'),\n file: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('File path'),\n mode: z.enum(['complete', 'review']).optional().describe('Fill mode'),\n keys: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Keys to include'),\n excludedKeys: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Keys to exclude'),\n pathFilter: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Path filter'),\n gitOptions: z\n .object({\n gitDiff: z.boolean().optional(),\n gitDiffBase: z.string().optional(),\n gitDiffCurrent: z.string().optional(),\n uncommitted: z.boolean().optional(),\n unpushed: z.boolean().optional(),\n untracked: z.boolean().optional(),\n })\n .optional()\n .describe('Git options'),\n aiOptions: z\n .object({\n provider: z.string().optional(),\n temperature: z.number().optional(),\n model: z.string().optional(),\n apiKey: z.string().optional(),\n customPrompt: z.string().optional(),\n applicationContext: z.string().optional(),\n })\n .optional()\n .describe('AI options'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n const { gitOptions, ...rest } = props;\n const fillOptions: any = { ...rest, gitOptions: undefined };\n\n if (gitOptions) {\n const { gitDiff, uncommitted, unpushed, untracked, ...restGit } =\n gitOptions;\n const mode = [];\n if (gitDiff) mode.push('gitDiff');\n if (uncommitted) mode.push('uncommitted');\n if (unpushed) mode.push('unpushed');\n if (untracked) mode.push('untracked');\n\n fillOptions.gitOptions = { ...restGit, mode };\n }\n\n await fill(fillOptions);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Fill successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Fill failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-push',\n {\n title: 'Push Dictionaries',\n description: 'Push local dictionaries to the server',\n inputSchema: {\n deleteLocaleDictionary: z\n .boolean()\n .optional()\n .describe('Delete local dictionary after push'),\n keepLocaleDictionary: z\n .boolean()\n .optional()\n .describe('Keep local dictionary after push'),\n dictionaries: z\n .array(z.string())\n .optional()\n .describe('List of dictionaries to push'),\n gitOptions: z\n .object({\n gitDiff: z.boolean().optional(),\n gitDiffBase: z.string().optional(),\n gitDiffCurrent: z.string().optional(),\n uncommitted: z.boolean().optional(),\n unpushed: z.boolean().optional(),\n untracked: z.boolean().optional(),\n })\n .optional()\n .describe('Git options'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n const { gitOptions, ...rest } = props;\n const pushOptions: any = { ...rest, gitOptions: undefined };\n\n if (gitOptions) {\n const { gitDiff, uncommitted, unpushed, untracked, ...restGit } =\n gitOptions;\n const mode = [];\n if (gitDiff) mode.push('gitDiff');\n if (uncommitted) mode.push('uncommitted');\n if (unpushed) mode.push('unpushed');\n if (untracked) mode.push('untracked');\n\n pushOptions.gitOptions = { ...restGit, mode };\n }\n\n await push(pushOptions);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Push successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Push failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-pull',\n {\n title: 'Pull Dictionaries',\n description: 'Pull dictionaries from the CMS',\n inputSchema: {\n dictionaries: z\n .array(z.string())\n .optional()\n .describe('List of dictionaries to pull'),\n newDictionariesPath: z\n .string()\n .optional()\n .describe('Path to save new dictionaries'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n await pull(props);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Pull successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Pull failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-content-list',\n {\n title: 'List Content Declarations',\n description:\n 'List the content declaration (.content.{ts,tsx,js,json,...}) files present in the project. That files contain the multilingual content of the application and are used to build the dictionaries.',\n inputSchema: {\n configOptions: configOptionsSchema,\n absolute: z\n .boolean()\n .optional()\n .describe(\n 'Output the results as absolute paths instead of relative paths'\n ),\n json: z\n .boolean()\n .optional()\n .describe('Output the results as JSON instead of formatted text'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const rows = listContentDeclarationRows(props);\n return {\n content: [\n {\n type: 'text',\n text: props.json\n ? JSON.stringify(rows)\n : JSON.stringify(rows, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Content list failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-content-test',\n {\n title: 'Test Translations',\n description:\n 'Test if there are missing translations in the content declaration files. That files contain the multilingual content of the application and are used to build the dictionaries.',\n inputSchema: {\n configOptions: configOptionsSchema,\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const missingTranslations = listMissingTranslations(\n props?.configOptions\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(missingTranslations, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Content test failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-extract',\n {\n title: 'Extract strings from Component',\n description:\n 'Extract strings from an existing component to be placed in a .content file close to the component. Trigger this action to make an existing component multilingual. If the component does not exist, create a normal component including text in JSX, and then trigger this tool to extract it.',\n inputSchema: {\n file: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('List of files to extract'),\n outputContentDeclarations: z\n .string()\n .optional()\n .describe('Path to output content declaration files'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n await extract({\n files: Array.isArray(props.file)\n ? props.file\n : props.file\n ? [props.file]\n : undefined,\n configOptions: props.configOptions,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: 'Extract successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Extract failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-projects-list',\n {\n title: 'List Projects',\n description:\n 'List all Intlayer projects in the directory. Search for configuration files to find all Intlayer projects.',\n inputSchema: {\n baseDir: z\n .string()\n .optional()\n .describe('Base directory to search from'),\n gitRoot: z\n .boolean()\n .optional()\n .describe(\n 'Search from the git root directory instead of the base directory'\n ),\n absolute: z\n .boolean()\n .optional()\n .describe(\n 'Output the results as absolute paths instead of relative paths'\n ),\n json: z\n .boolean()\n .optional()\n .describe('Output the results as JSON instead of formatted text'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const { searchDir, projectsPath } = await listProjects({\n baseDir: props.baseDir,\n gitRoot: props.gitRoot,\n });\n\n const projectsRelativePath = projectsPath\n .map((projectPath) =>\n props.absolute ? projectPath : relative(searchDir, projectPath)\n )\n .map((projectPath) => (projectPath === '' ? '.' : projectPath));\n\n const outputPaths = props.absolute\n ? projectsPath\n : projectsRelativePath;\n\n return {\n content: [\n {\n type: 'text',\n text: props.json\n ? JSON.stringify(outputPaths)\n : JSON.stringify(\n { searchDir, projectsPath: outputPaths },\n null,\n 2\n ),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Projects list failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../../../src/tools/cli.ts"],"sourcesContent":["import { relative } from 'node:path';\nimport { listProjects } from '@intlayer/chokidar/cli';\nimport { scanWebsite } from '@intlayer/chokidar/scan';\nimport {\n build,\n extract,\n fill,\n init,\n listContentDeclarationRows,\n listMissingTranslations,\n pull,\n push,\n} from '@intlayer/cli';\nimport { ALL_LOCALES } from '@intlayer/types/allLocales';\nimport z from 'zod';\nimport type { McpServer } from './docs';\n\nconst configOptionsSchema = z\n .object({\n baseDir: z.string().optional().describe('Base directory for the project'),\n env: z.string().optional().describe('Environment name'),\n envFile: z.string().optional().describe('Path to the environment file'),\n override: z\n .object({\n editor: z\n .object({\n clientId: z.string().optional().describe('Intlayer CMS client ID'),\n clientSecret: z\n .string()\n .optional()\n .describe('Intlayer CMS client secret'),\n backendURL: z\n .string()\n .optional()\n .describe('Intlayer CMS backend URL'),\n })\n .optional(),\n internationalization: z\n .object({\n locales: z\n .array(z.nativeEnum(ALL_LOCALES))\n .optional()\n .describe('Available locales'),\n defaultLocale: z\n .nativeEnum(ALL_LOCALES)\n .optional()\n .describe('Default locale'),\n })\n .optional(),\n log: z\n .object({\n mode: z\n .enum(['default', 'verbose', 'disabled'])\n .optional()\n .describe('Log mode'),\n prefix: z.string().optional().describe('Log prefix'),\n })\n .optional(),\n })\n .optional()\n .describe(\n 'Config override - use when running remotely or without a local config file'\n ),\n })\n .optional()\n .describe(\n 'Configuration options. Required when running remotely or when no intlayer config file is present'\n );\n\ntype LoadCLITools = (server: McpServer) => Promise<void>;\n\nexport const loadCLITools: LoadCLITools = async (server) => {\n server.registerTool(\n 'intlayer-init',\n {\n title: 'Initialize Intlayer',\n description: 'Initialize Intlayer in the project',\n inputSchema: {\n projectRoot: z.string().describe('Project root directory'),\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async ({ projectRoot }) => {\n try {\n await init(projectRoot);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Initialization successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Initialization failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-build',\n {\n title: 'Build Dictionaries',\n description:\n 'Build the dictionaries. List all content declarations files `.content.{ts,tsx,js,json,...}` to update the content callable using the `useIntlayer` hook.',\n inputSchema: {\n watch: z.boolean().optional().describe('Watch for changes'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async ({ watch, configOptions }) => {\n try {\n await build({ watch, configOptions });\n\n return {\n content: [\n {\n type: 'text',\n text: 'Build successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Build failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-fill',\n {\n title: 'Fill Translations',\n description:\n 'Fill the dictionaries with missing translations / review translations using Intlayer servers',\n inputSchema: {\n sourceLocale: z\n .nativeEnum(ALL_LOCALES)\n .optional()\n .describe('Source locale'),\n outputLocales: z\n .union([\n z.nativeEnum(ALL_LOCALES),\n z.array(z.nativeEnum(ALL_LOCALES)),\n ])\n .optional()\n .describe('Output locales'),\n file: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('File path'),\n mode: z.enum(['complete', 'review']).optional().describe('Fill mode'),\n keys: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Keys to include'),\n excludedKeys: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Keys to exclude'),\n pathFilter: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Path filter'),\n gitOptions: z\n .object({\n gitDiff: z.boolean().optional(),\n gitDiffBase: z.string().optional(),\n gitDiffCurrent: z.string().optional(),\n uncommitted: z.boolean().optional(),\n unpushed: z.boolean().optional(),\n untracked: z.boolean().optional(),\n })\n .optional()\n .describe('Git options'),\n aiOptions: z\n .object({\n provider: z.string().optional(),\n temperature: z.number().optional(),\n model: z.string().optional(),\n apiKey: z.string().optional(),\n customPrompt: z.string().optional(),\n applicationContext: z.string().optional(),\n })\n .optional()\n .describe('AI options'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n const { gitOptions, ...rest } = props;\n const fillOptions: any = { ...rest, gitOptions: undefined };\n\n if (gitOptions) {\n const { gitDiff, uncommitted, unpushed, untracked, ...restGit } =\n gitOptions;\n const mode = [];\n if (gitDiff) mode.push('gitDiff');\n if (uncommitted) mode.push('uncommitted');\n if (unpushed) mode.push('unpushed');\n if (untracked) mode.push('untracked');\n\n fillOptions.gitOptions = { ...restGit, mode };\n }\n\n await fill(fillOptions);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Fill successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Fill failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-push',\n {\n title: 'Push Dictionaries',\n description: 'Push local dictionaries to the server',\n inputSchema: {\n deleteLocaleDictionary: z\n .boolean()\n .optional()\n .describe('Delete local dictionary after push'),\n keepLocaleDictionary: z\n .boolean()\n .optional()\n .describe('Keep local dictionary after push'),\n dictionaries: z\n .array(z.string())\n .optional()\n .describe('List of dictionaries to push'),\n gitOptions: z\n .object({\n gitDiff: z.boolean().optional(),\n gitDiffBase: z.string().optional(),\n gitDiffCurrent: z.string().optional(),\n uncommitted: z.boolean().optional(),\n unpushed: z.boolean().optional(),\n untracked: z.boolean().optional(),\n })\n .optional()\n .describe('Git options'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n const { gitOptions, ...rest } = props;\n const pushOptions: any = { ...rest, gitOptions: undefined };\n\n if (gitOptions) {\n const { gitDiff, uncommitted, unpushed, untracked, ...restGit } =\n gitOptions;\n const mode = [];\n if (gitDiff) mode.push('gitDiff');\n if (uncommitted) mode.push('uncommitted');\n if (unpushed) mode.push('unpushed');\n if (untracked) mode.push('untracked');\n\n pushOptions.gitOptions = { ...restGit, mode };\n }\n\n await push(pushOptions);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Push successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Push failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-pull',\n {\n title: 'Pull Dictionaries',\n description: 'Pull dictionaries from the CMS',\n inputSchema: {\n dictionaries: z\n .array(z.string())\n .optional()\n .describe('List of dictionaries to pull'),\n newDictionariesPath: z\n .string()\n .optional()\n .describe('Path to save new dictionaries'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n await pull(props);\n\n return {\n content: [\n {\n type: 'text',\n text: 'Pull successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Pull failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-content-list',\n {\n title: 'List Content Declarations',\n description:\n 'List the content declaration (.content.{ts,tsx,js,json,...}) files present in the project. That files contain the multilingual content of the application and are used to build the dictionaries.',\n inputSchema: {\n configOptions: configOptionsSchema,\n absolute: z\n .boolean()\n .optional()\n .describe(\n 'Output the results as absolute paths instead of relative paths'\n ),\n json: z\n .boolean()\n .optional()\n .describe('Output the results as JSON instead of formatted text'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const rows = listContentDeclarationRows(props);\n return {\n content: [\n {\n type: 'text',\n text: props.json\n ? JSON.stringify(rows)\n : JSON.stringify(rows, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Content list failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-content-test',\n {\n title: 'Test Translations',\n description:\n 'Test if there are missing translations in the content declaration files. That files contain the multilingual content of the application and are used to build the dictionaries.',\n inputSchema: {\n configOptions: configOptionsSchema,\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const missingTranslations = listMissingTranslations(\n props?.configOptions\n );\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(missingTranslations, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Content test failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-extract',\n {\n title: 'Extract strings from Component',\n description:\n 'Extract strings from an existing component to be placed in a .content file close to the component. Trigger this action to make an existing component multilingual. If the component does not exist, create a normal component including text in JSX, and then trigger this tool to extract it.',\n inputSchema: {\n file: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('List of files to extract'),\n outputContentDeclarations: z\n .string()\n .optional()\n .describe('Path to output content declaration files'),\n configOptions: configOptionsSchema,\n },\n annotations: {\n destructiveHint: true,\n },\n },\n async (props) => {\n try {\n await extract({\n files: Array.isArray(props.file)\n ? props.file\n : props.file\n ? [props.file]\n : undefined,\n configOptions: props.configOptions,\n });\n\n return {\n content: [\n {\n type: 'text',\n text: 'Extract successful.',\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Extract failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-scan',\n {\n title: 'Scan Website',\n description:\n 'Scan a website to measure its page size and audit its i18n / SEO health (html lang/dir, canonical, hreflang, x-default, localized internal links, robots.txt, sitemap.xml, and unused bundle locale content). Returns a 0-100 score and per-check results.',\n inputSchema: {\n url: z.string().describe('Absolute URL of the website to scan'),\n deep: z\n .boolean()\n .optional()\n .describe(\n 'Attempt a deeper render-based scan using a locally installed puppeteer. Falls back to a basic fetch scan when puppeteer is not installed.'\n ),\n },\n annotations: {\n readOnlyHint: true,\n openWorldHint: true,\n },\n },\n async ({ url, deep }) => {\n try {\n const result = await scanWebsite(url, { deep });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Scan failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'intlayer-projects-list',\n {\n title: 'List Projects',\n description:\n 'List all Intlayer projects in the directory. Search for configuration files to find all Intlayer projects.',\n inputSchema: {\n baseDir: z\n .string()\n .optional()\n .describe('Base directory to search from'),\n gitRoot: z\n .boolean()\n .optional()\n .describe(\n 'Search from the git root directory instead of the base directory'\n ),\n absolute: z\n .boolean()\n .optional()\n .describe(\n 'Output the results as absolute paths instead of relative paths'\n ),\n json: z\n .boolean()\n .optional()\n .describe('Output the results as JSON instead of formatted text'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async (props) => {\n try {\n const { searchDir, projectsPath } = await listProjects({\n baseDir: props.baseDir,\n gitRoot: props.gitRoot,\n });\n\n const projectsRelativePath = projectsPath\n .map((projectPath) =>\n props.absolute ? projectPath : relative(searchDir, projectPath)\n )\n .map((projectPath) => (projectPath === '' ? '.' : projectPath));\n\n const outputPaths = props.absolute\n ? projectsPath\n : projectsRelativePath;\n\n return {\n content: [\n {\n type: 'text',\n text: props.json\n ? JSON.stringify(outputPaths)\n : JSON.stringify(\n { searchDir, projectsPath: outputPaths },\n null,\n 2\n ),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n {\n type: 'text',\n text: `Projects list failed: ${errorMessage}`,\n },\n ],\n };\n }\n }\n );\n};\n"],"mappings":"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"}
|
package/dist/esm/tools/docs.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
2
|
import { getSearchAPI } from "@intlayer/api";
|
|
3
|
+
import { buildReviewReport, formatReviewReport } from "@intlayer/chokidar/docReview";
|
|
3
4
|
import { getDoc, getDocBySlug, getDocMetadataRecord, getDocsKeys } from "@intlayer/docs";
|
|
4
5
|
|
|
5
6
|
//#region src/tools/docs.ts
|
|
@@ -101,6 +102,42 @@ const loadDocsTools = async (server) => {
|
|
|
101
102
|
}] };
|
|
102
103
|
}
|
|
103
104
|
});
|
|
105
|
+
server.registerTool("review-doc-blocks", {
|
|
106
|
+
title: "Review Doc Blocks",
|
|
107
|
+
description: "Compare a base markdown document with its translation and return only the blocks that diverge (changed, missing, or stale), with their line ranges and content. Use this to translate a large document incrementally without retranslating it from scratch: it tells you exactly which blocks to (re)translate. Optionally pass the base line numbers that changed (for example from a git diff) so aligned-but-edited blocks are flagged for review.",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
baseContent: z.string().describe("The base (source) markdown document, used as reference"),
|
|
110
|
+
targetContent: z.string().describe("The existing translated markdown document (may be empty for a brand new translation)"),
|
|
111
|
+
changedLines: z.array(z.number()).optional().describe("1-based line numbers that changed in the base document. When omitted, only inserted and deleted blocks are reported."),
|
|
112
|
+
baseLabel: z.string().optional().describe("Label for the base locale in the formatted output"),
|
|
113
|
+
targetLabel: z.string().optional().describe("Label for the target locale in the formatted output"),
|
|
114
|
+
format: z.enum(["text", "json"]).optional().describe("Output format. Defaults to \"text\".")
|
|
115
|
+
},
|
|
116
|
+
annotations: { readOnlyHint: true }
|
|
117
|
+
}, async ({ baseContent, targetContent, changedLines, baseLabel, targetLabel, format }) => {
|
|
118
|
+
try {
|
|
119
|
+
const report = buildReviewReport({
|
|
120
|
+
baseText: baseContent,
|
|
121
|
+
targetText: targetContent,
|
|
122
|
+
changedLines
|
|
123
|
+
});
|
|
124
|
+
return { content: [{
|
|
125
|
+
type: "text",
|
|
126
|
+
text: format === "json" ? JSON.stringify(report, null, 2) : formatReviewReport(report, {
|
|
127
|
+
baseLabel,
|
|
128
|
+
targetLabel
|
|
129
|
+
})
|
|
130
|
+
}] };
|
|
131
|
+
} catch (error) {
|
|
132
|
+
return {
|
|
133
|
+
content: [{
|
|
134
|
+
type: "text",
|
|
135
|
+
text: `Review doc blocks failed: ${error instanceof Error ? error.message : "An unknown error occurred"}`
|
|
136
|
+
}],
|
|
137
|
+
isError: true
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
104
141
|
};
|
|
105
142
|
|
|
106
143
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.mjs","names":[],"sources":["../../../src/tools/docs.ts"],"sourcesContent":["import { getSearchAPI } from '@intlayer/api';\nimport type { DocKey } from '@intlayer/docs';\nimport {\n getDoc,\n getDocBySlug,\n getDocMetadataRecord,\n getDocsKeys,\n} from '@intlayer/docs';\nimport z from 'zod';\n\nexport type ToolResult = {\n content: { type: string; text: string }[];\n isError?: boolean;\n};\nexport type McpServer = {\n registerTool(\n name: string,\n config: any,\n handler: (params: any) => Promise<ToolResult>\n ): void;\n};\n\ntype LoadDocsTools = (server: McpServer) => Promise<void>;\n\nexport const loadDocsTools: LoadDocsTools = async (server) => {\n const docsKeys = getDocsKeys();\n\n server.registerTool(\n 'get-doc-list',\n {\n title: 'Get Doc List',\n description:\n 'Get the list of docs names and their metadata to get more details about what doc to retrieve',\n inputSchema: {},\n annotations: {\n readOnlyHint: true,\n },\n },\n async () => {\n try {\n const docsMetadataRecord = await getDocMetadataRecord();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(docsMetadataRecord, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Get doc list failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'get-doc',\n {\n title: 'Get Doc by Key',\n description:\n 'Get a doc by his key. Example: `./docs/en/getting-started.md`. List all docs metadata first to get more details about what doc key to retrieve.',\n inputSchema: {\n docKey: z.enum(docsKeys as [string, ...string[]]),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ docKey }) => {\n try {\n const doc = await getDoc(docKey as DocKey);\n return {\n content: [{ type: 'text', text: doc }],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [{ type: 'text', text: `Get doc failed: ${errorMessage}` }],\n };\n }\n }\n );\n\n server.registerTool(\n 'get-doc-by-slug',\n {\n title: 'Get Doc by Slug',\n description:\n 'Get an array of docs by their slugs. If not slug is provided, return all docs (1.2Mb). List all docs metadata first to get more details about what doc to retrieve.',\n inputSchema: {\n slug: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Slug of the docs. If not provided, return all docs. If not provided, return all docs.'\n ),\n strict: z\n .boolean()\n .optional()\n .describe(\n 'Strict mode - only return docs that match all slugs, by excluding additional slugs'\n ),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ slug, strict }) => {\n try {\n const doc = await getDocBySlug(slug ?? [], undefined, strict);\n return {\n content: doc.map((d) => ({ type: 'text', text: d })),\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Get doc by slug failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'fetch-doc-chunks',\n {\n title: 'Fetch Doc Chunks',\n description:\n 'Fetch related doc chunks using keywords or questions. This tool will return the most relevant chunks of documentation based on the input query.',\n inputSchema: {\n query: z.string().describe('The keywords or question to search for'),\n limit: z\n .number()\n .optional()\n .describe('The number of chunks to retrieve (default: 10)'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ query, limit }) => {\n try {\n const { searchDoc } = getSearchAPI(undefined);\n const response = await searchDoc({\n input: query,\n limit: limit?.toString(),\n returnContent: 'true',\n });\n\n if (!response.data || !Array.isArray(response.data)) {\n return {\n content: [{ type: 'text', text: 'No relevant chunks found.' }],\n };\n }\n\n const chunks = response.data;\n\n return {\n content: chunks.map((chunk: any) => ({\n type: 'text',\n text: [\n `File: ${chunk.fileKey}`,\n `Title: ${chunk.docName}`,\n `URL: ${chunk.docUrl}`,\n `Chunk: ${chunk.chunkNumber}`,\n `Content:`,\n chunk.content,\n ].join('\\n'),\n })),\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Fetch doc chunks failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n};\n"],"mappings":";;;;;AAwBA,MAAa,gBAA+B,OAAO,WAAW;CAC5D,MAAM,WAAW,aAAa;AAE9B,QAAO,aACL,gBACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EAAE;EACf,aAAa,EACX,cAAc,MACf;EACF,EACD,YAAY;AACV,MAAI;GACF,MAAM,qBAAqB,MAAM,sBAAsB;AAEvD,UAAO,EACL,SAAS,CACP;IACE,MAAM;IACN,MAAM,KAAK,UAAU,oBAAoB,MAAM,EAAE;IAClD,CACF,EACF;WACM,OAAO;AAGd,UAAO,EACL,SAAS,CACP;IAAE,MAAM;IAAQ,MAAM,wBAHxB,iBAAiB,QAAQ,MAAM,UAAU;IAGuB,CAC/D,EACF;;GAGN;AAED,QAAO,aACL,WACA;EACE,OAAO;EACP,aACE;EACF,aAAa,EACX,QAAQ,EAAE,KAAK,SAAkC,EAClD;EACD,aAAa,EACX,cAAc,MACf;EACF,EACD,OAAO,EAAE,aAAa;AACpB,MAAI;AAEF,UAAO,EACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,MAFhB,OAAO,OAAiB;IAEH,CAAC,EACvC;WACM,OAAO;AAGd,UAAO,EACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,mBAFhC,iBAAiB,QAAQ,MAAM,UAAU;IAE0B,CAAC,EACrE;;GAGN;AAED,QAAO,aACL,mBACA;EACE,OAAO;EACP,aACE;EACF,aAAa;GACX,MAAM,EACH,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CACxC,UAAU,CACV,SACC,wFACD;GACH,QAAQ,EACL,SAAS,CACT,UAAU,CACV,SACC,qFACD;GACJ;EACD,aAAa,EACX,cAAc,MACf;EACF,EACD,OAAO,EAAE,MAAM,aAAa;AAC1B,MAAI;AAEF,UAAO,EACL,UAAS,MAFO,aAAa,QAAQ,EAAE,EAAE,QAAW,OAAO,EAE9C,KAAK,OAAO;IAAE,MAAM;IAAQ,MAAM;IAAG,EAAE,EACrD;WACM,OAAO;AAGd,UAAO,EACL,SAAS,CACP;IAAE,MAAM;IAAQ,MAAM,2BAHxB,iBAAiB,QAAQ,MAAM,UAAU;IAG0B,CAClE,EACF;;GAGN;AAED,QAAO,aACL,oBACA;EACE,OAAO;EACP,aACE;EACF,aAAa;GACX,OAAO,EAAE,QAAQ,CAAC,SAAS,yCAAyC;GACpE,OAAO,EACJ,QAAQ,CACR,UAAU,CACV,SAAS,iDAAiD;GAC9D;EACD,aAAa,EACX,cAAc,MACf;EACF,EACD,OAAO,EAAE,OAAO,YAAY;AAC1B,MAAI;GACF,MAAM,EAAE,cAAc,aAAa,OAAU;GAC7C,MAAM,WAAW,MAAM,UAAU;IAC/B,OAAO;IACP,OAAO,OAAO,UAAU;IACxB,eAAe;IAChB,CAAC;AAEF,OAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,QAAQ,SAAS,KAAK,CACjD,QAAO,EACL,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM;IAA6B,CAAC,EAC/D;AAKH,UAAO,EACL,SAHa,SAAS,KAGN,KAAK,WAAgB;IACnC,MAAM;IACN,MAAM;KACJ,SAAS,MAAM;KACf,UAAU,MAAM;KAChB,QAAQ,MAAM;KACd,UAAU,MAAM;KAChB;KACA,MAAM;KACP,CAAC,KAAK,KAAK;IACb,EAAE,EACJ;WACM,OAAO;AAGd,UAAO,EACL,SAAS,CACP;IAAE,MAAM;IAAQ,MAAM,4BAHxB,iBAAiB,QAAQ,MAAM,UAAU;IAG2B,CACnE,EACF;;GAGN"}
|
|
1
|
+
{"version":3,"file":"docs.mjs","names":[],"sources":["../../../src/tools/docs.ts"],"sourcesContent":["import { getSearchAPI } from '@intlayer/api';\nimport {\n buildReviewReport,\n formatReviewReport,\n} from '@intlayer/chokidar/docReview';\nimport type { DocKey } from '@intlayer/docs';\nimport {\n getDoc,\n getDocBySlug,\n getDocMetadataRecord,\n getDocsKeys,\n} from '@intlayer/docs';\nimport z from 'zod';\n\nexport type ToolResult = {\n content: { type: string; text: string }[];\n isError?: boolean;\n};\nexport type McpServer = {\n registerTool(\n name: string,\n config: any,\n handler: (params: any) => Promise<ToolResult>\n ): void;\n};\n\ntype LoadDocsTools = (server: McpServer) => Promise<void>;\n\nexport const loadDocsTools: LoadDocsTools = async (server) => {\n const docsKeys = getDocsKeys();\n\n server.registerTool(\n 'get-doc-list',\n {\n title: 'Get Doc List',\n description:\n 'Get the list of docs names and their metadata to get more details about what doc to retrieve',\n inputSchema: {},\n annotations: {\n readOnlyHint: true,\n },\n },\n async () => {\n try {\n const docsMetadataRecord = await getDocMetadataRecord();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(docsMetadataRecord, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Get doc list failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'get-doc',\n {\n title: 'Get Doc by Key',\n description:\n 'Get a doc by his key. Example: `./docs/en/getting-started.md`. List all docs metadata first to get more details about what doc key to retrieve.',\n inputSchema: {\n docKey: z.enum(docsKeys as [string, ...string[]]),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ docKey }) => {\n try {\n const doc = await getDoc(docKey as DocKey);\n return {\n content: [{ type: 'text', text: doc }],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [{ type: 'text', text: `Get doc failed: ${errorMessage}` }],\n };\n }\n }\n );\n\n server.registerTool(\n 'get-doc-by-slug',\n {\n title: 'Get Doc by Slug',\n description:\n 'Get an array of docs by their slugs. If not slug is provided, return all docs (1.2Mb). List all docs metadata first to get more details about what doc to retrieve.',\n inputSchema: {\n slug: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe(\n 'Slug of the docs. If not provided, return all docs. If not provided, return all docs.'\n ),\n strict: z\n .boolean()\n .optional()\n .describe(\n 'Strict mode - only return docs that match all slugs, by excluding additional slugs'\n ),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ slug, strict }) => {\n try {\n const doc = await getDocBySlug(slug ?? [], undefined, strict);\n return {\n content: doc.map((d) => ({ type: 'text', text: d })),\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Get doc by slug failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'fetch-doc-chunks',\n {\n title: 'Fetch Doc Chunks',\n description:\n 'Fetch related doc chunks using keywords or questions. This tool will return the most relevant chunks of documentation based on the input query.',\n inputSchema: {\n query: z.string().describe('The keywords or question to search for'),\n limit: z\n .number()\n .optional()\n .describe('The number of chunks to retrieve (default: 10)'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({ query, limit }) => {\n try {\n const { searchDoc } = getSearchAPI(undefined);\n const response = await searchDoc({\n input: query,\n limit: limit?.toString(),\n returnContent: 'true',\n });\n\n if (!response.data || !Array.isArray(response.data)) {\n return {\n content: [{ type: 'text', text: 'No relevant chunks found.' }],\n };\n }\n\n const chunks = response.data;\n\n return {\n content: chunks.map((chunk: any) => ({\n type: 'text',\n text: [\n `File: ${chunk.fileKey}`,\n `Title: ${chunk.docName}`,\n `URL: ${chunk.docUrl}`,\n `Chunk: ${chunk.chunkNumber}`,\n `Content:`,\n chunk.content,\n ].join('\\n'),\n })),\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Fetch doc chunks failed: ${errorMessage}` },\n ],\n };\n }\n }\n );\n\n server.registerTool(\n 'review-doc-blocks',\n {\n title: 'Review Doc Blocks',\n description:\n 'Compare a base markdown document with its translation and return only the blocks that diverge (changed, missing, or stale), with their line ranges and content. Use this to translate a large document incrementally without retranslating it from scratch: it tells you exactly which blocks to (re)translate. Optionally pass the base line numbers that changed (for example from a git diff) so aligned-but-edited blocks are flagged for review.',\n inputSchema: {\n baseContent: z\n .string()\n .describe('The base (source) markdown document, used as reference'),\n targetContent: z\n .string()\n .describe(\n 'The existing translated markdown document (may be empty for a brand new translation)'\n ),\n changedLines: z\n .array(z.number())\n .optional()\n .describe(\n '1-based line numbers that changed in the base document. When omitted, only inserted and deleted blocks are reported.'\n ),\n baseLabel: z\n .string()\n .optional()\n .describe('Label for the base locale in the formatted output'),\n targetLabel: z\n .string()\n .optional()\n .describe('Label for the target locale in the formatted output'),\n format: z\n .enum(['text', 'json'])\n .optional()\n .describe('Output format. Defaults to \"text\".'),\n },\n annotations: {\n readOnlyHint: true,\n },\n },\n async ({\n baseContent,\n targetContent,\n changedLines,\n baseLabel,\n targetLabel,\n format,\n }) => {\n try {\n const report = buildReviewReport({\n baseText: baseContent,\n targetText: targetContent,\n changedLines,\n });\n\n const text =\n format === 'json'\n ? JSON.stringify(report, null, 2)\n : formatReviewReport(report, { baseLabel, targetLabel });\n\n return {\n content: [{ type: 'text', text }],\n };\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'An unknown error occurred';\n return {\n content: [\n { type: 'text', text: `Review doc blocks failed: ${errorMessage}` },\n ],\n isError: true,\n };\n }\n }\n );\n};\n"],"mappings":"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"}
|
package/dist/esm/tools/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { loadAPITools } from "./api.mjs";
|
|
2
|
-
import { loadCLITools } from "./cli.mjs";
|
|
3
|
-
import { loadDocsTools } from "./docs.mjs";
|
|
4
1
|
import { loadInstallLSPTool } from "./installLSP.mjs";
|
|
2
|
+
import { loadCLITools } from "./cli.mjs";
|
|
3
|
+
import { loadAPITools } from "./api.mjs";
|
|
5
4
|
import { loadInstallSkillsTool } from "./installSkills.mjs";
|
|
5
|
+
import { loadDocsTools } from "./docs.mjs";
|
|
6
6
|
|
|
7
7
|
export { loadAPITools, loadCLITools, loadDocsTools, loadInstallLSPTool, loadInstallSkillsTool };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as readline from "node:readline";
|
|
2
|
-
import z from "zod";
|
|
3
1
|
import { PLATFORMS, SKILLS, installSkills } from "@intlayer/chokidar/cli";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import * as readline from "node:readline";
|
|
4
4
|
|
|
5
5
|
//#region src/tools/installSkills.ts
|
|
6
6
|
const loadInstallSkillsTool = (server) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","names":[],"sources":["../../../src/tools/cli.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","names":[],"sources":["../../../src/tools/cli.ts"],"mappings":";;;KAqEK,YAAA,IAAgB,MAAA,EAAQ,SAAA,KAAc,OAAA;AAAA,cAE9B,YAAA,EAAc,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","names":[],"sources":["../../../src/tools/docs.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"docs.d.ts","names":[],"sources":["../../../src/tools/docs.ts"],"mappings":";KAcY,UAAA;EACV,OAAA;IAAW,IAAA;IAAc,IAAA;EAAA;EACzB,OAAA;AAAA;AAAA,KAEU,SAAA;EACV,YAAA,CACE,IAAA,UACA,MAAA,OACA,OAAA,GAAU,MAAA,UAAgB,OAAA,CAAQ,UAAA;AAAA;AAAA,KAIjC,aAAA,IAAiB,MAAA,EAAQ,SAAA,KAAc,OAAA;AAAA,cAE/B,aAAA,EAAe,aAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intlayer/mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-canary.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Intlayer MCP server. Handle MCP to help IDE to use Intlayer. It build, fill, pull, push, dictionaries",
|
|
6
6
|
"keywords": [
|
|
@@ -114,26 +114,26 @@
|
|
|
114
114
|
"@ai-sdk/mcp": "1.0.46",
|
|
115
115
|
"@fastify/cors": "11.2.0",
|
|
116
116
|
"@fastify/helmet": "13.0.2",
|
|
117
|
-
"@intlayer/api": "
|
|
118
|
-
"@intlayer/chokidar": "
|
|
119
|
-
"@intlayer/cli": "
|
|
120
|
-
"@intlayer/config": "
|
|
117
|
+
"@intlayer/api": "9.0.0-canary.1",
|
|
118
|
+
"@intlayer/chokidar": "9.0.0-canary.1",
|
|
119
|
+
"@intlayer/cli": "9.0.0-canary.1",
|
|
120
|
+
"@intlayer/config": "9.0.0-canary.1",
|
|
121
121
|
"@intlayer/docs": "8.12.5-canary.0",
|
|
122
|
-
"@intlayer/types": "
|
|
122
|
+
"@intlayer/types": "9.0.0-canary.1",
|
|
123
123
|
"dotenv": "17.4.2",
|
|
124
124
|
"fastify": "5.8.5",
|
|
125
125
|
"zod": "4.4.3"
|
|
126
126
|
},
|
|
127
127
|
"devDependencies": {
|
|
128
|
-
"@intlayer/types": "
|
|
129
|
-
"@types/node": "25.9.
|
|
128
|
+
"@intlayer/types": "9.0.0-canary.1",
|
|
129
|
+
"@types/node": "25.9.3",
|
|
130
130
|
"@utils/ts-config": "1.0.4",
|
|
131
131
|
"@utils/ts-config-types": "1.0.4",
|
|
132
132
|
"@utils/tsdown-config": "1.0.4",
|
|
133
133
|
"rimraf": "6.1.3",
|
|
134
134
|
"tsdown": "0.21.10",
|
|
135
135
|
"typescript": "6.0.3",
|
|
136
|
-
"vitest": "4.1.
|
|
136
|
+
"vitest": "4.1.9"
|
|
137
137
|
},
|
|
138
138
|
"engines": {
|
|
139
139
|
"node": ">=14.18"
|