Daniel Sun created GROOVY-12487:
-----------------------------------
Summary: Add an optional MCP server
Key: GROOVY-12487
URL: https://issues.apache.org/jira/browse/GROOVY-12487
Project: Groovy
Issue Type: New Feature
Reporter: Daniel Sun
An agent needs to ask the Groovy compiler about source without running that
source. {{groovy-mcp}} is an optional subproject that speaks the Model Context
Protocol (MCP) over stdio. It calls the existing {{GroovyLanguageEngine}} in
{{groovy-lsp}}. It is not a second compiler, and it is not part of
{{groovy-all}}.
h3. Launch
{noformat}
groovymcp [--stdio] [--root DIR] [--classpath PATH] [--version] [--help]
{noformat}
* {{--stdio}} is accepted and changes nothing. Stdio is the only transport.
* {{--root}} confines every {{path}} argument to that directory. The directory
is not scanned. Without it, {{path}} is rejected and in-memory {{text}} still
works.
* {{--classpath}} is the compile classpath. It is fixed at launch. A tool call
cannot change it, and the server reports the entry count, not the paths.
* {{--help}} wins over later arguments and exits 0. {{--version}} prints
{{groovy-mcp}} and the implementation version.
Stdout is the protocol stream. Server logs go to stderr. {{main}} redirects
incidental standard output to stderr only while the process is serving, and
restores it afterwards.
h3. Protocol
One JSON-RPC 2.0 message is one UTF-8 line. A JSON array (a batch) is rejected.
CRLF is one line; the CR is not part of the payload and does not count toward
the message cap.
Supported protocol versions are {{2025-11-25}}, {{2025-06-18}}, {{2025-03-26}},
and {{2024-11-05}}. A supported version is echoed. Any other non-empty version
is answered as {{2025-11-25}}.
A session must {{initialize}}, then send {{notifications/initialized}}, before
tools, resources, or prompts answer. {{ping}} is allowed earlier. A second
{{initialize}} is an error. Requests before the session is ready return
{{-32002}}.
* A tool mistake, including an unknown tool, is a successful response with
{{isError}} set. The unknown-tool text is the constant {{unknown tool}}. The
name from the request is not repeated.
* An unknown resource, an unknown prompt, or an argument value that is not an
object returns {{-32602}}.
* An unexpected failure is {{-32603}} with the message {{Internal error}}. The
log records the exception class and a short message, not the source text.
* {{notifications/cancelled}} is ignored. The session handles one request at a
time, and a compile is not interrupted.
Tool input and output schemas use JSON Schema 2020-12. Each tool has a title
and an {{outputSchema}}. A successful {{structuredContent}} matches that
schema. A failed call's {{structuredContent}} is an {{error}} string.
h3. What the server exposes
Thirteen read-only tools wrap the engine: diagnostics, describe, definition,
implementations, references, symbols, complete, signatures, tokens, format,
organize-imports, rename, and close. Format, organize-imports, and rename
return edits. They do not write files. An empty rename means the compiler did
not prove the binding.
Positions are 0-based UTF-16 and are passed through unchanged.
Source is passed in one of three ways:
* {{text}} keeps the source in a {{groovy-buffer}} URI. The default is
{{groovy-buffer:snippet}}. {{text}} may also carry a {{uri}} of that scheme. It
is not attached to a file URI.
* {{path}} reads one file under {{--root}}.
* {{uri}} addresses a buffer that is already open. A file URI must stay inside
the root, including the path after symbolic links are resolved.
{{text}} together with {{path}} is rejected, and so is {{path}} together with
{{uri}}.
Three JSON resources list the lexer keywords, the default imports, and the
server limits. The keyword list and the default imports come from the compiler.
Two prompts, {{explain-groovy}} and {{review-groovy}}, tell the model to use
those tools and not to run the source. The server does not treat the prompt
text as instructions to itself.
h3. Limits and safety
Defaults are 2 MiB for one message, 512 Ki characters of source, and 512 Ki
characters of result JSON. Oversized tool JSON is replaced with an error
result. Client strings that must be quoted are shortened, and control
characters are replaced.
There is no evaluate tool. Grab and ASTTest stay disabled. The process does not
walk a workspace, invoke Gradle or Maven, or download dependencies. Sampling,
elicitation, tasks, and HTTP transports are not implemented. The module does
not depend on an MCP library or an LLM client library. JSON is parsed and
written with {{groovy.json}}.
h3. Build
The module is optional. Binary-compatibility checks are off until a release has
published a baseline jar, as with {{groovy-lsp}}. The jar's main class is
{{org.apache.groovy.mcp.GroovyMcpLauncher}}. The binary distribution ships the
jar, {{groovymcp}}, and {{groovymcp.bat}}. Both scripts are force-added because
{{bin/}} is ignored, the same way {{groovylsp}} is tracked. The user guide is
included from the binary documentation.
The public types are {{GroovyMcpServer}}, {{GroovyMcpLauncher}}, and
{{McpServerConfig}}. Types under {{org.apache.groovy.mcp.internal}} are not a
supported API.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)