[MCP Server] i18n for tool activity messages

(cherry picked from commit 774d78070494db974b41baaa33f047a5760d3c8a)

GitOrigin-RevId: e1f84771d6189fa1267632ad6c1de23d2c7c366c
This commit is contained in:
Artem.Bukhonov
2025-07-12 18:49:41 +02:00
committed by intellij-monorepo-bot
parent d34f8bf3f5
commit 22d44fe866
11 changed files with 55 additions and 41 deletions

View File

@@ -58,3 +58,27 @@ command.execution.confirmation.allow=Allow
command.execution.confirmation.deny=Deny
dialog.mcp.server.consent.enable.button=Enable
dialog.mcp.server.consent.cancel.button=Cancel
# Tool activities
tool.activity.traversing.folder.tree=Traversing folder tree for ''{0}''
tool.activity.finding.files.by.name=Finding files with name containing ''{0}''
tool.activity.finding.files.by.glob=Finding files by glob ''{0}''
tool.activity.opening.file=Opening file ''{0}''
tool.activity.getting.open.files=Getting open files
tool.activity.creating.file=Creating file ''{0}''
tool.activity.searching.commits=Searching commits for ''{0}''
tool.activity.checking.vcs.status=Checking VCS status
tool.activity.formatting.file=Formatting file ''{0}''
tool.activity.reading.file=Reading file ''{0}''
tool.activity.replacing.text.in.file=Replacing text in ''{0}'': ''{1}'' \u2192 ''{2}''
tool.activity.searching.files.for.text=Searching project files for ''{0}''
tool.activity.searching.content.with.regex=Searching content with regex ''{0}''
tool.activity.running.command=Running command: ''{0}''
tool.activity.getting.symbol.info=Getting symbol info at ''{0}:{1}:{2}''
tool.activity.renaming.symbol=Renaming ''{0}'' to ''{1}'' in ''{2}''
tool.activity.getting.run.configurations=Getting run configurations
tool.activity.executing.run.configuration=Executing run configuration ''{0}''
tool.activity.collecting.file.problems=Collecting problems in file ''{0}''
tool.activity.checking.project.issues=Checking project issues
tool.activity.listing.modules=Listing modules
tool.activity.checking.dependencies=Checking dependencies

View File

