Native gateway that hosts your modules behind WebSocket, HTTP, optional TCP, and optional HTTP/2 servers. It can run Graftcode Vision (web UI) and the Graftcode Module Analyzer (GMA) for a graph view of loaded modules.
Installers and archives are published on GitHub Releases.
iwr https://grft.dev/get | iexcurl -fsSL https://grft.dev/get | shAll Graftcode Gateway CLI options are optional.
GG can be used just by launching it in a directory which contains the modules to host. By default, GG will scan the current directory for modules and try to detect the runtime. If you want to specify the modules and runtime explicitly, use the --modules and --runtime options.
See Known issues below for common pitfalls and troubleshooting tips, especially when communication with the gateway fails or modules are not loaded.
Run gg --help (or gg.exe --help on Windows) for the full CLI.
You may pass the main module path as the first positional argument instead of --modules (for example: ./gg ./MyApp.dll --port 8888). If both are provided, --modules takes precedence.
Option names are case-insensitive (for example --httpport and --httpPort are equivalent).
| Option | Default | Description |
|---|---|---|
--runtime |
auto |
Runtime to host: auto, clr, netcore, java, jvm, python, python27, ruby, nodejs, php |
--modules |
(empty) | Comma-separated list of modules to host (DLLs, JARs, package paths, etc.) |
--config |
(empty) | Path to a JSON config file or inline JSON string (see Plugin server config) |
--projectKey |
(empty) | Project key for portal authentication and project metadata. Use env:jwt form (for example dev:eyJ...) or a bare JWT. Get your key from Graftcode Portal. |
--gatewayName |
(empty) | Stable gateway name sent to GSMU. When set, GSMU finds or creates that gateway and later runs reuse it. When omitted, GSMU assigns a new random name each run (for example false-candlewood). GG and Vision always show the name returned by GSMU. |
--endpoint |
https://grft.dev |
Graftcode API endpoint URL used for GSMU upload and related services |
--port |
80 |
WebSocket server port |
--httpPort |
81 |
HTTP server port for Graftcode Vision (used when --GV is enabled) |
--tcpPort |
82 |
TCP server port when --tcpServer is enabled |
--http2Port |
83 |
HTTP/2 server port when --http2Server is enabled |
--GV |
true |
Host Graftcode Vision. When enabled, also turns on --GSMU |
--GMA |
true |
Run the Graftcode Module Analyzer to build the Unified Graft Model. Pass --GMA false to disable |
--GSMU |
false |
Upload the Unified Graft Model to GSMU |
--types |
(empty) | Comma-separated list of types to expose from hosted modules |
--methods |
(empty) | Comma-separated list of methods to expose from hosted modules |
--tcpServer |
false |
Enable the TCP server |
--http2Server |
false |
Enable the HTTP/2 server |
--runApp |
false |
Run the hosted application entry point |
--initMethod |
(empty) | Static method to invoke after modules are loaded. Use Class.Method (C#, Java, Python, Node.js) or Class::method (Ruby, PHP) |
--initMethodArgs |
(empty) | Optional comma-separated arguments for --initMethod. Values are passed as strings, numbers, or true/false |
--mcpBaseClass |
(empty) | Optional declaring type FQN from the UGM (for example MyAsm.MyNs.MyClass, com.app.Util, package.module, MyModule::MyClass, or My\Php\Class) used when MCP tools/call uses a bare method name, params.class is empty, and the name is not in the MCP registry. Dotted names are normalized for Ruby and PHP. |
--noVersioning |
false |
Disable versioning for hosted modules |
--keepVersioning |
true |
Enable versioning for hosted modules |
--useContext |
false |
[DEPRECATED] Previously enabled Graftcode Context manually. Context is now auto-detected at startup when the hosted module provides it |
--corsAllowedOrigins |
(empty) | Comma-separated CORS origin allowlist (for example http://localhost:3000,https://app.example.com or *) |
--corsConfig |
(empty) | Path to a CORS config file (key=value format) |
--doNotExtractBinaries |
false |
Do not extract bundled binaries; you must provide them yourself |
--graftOnly |
false |
Generate and publish the Unified Graft Model without starting any servers |
Versioning behavior is resolved after CLI and environment-variable parsing:
- Without a
--projectKey(orGC_PROJECT_KEY) and without GSMU, the gateway runs in standalone mode and disables versioning by default. Standalone is not used whenever GSMU is called (--GSMUor--GV, which enables GSMU). --keepVersioning(defaulttrue) re-enables versioning even without a project key.--noVersioningexplicitly disables versioning regardless of project key.
The WebSocket server always starts. The HTTP server (Graftcode Vision) starts only when --GV is enabled (default).
auto— Let GG detect the runtime (default)netcore— latest .NET (Core) runtime installed on machine. Supported versions: .NET Core 3.1, .NET 5 or newerclr— .NET Framework runtime installed on the machine; 4.7.2 or newerjava/jvm— Java installed on the machine;JAVA_HOMEshould point at the JDK; Java 8 or newerpython— Python 3 installed on the machine; Python 3.6 or newerpython27— Python 2.7 installed on the machineruby— Ruby 3 installed on the machine. Supported Ruby 3 or newernodejs— Node.js 22 installed on the machine. Supported Node.js 22 or newerphp— PHP 7.4 installed on the machine. Supported PHP 7.4 or newer
./gg /path/to/your.dll --port 8888 --httpPort 8889
./gg /path/to/package/dir --port 8888 --httpPort=8889
./gg /path/to/your.jar --port 8888 --httpPort 8889
./gg /path/to/lib.dll --http2Server --http2Port 8989 --tcpServer --tcpPort 8990
./gg /path/to/lib.dll --httpPort 8888 --corsConfig ./cors.config
./gg /path/to/lib.dll --types MyClass.MyClass --methods Add,Subtract
./gg --runtime netcore --types MyNamespace.MyClass --http2Server
./gg /path/to/lib.dll --projectKey env:eyJ... --gatewayName my-gateway
./gg /path/to/lib.dll --projectKey env:eyJ...When no module path is provided, GG uses AnalyzeLocalRuntime (via GMA, enabled
by default) to analyze types already loaded in the process. In this mode, set
--runtime explicitly and pass --types (and optionally --methods).
GG exposes hosted module methods as MCP tools via Streamable HTTP at POST /mcp.
| Server | Default port | MCP endpoint |
|---|---|---|
| HTTP (Drogon) | --httpPort (81) |
http://localhost:81/mcp |
| WebSocket (uWebSockets) | --port (80) |
http://localhost:80/mcp |
| HTTP/2 (optional) | --http2Port (83) |
http://localhost:83/mcp |
Example MCP client config (Streamable HTTP):
{
"mcpServers": {
"graftcode-gateway": {
"url": "http://localhost:81/mcp"
}
}
}Clients that only support stdio MCP servers can bridge over HTTP with mcp-remote:
{
"mcpServers": {
"graftcode-gateway": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:81/mcp"]
}
}
}POST /mcp handles JSON-RPC (initialize, tools/list, tools/call). GET /mcp returns 405. DELETE /mcp with Mcp-Session-Id ends the session.
Single-port HTTP/2 mode: When your deployment can expose only one port, enable the HTTP/2 server and use it for both the binary graft protocol and MCP:
POST /h2— binary byte-array protocol (HTTP/2 clients)POST /mcp— MCP Streamable HTTP (HTTP/1.1 or HTTP/2)
./gg ./MyApp.dll --http2Server --http2Port 8989Point MCP clients at http://localhost:8989/mcp. Standard MCP clients use HTTP/1.1, which the gateway accepts on the same port alongside HTTP/2 for graft traffic.
The HTTP/2 port also exposes the same informational GET routes as the WebSocket port (/status, /gatewayname, /http2port, /mcpport, /ugm, /libraries, /discover, /idl, /mcpmodel, package install commands, etc.).
Pass a file path with --corsConfig to control CORS from configuration instead of code.
Supported keys:
allowedOriginsororiginsallowedMethodsormethodsallowedHeadersorheadersexposedHeadersorexposeHeadersallowCredentialsorcredentials(true/false,1/0,yes/no)
Example cors.config:
# Comma-separated values
allowedOrigins=http://localhost:3000,https://app.example.com
allowedMethods=GET,POST,PUT,PATCH,DELETE,OPTIONS
allowedHeaders=content-type,authorization,MCP-Protocol-Version,Mcp-Session-Id
exposedHeaders=Mcp-Session-Id,MCP-Protocol-Version
allowCredentials=falseNotes:
- If
allowedOriginsis empty or missing, CORS headers are not added. - If
allowedOrigins=*andallowCredentials=true, gateway responds with request origin (not*) to keep browser behavior valid. --corsAllowedOriginsworks without a config file; when both are provided, values from--corsConfigare applied during startup and can override CLI defaults.
Environment variables are read after CLI parsing and override matching CLI values.
| Variable | Purpose |
|---|---|
GG_DEBUG |
Set to 1 or TRUE to log incoming and outgoing byte traffic to the console |
GSMU_ENDPOINT |
When set, overrides the gateway endpoint from --endpoint (default CLI value is https://grft.dev) |
GC_PROJECT_KEY |
Project key in env:token form (for example dev:eyJ...) or as a bare JWT; when set, overrides --projectKey |
UWS_HTTP_MAX_HEADERS_SIZE |
Max HTTP request header size in bytes for the WebSocket/HTTP listener. Default is 16384 |
You can run an external server plugin by passing a config file path or inline JSON to --config:
./gg --config /path/to/plugin-config.json
./gg /path/to/lib.dll --config '{"name":"RabbitmqPlugin","queue":"gg","replyQueue":"gg.reply"}'Example config:
{
"name": "RabbitmqPlugin",
"queue": "gg",
"replyQueue": "gg.reply",
"user": "guest",
"password": "guest",
"vhost": "/",
"rpcTimeoutMs": 30000
}name is treated as a base library name and mapped by OS:
- Windows:
<name>.dll - Linux:
lib<name>.so - macOS:
lib<name>.dylib
The library is searched first in the same directory as the config file (when a file path is used), then in the current working directory.
The plugin library must export both factory functions:
CreateServerDestroyServer
and return an instance implementing GraftcodeGateway::IServer. The gateway calls configure(jsonConfig, processMessage) on the plugin before start(), passing the JSON config and a callback used to process incoming messages and write responses.
The same --config value is also forwarded to the runtime transmitter configuration.
-
If Graftcode Gateway does not respond on default ports, check if the ports are not blocked by firewall or used by other applications. You can also specify custom ports using
--port,--httpPort,--tcpPort, and--http2Portoptions. Default ports may require elevated permissions on some operating systems. If you encounter permission issues, try using different ports. Default port for WebSocket is set to 80 to be easily accessible, e.g. on web applications without the need to specify port in the URL. If you are hosting a web application on the same machine, make sure to use different ports for the gateway and your application to avoid conflicts. -
If Graftcode Gateway is launched in auto mode it will try to detect the runtime based on the provided modules.
-
If
--modulesare not specified, GG will scan current directory for modules to host. If current directory contains many different files, GG may fail to detect the runtime or load modules. To fix this, specify the modules explicitly or run GG in a directory with only the relevant modules. -
If you are hosting .NET Framework runtime (CLR) and your modules target .NET Core, GG may fail to load them. Make sure to use the appropriate runtime for your modules.
-
If you are hosting Java runtime and your modules are not packaged as JAR files, GG may fail to load them. Make sure to package your Java modules as JAR files or specify the correct paths to the class files.
-
If you are hosting Python runtime and your modules have dependencies that are not installed in the Python environment, GG may fail to load them. Make sure to install all required dependencies in the Python environment before hosting the modules.
-
If you are hosting Ruby runtime and your modules have dependencies that are not installed in the Ruby environment, GG may fail to load them. Make sure to install all required dependencies in the Ruby environment before hosting the modules.
-
If you are hosting Node.js or PHP runtimes and your modules have dependencies that are not installed in that environment, GG may fail to load them. Install the required packages before hosting the modules.