Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,34 +233,6 @@ jobs:
run: |
mvn clean install -pl $EXCLUDE_MODULES -q -DskipTests -Dci
mvn verify -pl gremlin-driver -DskipIntegrationTests=false
javascript-node20:
name: javascript-all-node20
timeout-minutes: 15
needs: cache-gremlin-server-docker-image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up JDK 11
uses: actions/setup-java@v5
with:
java-version: '11'
distribution: 'temurin'
- name: Get Cached Server Base Image
uses: actions/cache@v5
id: gremlin-server-test-docker-image
with:
path: |
./gremlin-server/*
~/.m2/repository/org/apache/tinkerpop/*
key: ${{ github.sha }}
- name: Load Docker Image
working-directory: ./gremlin-server
run: docker load --input gremlin-server.tar
- name: Build with Maven
run: |
EXCLUDE="-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlin-go,-:gremlin-python,$EXCLUDE_FOR_GLV"
mvn clean install -pl $EXCLUDE -q -DskipTests -Dci
mvn verify -pl :gremlin-javascript,:gremlint,:gremlin-mcp -Dnode.test.version=20
javascript-node22:
name: javascript-glv-node22
timeout-minutes: 15
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
[[release-4-0-0]]
=== TinkerPop 4.0.0 (NOT OFFICIALLY RELEASED YET)

* Added grammar-based `Translator` for `gremlin-javascript` supporting translation to JavaScript, Python, Go, .NET, Java, Groovy, canonical, and anonymized output.
* Added `translate_gremlin_query` tool to `gremlin-mcp` that translates Gremlin queries to a target language variant, with optional LLM-assisted normalization via MCP sampling for non-canonical input.
* Modified `gremlin-mcp` to support offline mode where utility tools (translate, format) remain available without a configured `GREMLIN_MCP_ENDPOINT`.
* Added `__contains__` and `keys()` to `Element` in `gremlin-python`.
* Added `subgraph()` support for `gremlin-python` so that results are stored in a detached `Graph` object.
* Modified grammar to make `discard()` usage more consistent as a filter step where it can now be used to chain additional traversal steps and be used anonymously.
Expand Down
40 changes: 38 additions & 2 deletions docs/src/reference/gremlin-applications.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -2353,9 +2353,12 @@ input schema, and a result schema. When connected to a Gremlin MCP server, the a
* Inspect the server’s health and connection to a Gremlin data source
* Discover the graph’s schema (labels, properties, relationships, counts)
* Execute Gremlin traversals
* Translate Gremlin queries between language variants
* Format Gremlin queries for readability

The Gremlin MCP server sits alongside Gremlin Server (or any TinkerPop‑compatible endpoint) and forwards tool calls to
the graph via standard Gremlin traversals.
the graph via standard Gremlin traversals. The translation and formatting tools are utility tools that work
independently and do not require a graph connection.

IMPORTANT: This MCP server is designed for development and trusted environments.

Expand All @@ -2382,6 +2385,7 @@ The Gremlin MCP server exposes these tools:
properties may be surfaced as enums to encourage valid values in queries.
* `run_gremlin_query` — Executes an arbitrary Gremlin traversal and returns JSON results.
* `refresh_schema_cache` — Forces schema discovery to run again when the graph has changed.
* `translate_gremlin_query` — Translates a Gremlin query to a target language variant with optional normalization.
* `format_gremlin_query` — Formats a Gremlin query using gremlint.

==== Schema discovery
Expand Down Expand Up @@ -2439,6 +2443,38 @@ g.V().
limit(1).fold())
----

==== Translating traversals

The `translate_gremlin_query` tool translates a Gremlin query from one language variant to another. Supported
targets are: `canonical`, `javascript`, `python`, `go`, `dotnet`, `java`, `groovy`, and `anonymized`. The
`canonical` target produces gremlin-language ANTLR format with normalized whitespace and explicit enum names,
which is useful for validating or standardizing queries before further processing.

The optional `source` parameter controls how the input is pre-processed before translation:

* When omitted or set to `auto` (the default), the server applies mechanical normalization (stripping
language-specific prefixes, correcting step casing) and then requests LLM normalization from the MCP client
via MCP sampling. This handles input from any dialect without the caller needing to know the source language.
If the MCP client does not support sampling, the LLM step is skipped and a `warning` field is included in
the response to indicate that the result is based on mechanical normalization only.
* When set to `canonical`, normalization is skipped entirely and the input is passed directly to the translator.
This is the most efficient path when the input is known to be in canonical gremlin-language ANTLR format.

For example, a user could supply this prompt to the assistant:

[source,text]
----
Translate this Go traversal to Groovy:
gremlingo.T__.V().Has("name", "Alice").Out("knows").Values("name")
----

And the assistant would call `translate_gremlin_query` with `target: "groovy"` and receive:

[source,groovy]
----
g.V().has('name', 'Alice').out('knows').values('name')
----

==== Executing traversals

When the assistant needs to answer a question, a common sequence is:
Expand All @@ -2463,7 +2499,7 @@ endpoint the server should use.

Basic connection settings:

* `GREMLIN_MCP_ENDPOINT` — `host:port` or `host:port/traversal_source` for the target Gremlin Server or compatible endpoint (default traversal source: `g`)
* `GREMLIN_MCP_ENDPOINT` — `host:port` or `host:port/traversal_source` for the target Gremlin Server or compatible endpoint (default traversal source: `g`). Optional — when not set, graph tools are not registered but `translate_gremlin_query` and `format_gremlin_query` remain available.
* `GREMLIN_MCP_USE_SSL` — set to `true` when TLS is required by the endpoint (default: `false`)
* `GREMLIN_MCP_USERNAME` / `GREMLIN_PASSWORD` — credentials when authentication is enabled (optional)
* `GREMLIN_MCP_IDLE_TIMEOUT` — idle connection timeout in seconds (default: `300`)
Expand Down
46 changes: 46 additions & 0 deletions docs/src/upgrade/release-4.x.x.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,52 @@ complete list of all the modifications that are part of this release.

=== Upgrading for Users

==== Gremlin MCP Server

===== Gremlin Query Translation

A `translate_gremlin_query` tool is now available that translates a Gremlin query into a target language variant.
Supported targets are `canonical`, `javascript`, `python`, `go`, `dotnet`, `java`, `groovy`, and `anonymized`.

The optional `source` parameter describes the dialect of the input. When omitted or set to `auto`, the server
normalizes the input before translating — first by applying mechanical transformations (stripping language-specific
prefixes, correcting step casing, etc.) and then by requesting LLM normalization from the MCP client via MCP
sampling. If the MCP client does not support sampling, the LLM step is skipped gracefully and a warning is included
in the response. Set `source` to `canonical` to bypass normalization entirely when the input is already in canonical
gremlin-language ANTLR format.

Some example prompts that will invoke this tool:

[source,text]
----
Translate g.V().has('name','Alice').out('knows').values('name') to Python.
----

[source,text]
----
Convert this Go Gremlin traversal to Groovy:
gremlingo.T__.V().Has("name", "Alice").Out("knows").Values("name")
----

[source,text]
----
I have some Java Gremlin code. Translate it to canonical format so I can review it:
g.V().has("name", "Alice").out("knows").values("name")
----

===== Offline Mode

`GREMLIN_MCP_ENDPOINT` is no longer required to start the server. When no endpoint is configured, graph tools
(`get_graph_status`, `get_graph_schema`, `run_gremlin_query`) are not registered, but the utility tools
(`translate_gremlin_query`, `format_gremlin_query`) remain fully available. This makes it possible to use the
Gremlin MCP Server purely as a translation and formatting aid without any graph database:

[source,text]
----
Format this Gremlin query for readability:
g.V().has('name','Alice').out('knows').out('knows').where(neq('Alice')).values('name').dedup()
----

==== SLF4j 2.x

TinkerPop has generally upgraded to SLF4j 2.x which brings with it some important changes to log initialization which
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,78 @@ public static Collection<Object[]> data() {
null,
null,
null},
{"g.tx().begin()",
null,
null,
"g.Tx().Begin()",
"g.Tx().Begin()",
null,
null,
null,
null},
{"g.tx().rollback()",
null,
null,
"g.Tx().Rollback()",
"g.Tx().Rollback()",
null,
null,
null,
null},
{"g.V().next()",
null,
null,
"g.V().Next()",
"g.V().Next()",
null,
null,
null,
null},
{"g.V().next(2)",
null,
"g.V().next(number0)",
"g.V().Next(2)",
"g.V().Next(2)",
null,
null,
null,
null},
{"g.V().hasNext()",
null,
null,
"g.V().HasNext()",
"g.V().HasNext()",
null,
null,
null,
"g.V().has_next()"},
{"g.V().tryNext()",
null,
null,
"g.V().TryNext()",
"g.V().TryNext()",
null,
null,
null,
"g.V().try_next()"},
{"g.V().toSet()",
null,
null,
"g.V().ToSet()",
"g.V().ToSet()",
null,
null,
null,
"g.V().to_set()"},
{"g.V().toBulkSet()",
null,
null,
"g.V().ToBulkSet()",
"g.V().ToBulkSet()",
null,
null,
null,
"g.V().to_bulk_set()"},
{"g.call(\"--list\").with(\"service\", __.constant(\"tinker.search\"))",
"g.call(\"--list\").with(\"service\", __.constant(\"tinker.search\"))",
"g.call(string0).with(string1, __.constant(string2))",
Expand Down
6 changes: 3 additions & 3 deletions gremlin-javascript/build/generate.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ radishGremlinFile.withWriter('UTF-8') { Writer writer ->
'* to you under the Apache License, Version 2.0 (the\n' +
'* "License"); you may not use this file except in compliance\n' +
'* with the License. You may obtain a copy of the License at\n' +
'* \n' +
'* http://www.apache.org/licenses/LICENSE-2.0\n' +
'* \n' +
'*\n' +
'* http://www.apache.org/licenses/LICENSE-2.0\n' +
'*\n' +
'* Unless required by applicable law or agreed to in writing,\n' +
'* software distributed under the License is distributed on an\n' +
'* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n' +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ npm-debug.log
# maven plugin com.github.eirslett frontend-maven-plugin installs node.js runtime in "node" folder
node/
doc/
build/
build/
lib/language/grammar/
**/.duel-cache/
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ services:
- .:/js_app
- ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features:/gremlin-test
- ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary:/js_app/gremlin-test/graphbinary
- ../../../../../gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator:/js_app/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator
- ../../../../../docker/gremlin-test-server:/js_app/gremlin-test-server
- ../../../../../gremlin-tools/gremlin-socket-server/conf:/js_app/gremlin-socket-server/conf/
- ../../../../../gremlin-language/src/main/antlr4:/gremlin-language/src/main/antlr4
- ../../../..:/gremlin-javascript
environment:
- DOCKER_ENVIRONMENT=true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { GremlinTranslator } from './translator/GremlinTranslator.js';
export { Translation } from './translator/Translation.js';
export { TranslatorException } from './translator/TranslatorException.js';
export { Translator } from './translator/Translator.js';
export { default as TranslateVisitor } from './translator/TranslateVisitor.js';
export { default as JavascriptTranslateVisitor } from './translator/JavascriptTranslateVisitor.js';
export { default as PythonTranslateVisitor } from './translator/PythonTranslateVisitor.js';
export { default as GoTranslateVisitor } from './translator/GoTranslateVisitor.js';
export { default as DotNetTranslateVisitor } from './translator/DotNetTranslateVisitor.js';
export { default as JavaTranslateVisitor } from './translator/JavaTranslateVisitor.js';
export { default as GroovyTranslateVisitor } from './translator/GroovyTranslateVisitor.js';
export { default as AnonymizedTranslateVisitor } from './translator/AnonymizedTranslateVisitor.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "module" }
Loading
Loading