@@ -1,5 +1,6 @@
package com.intellij.mcpserver
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.application
import com.intellij.util.messages.Topic
@@ -15,7 +16,7 @@ interface ToolCallListener {
fun afterMcpToolCall(mcpToolDescriptor: McpToolDescriptor, events: List<McpToolSideEffectEvent>, error: Throwable?) {}
fun toolActivity(mcpToolDescriptor: McpToolDescriptor, toolActivityDescription: String) {}
fun toolActivity(mcpToolDescriptor: McpToolDescriptor, @NlsContexts.Label toolActivityDescription: String) {}
}
sealed interface McpToolSideEffectEvent
@@ -27,6 +28,6 @@ class FileDeletedEvent(val file: VirtualFile, val content: String?) : FileEvent
class FileMovedEvent(val file: VirtualFile, val oldParent: VirtualFile, val newParent: VirtualFile) : FileEvent
class FileContentChangeEvent(val file: VirtualFile, val oldContent: String?, val newContent: String) : FileEvent
fun CoroutineContext.reportToolActivity(toolDescription: String) {
fun CoroutineContext.reportToolActivity(@NlsContexts.Label toolDescription: String) {
application.messageBus.syncPublisher(ToolCallListener.TOPIC).toolActivity(this.currentToolDescriptor, toolDescription)
}

View File

@@ -51,7 +51,7 @@ class AnalysisToolset : McpToolset {
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION)
timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE,
): FileProblemsResult {
currentCoroutineContext().reportToolActivity("Collecting problems in file '$filePath'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.collecting.file.problems", filePath))
val project = currentCoroutineContext().project
val projectDir = project.projectDirectory
@@ -107,7 +107,7 @@ class AnalysisToolset : McpToolset {
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION)
timeout: Int = Constants.LONG_TIMEOUT_MILLISECONDS_VALUE,
): ProjectProblemsResult {
currentCoroutineContext().reportToolActivity("Checking project issues")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.checking.project.issues"))
val project = currentCoroutineContext().project
val problems = CopyOnWriteArrayList<ProjectProblem>()
@@ -145,7 +145,7 @@ class AnalysisToolset : McpToolset {
|Returns structured information about each module including name and type.
""")
suspend fun get_project_modules(): ProjectModulesResult {
currentCoroutineContext().reportToolActivity("Listing modules")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.listing.modules"))
val project = currentCoroutineContext().project
val modules = readAction {
@@ -167,7 +167,7 @@ class AnalysisToolset : McpToolset {
|Returns structured information about project library names.
""")
suspend fun get_project_dependencies(): ProjectDependenciesResult {
currentCoroutineContext().reportToolActivity("Checking dependencies")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.checking.dependencies"))
val project = currentCoroutineContext().project
val dependencies = readAction {

View File

@@ -1,12 +1,9 @@
package com.intellij.mcpserver.toolsets.general
import com.intellij.lang.documentation.impl.documentationTargets
import com.intellij.mcpserver.McpToolset
import com.intellij.mcpserver.*
import com.intellij.mcpserver.annotations.McpDescription
import com.intellij.mcpserver.annotations.McpTool
import com.intellij.mcpserver.mcpFail
import com.intellij.mcpserver.project
import com.intellij.mcpserver.reportToolActivity
import com.intellij.mcpserver.toolsets.Constants
import com.intellij.mcpserver.util.SymbolInfo
import com.intellij.mcpserver.util.convertHtmlToMarkdown
@@ -46,7 +43,7 @@ class CodeInsightToolset : McpToolset {
@McpDescription("1-based column number")
column: Int,
): SymbolInfoResult {
currentCoroutineContext().reportToolActivity("Getting symbol info at '$filePath:$line:$column'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.getting.symbol.info", filePath, line, column))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(filePath)

View File

@@ -44,7 +44,7 @@ class ExecutionToolset : McpToolset {
|Use this tool to query the list of available run configurations in the current project.
""")
suspend fun get_run_configurations(): RunConfigurationsList {
currentCoroutineContext().reportToolActivity("Getting run configurations")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.getting.run.configurations"))
val project = currentCoroutineContext().project
val runManager = RunManager.getInstance(project)
@@ -80,7 +80,7 @@ class ExecutionToolset : McpToolset {
@McpDescription(Constants.TRUNCATE_MODE_DESCRIPTION)
truncateMode: TruncateMode = Constants.TRUCATE_MODE_VALUE,
): RunConfigurationResult {
currentCoroutineContext().reportToolActivity("Executing run configuration '$configurationName'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.executing.run.configuration", configurationName))
val project = currentCoroutineContext().project
val runManager = RunManager.getInstance(project)

View File

@@ -56,7 +56,7 @@ class FileToolset : McpToolset {
@McpDescription("Maximum recursion depth") maxDepth: Int = 5,
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION) timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE,
): DirectoryTreeInfo {
currentCoroutineContext().reportToolActivity("Traversing folder tree for '$directoryPath'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.traversing.folder.tree", directoryPath))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(directoryPath)
if (!resolvedPath.exists()) mcpFail("No such directory: $resolvedPath")
@@ -94,7 +94,7 @@ class FileToolset : McpToolset {
@McpDescription("Timeout in milliseconds")
timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE,
): FilesListResult {
currentCoroutineContext().reportToolActivity("Finding files with name containing '$nameKeyword'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.finding.files.by.name", nameKeyword))
val project = currentCoroutineContext().project
val projectDir = project.projectDirectory
@@ -145,7 +145,7 @@ class FileToolset : McpToolset {
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION)
timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE
) : FilesListResult {
currentCoroutineContext().reportToolActivity("Finding files by glob '$globPattern'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.finding.files.by.glob", globPattern))
val project = currentCoroutineContext().project
val projectDirPath = project.projectDirectory
val fileIndex = ProjectRootManager.getInstance(project).getFileIndex()
@@ -205,7 +205,7 @@ class FileToolset : McpToolset {
@McpDescription(Constants.RELATIVE_PATH_IN_PROJECT_DESCRIPTION)
filePath: String,
) {
currentCoroutineContext().reportToolActivity("Opening file '$filePath'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.opening.file", filePath))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(filePath)
@@ -226,7 +226,7 @@ class FileToolset : McpToolset {
|Use this tool to explore current open editors.
""")
suspend fun get_all_open_file_paths(): OpenFilesInfo {
currentCoroutineContext().reportToolActivity("Getting open files")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.getting.open.files"))
val project = currentCoroutineContext().project
val projectDir = project.projectDirectory
@@ -255,7 +255,7 @@ class FileToolset : McpToolset {
@McpDescription("Content to write into the new file")
text: String? = null,
) {
currentCoroutineContext().reportToolActivity("Creating file '$pathInProject'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.creating.file", pathInProject))
val project = currentCoroutineContext().project
val path = project.resolveInProject(pathInProject)

View File

@@ -3,12 +3,9 @@
package com.intellij.mcpserver.toolsets.general
import com.intellij.codeInsight.actions.ReformatCodeProcessor
import com.intellij.mcpserver.McpToolset
import com.intellij.mcpserver.*
import com.intellij.mcpserver.annotations.McpDescription
import com.intellij.mcpserver.annotations.McpTool
import com.intellij.mcpserver.mcpFail
import com.intellij.mcpserver.project
import com.intellij.mcpserver.reportToolActivity
import com.intellij.mcpserver.toolsets.Constants
import com.intellij.mcpserver.util.resolveInProject
import com.intellij.openapi.application.EDT
@@ -30,7 +27,7 @@ class FormattingToolset : McpToolset {
@McpDescription(Constants.RELATIVE_PATH_IN_PROJECT_DESCRIPTION)
path: String,
): String {
currentCoroutineContext().reportToolActivity("Formatting file '$path'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.formatting.file", path))
val project = currentCoroutineContext().project
val resolvedFilePath = project.resolveInProject(path)

View File

@@ -1,11 +1,8 @@
package com.intellij.mcpserver.toolsets.general
import com.intellij.mcpserver.McpToolset
import com.intellij.mcpserver.*
import com.intellij.mcpserver.annotations.McpDescription
import com.intellij.mcpserver.annotations.McpTool
import com.intellij.mcpserver.mcpFail
import com.intellij.mcpserver.project
import com.intellij.mcpserver.reportToolActivity
import com.intellij.mcpserver.toolsets.Constants
import com.intellij.mcpserver.util.resolveInProject
import com.intellij.openapi.application.EDT
@@ -45,7 +42,7 @@ class RefactoringToolset : McpToolset {
@McpDescription("New name for the symbol")
newName: String,
): String {
currentCoroutineContext().reportToolActivity("Renaming '$symbolName' to '$newName' in '$pathInProject'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.renaming.symbol", symbolName, newName, pathInProject))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(pathInProject)

View File

@@ -5,12 +5,9 @@ package com.intellij.mcpserver.toolsets.general
import com.intellij.find.FindBundle
import com.intellij.find.FindManager
import com.intellij.find.impl.FindInProjectUtil
import com.intellij.mcpserver.McpToolset
import com.intellij.mcpserver.*
import com.intellij.mcpserver.annotations.McpDescription
import com.intellij.mcpserver.annotations.McpTool
import com.intellij.mcpserver.mcpFail
import com.intellij.mcpserver.project
import com.intellij.mcpserver.reportToolActivity
import com.intellij.mcpserver.toolsets.Constants
import com.intellij.mcpserver.util.*
import com.intellij.openapi.application.readAction
@@ -52,7 +49,7 @@ class TextToolset : McpToolset {
@McpDescription("Max number of lines to return. Truncation will be performed depending on truncateMode.")
maxLinesCount: Int = 1000,
): String {
currentCoroutineContext().reportToolActivity("Reading file '$pathInProject'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.reading.file", pathInProject))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(pathInProject)
@@ -104,7 +101,7 @@ class TextToolset : McpToolset {
@McpDescription("Case-sensitive search")
caseSensitive: Boolean = true,
) {
currentCoroutineContext().reportToolActivity("Replacing text in '$pathInProject': '$oldText' → '$newText'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.replacing.text.in.file", pathInProject, oldText, newText))
val project = currentCoroutineContext().project
val resolvedPath = project.resolveInProject(pathInProject)
val (document, text) = readAction {
@@ -157,7 +154,7 @@ class TextToolset : McpToolset {
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION)
timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE,
): UsageInfoResult {
currentCoroutineContext().reportToolActivity("Searching project files for '$searchText'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.searching.files.for.text", searchText))
return search_in_files(searchText, false, directoryToSearch, fileMask, caseSensitive, maxUsageCount, timeout)
}
@@ -182,7 +179,7 @@ class TextToolset : McpToolset {
@McpDescription(Constants.TIMEOUT_MILLISECONDS_DESCRIPTION)
timeout: Int = Constants.MEDIUM_TIMEOUT_MILLISECONDS_VALUE,
): UsageInfoResult {
currentCoroutineContext().reportToolActivity("Searching content with regex '$regexPattern'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.searching.content.with.regex", regexPattern))
return search_in_files(regexPattern, true, directoryToSearch, fileMask, caseSensitive, maxUsageCount, timeout)
}

View File

@@ -54,7 +54,7 @@ class TerminalToolset : McpToolset {
@McpDescription(Constants.TRUNCATE_MODE_DESCRIPTION)
truncateMode: TruncateMode = Constants.TRUCATE_MODE_VALUE,
): CommandExecutionResult {
currentCoroutineContext().reportToolActivity("Running command: '$command'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.running.command", command))
val project = currentCoroutineContext().project
checkUserConfirmationIfNeeded(McpServerBundle.message("label.do.you.want.to.execute.command.in.terminal"), command, project)

View File

@@ -2,6 +2,7 @@
package com.intellij.mcpserver.toolsets.vcs
import com.intellij.mcpserver.McpServerBundle
import com.intellij.mcpserver.McpToolset
import com.intellij.mcpserver.annotations.McpDescription
import com.intellij.mcpserver.annotations.McpTool
@@ -27,7 +28,7 @@ class VcsToolset : McpToolset {
@McpDescription("Text or keywords to search for in commit messages")
text: String
): String {
currentCoroutineContext().reportToolActivity("Searching commits for '$text'")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.searching.commits", text))
val project = currentCoroutineContext().project
val queryText = text
val matchingCommits = mutableListOf<String>()
@@ -79,7 +80,7 @@ class VcsToolset : McpToolset {
Note: Works with any VCS supported by the IDE, but is most commonly used with Git
""")
suspend fun get_project_vcs_status(): String {
currentCoroutineContext().reportToolActivity("Checking VCS status")
currentCoroutineContext().reportToolActivity(McpServerBundle.message("tool.activity.checking.vcs.status"))
val project = currentCoroutineContext().project
val projectDir = project.projectDirectory