Skip to main content
Glama
Joern MCP Server
by sfncat

Joern MCP Server

A simple MCP Server for Joern.

Project Introduction

This project is an MCP Server based on Joern, providing a series of features to help developers with code review and security analysis.

Related MCP server: codebadger

Environment Requirements

  • Python >= 3.10 (default 3.12) & uv

  • Joern

Installation Steps

  1. Clone the project locally:

    git clone https://github.com/sfncat/mcp-joern.git
    cd mcp-joern
  2. Install Python dependencies:

    uv venv .venv
    source .venv/bin/activate
    uv sync

Project Structure

├── server.py                       # MCP Server main program
├── test_mcp_client.py              # Test program for joern server and mcp tool
├── test_sc_tools.py                # Direct test program for sc tools
├── common_tools.py                 # Common utility functions
├── server_tools.py                 # Server utility functions
├── server_tools.sc                 # Scala implementation of server utility functions
├── server_tools_source.sc          # Scala implementation of server utility functions,use sourceCode to get the source code of method
├── requirements.txt                # Python dependency file
├── sample_cline_mcp_settings.json  # Sample cline mcp configuration file
└── env_example.txt                 # Environment variables example file

Usage

  1. Start the Joern server:

    joern -J-Xmx40G -J-XX:CompressedClassSpaceSize=1g -J-XX:MaxMetaspaceSize=2g \
          --server --server-host 127.0.0.1 --server-port 16162 \
          --server-auth-username user --server-auth-password password --import server_tools.sc
    Or
    joern -J-Xmx40G -J-XX:CompressedClassSpaceSize=1g -J-XX:MaxMetaspaceSize=2g \
          --server --server-host 127.0.0.1 --server-port 16162 \
          --server-auth-username user --server-auth-password password --import server_tools_source.sc

    Why the extra JVM flags. Both defaults are too small and only fail after prolonged use, so the breakage looks like a dead server rather than a JVM sizing problem:

    • -XX:CompressedClassSpaceSize=1g — the Joern REPL compiles one class per query (rs$line$N). The default class space (128m) is exhausted after a few thousand queries, after which every query fails with NoClassDefFoundError: Could not initialize class rs$line$NNNN.

    • -XX:MaxMetaspaceSize=2g — keeps metaspace headroom in step with the class space.

    • -J-Xmx… — size the heap for your CPG. An undersized heap shows up as queries timing out (not as an OOM). We run -Xmx60G for a ~400 MB CPG. If you are using it under Windows, you may need to set the JVM system variables through the command line or in the system environment variables.

    set _JAVA_OPTIONS=-Dfile.encoding=UTF-8

    set joern logging level to ERROR

    set SL_LOGGING_LEVEL=ERROR //windows
    export SL_LOGGING_LEVEL=ERROR //linux

    if you have the following warning

    Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)

    you can disable it by setting the environment variable

    set TERM=dumb
    export TERM=dumb

    to restore the default behavior

    set TERM=xterm-256color
    export TERM=xterm-256color
  2. Copy env_example.txt to .env Modify the configuration information to match the joern server startup configuration

  3. Run the test connection: Modify the information in test_mcp_client.py to confirm the joern server is working properly

    uv run test_mcp_client.py
    Starting MCP server test...
    ==================================================
    Testing server connection...
    [04/16/25 20:38:54] INFO     Processing request of type CallToolRequest                                                                                                                     server.py:534
    Connection test result: Successfully connected to Joern MCP, joern server version is XXX
  4. Configure MCP server Configure the mcp server in cline, refer to sample_cline_mcp_settings.json.

  5. Use MCP server Ask questions to the large language model, refer to prompts_en.md

Development Notes

  • .env file is used to store environment variables

  • .gitignore file defines files to be ignored by Git version control

  • pyproject.toml defines the Python configuration for the project

  • MCP tool development

    • Implement in server_tools.sc, add definitions in server_tools.py, and add tests in test_mcp_client.py

Contribution Guidelines

Welcome to submit Issues and Pull Requests to help improve the project.

Welcome to add more tools.

References

https://github.com/flankerhqd/jebmcp

https://docs.joern.io/server/

https://docs.joern.io/interpreter/

Change Log

v1.2.0 (2026-09-10)

Server-side call-graph tools (performance)

  • New Scala helpers in server_tools.sc: get_methods_by_name (indexed nameExact lookup, replacing full-CPG .filter(_.fullName.contains(...)) scans which time out on large CPGs), get_callee_chain (server-side BFS returning the whole call chain - method full name plus code, JDK/framework callees skipped - in one HTTP round-trip) and get_callee_chain_names (names only, no code).

  • New MCP tools exposing them: get_callee_chain_server, get_methods_by_name.

  • Effect: resolving one call chain drops from ~30 HTTP round-trips to 1.

HTTP client hardening (server.py)

  • joern_remote now uses a kept-alive requests.Session with a connection pool.

  • Retries transient failures 3 times, but fails fast on 401/403 (auth errors are not transient).

  • Returns an explicit ERROR: ... string on failure instead of None, so callers can tell a failure apart from a legitimately empty result.

Fixes

  • Credential key compatibility: the shipped .env uses USER_NAME/PASSWORD while host configs inject JOERN_AUTH_USERNAME/JOERN_AUTH_PASSWORD. Only the latter was read, so any launch without host-injected env (including the bundled test_mcp_client.py) failed with a silent 401. Both names are now accepted.

  • FastMCP compatibility: the log_level constructor argument was removed in fastmcp 2.x; it is now passed inside a try/except with a FASTMCP_LOG_LEVEL fallback.

Docs & housekeeping

  • Start command now includes -XX:CompressedClassSpaceSize=1g -XX:MaxMetaspaceSize=2g (see the note under "Start the Joern server" for why the defaults fail only after prolonged use).

  • Code comments are English only; Chinese is confined to README_cn.md and prompts_cn.md.

  • .gitignore: ignore local CPG artifacts (*.cpg), backups (*.bak-*) and the local credential-injecting run_verify.sh wrapper.

  • Version bumped to 1.2.0.

v1.3.0 (2026-09-10)

  • tests/fixture/: a self-contained Android fixture (crafted sources + build_fixture.sh) that builds a ~12 KB APK against API 36 / SDK extension level 17 and the matching CPG. Every construct that has broken the tooling before is present exactly once: a custom base receiver whose business entry is handleBroadCastReceive() (not onReceive), a 4-hop delegation chain across classes and an interface, a duplicated simple method name, an anonymous inner class, a SharedPreferences write (hd_member) at the chain end, framework calls the chain tool must skip, and a permission-gated receiver.

  • test_mcp_client.py is now an assertion-based regression gate over that fixture: it checks the chain/lookup tools, the legacy queries and the error path, and exits non-zero on failure. The ad-hoc verify_mcp.py was merged into it.

  • The fixture APK carries the same version as this package (pyproject.toml), so tests/fixture/fixture.apk and fixture.cpg are versioned together with the server.

  • Documentation and tool help no longer use the old NFC sample; they use the fixture.

  • Version 1.2.0 -> 1.3.0.

Tests

cd tests/fixture && ./build_fixture.sh --cpg   # fixture.apk + fixture.cpg
cd ../.. && uv run test_mcp_client.py          # protocol-level regression gate

Available Tools

18 tools
check_connectionB

Check if the Joern MCP plugin is running

Inputs: no named parameters.

get_call_code_by_idA

Get the source code of a specific call node from the loaded CPG by the call id

@param id: The unique identifier of the call node, the id is a Long int string, like '111669149702L'
@return: The source code of the specified call

Inputs: code_id (required).

get_calls_in_method_by_method_full_nameC

Get the calls info by the method full name which the call is in the method

@param method_full_name: The full name of the method
@return: The calls info of the method

Inputs: method_full_name (required).

get_class_full_name_by_idB

Retrieves the fully name of a class by its ID

@param id: The unique identifier of the class (typeDecl), the id is a Long int string, like '111669149702L'
@return: The fully name of the class (e.g., com.android.nfc.NfcService$6)

Inputs: class_id (required).

get_class_methods_by_class_full_nameB

Get the methods of a class by its fully qualified name

@param class_full_name: The fully qualified name of the class
@return: List of full name, name, signature and id of methods in the class

Inputs: class_full_name (required).

get_derived_classes_by_class_full_nameB

Get the derived classes of a class

@param class_full_name: The fully qualified name of the class
@return: The derived classes info of the class, including the full name, name and id

Inputs: class_full_name (required).

get_helpB

Get help information from joern server

Inputs: no named parameters.

get_method_by_call_idC

Get the method info by the call id which the call is in the method

@param id: The id of the call
@return: The method info of the call

Inputs: call_id (required).

get_method_calleesB

Retrieves a list of methods info that are called by the specified method

@param method_full_name: The fully qualified name of the source method(e.g., com.android.nfc.NfcService$6.onReceive:void(android.content.Context,android.content.Intent)) @return: List of full name, name, signature and id of methods which call the source method

Inputs: method_full_name (required).

get_method_callersA

Retrieves a list of methods that call the specified method

@param method_full_name: The fully qualified name of the source method(e.g., com.android.nfc.NfcService$6.onReceive:void(android.content.Context,android.content.Intent))
@return: List of full name, name, signature and id of methods called by the source method

Inputs: method_full_name (required).

get_method_code_by_class_full_name_and_method_nameA

Get the code of a method by its class full name and method name, this tool is usually used when you don't know the full name of the method, but you know the full name of the class and the name of the method. If there are multiple methods with the same name in the class, the code of all methods will be returned.

@param class_full_name: The fully qualified name of the class, like 'com.android.nfc.NfcService'
@param method_name: The name of the method, like 'onReceive'
@return: List of full name, name, signature and id of methods in the class

Inputs: class_full_name (required), method_name (required).

get_method_code_by_full_nameA

Get the code of a method by its fully name, If you know the full name of the method, you can use this tool to get the method code directly. If you only know the full name of the class and the name of the method, you should use get_method_code_by_class_full_name_and_method_name @param method_full_name: The fully qualified name of the method (e.g., com.android.nfc.NfcService$6.onReceive:void(android.content.Context,android.content.Intent)) @return: The source code of the specified method

Inputs: method_full_name (required).

get_method_code_by_idC

Get the code of a method by its class full name and method name

@param class_full_name: The fully qualified name of the class
@param method_name: The name of the method
@return: List of full name, name, signature and id of methods in the class

Inputs: method_id (required).

get_method_full_name_by_idA

Retrieves the fully qualified name of a method by its ID

@param id: The unique identifier of the method, the id is a Long int string, like '111669149702L'
@return: The fully qualified name of the method (e.g., com.android.nfc.NfcService$6.onReceive:void(android.content.Context,android.content.Intent))

Inputs: method_id (required).

get_parent_classes_by_class_full_nameB

Get the parent classes of a class

@param class_full_name: The fully qualified name of the class
@return: The parent classes info of the class, including the full name, name and id

Inputs: class_full_name (required).

get_referenced_method_full_name_by_call_idC

Get the method info by the call id which the call is referenced the method

@param id: The id of the call
@return: The method info of the call

Inputs: call_id (required).

load_cpgB
Loads a CPG from a file if the cpg is not loaded or the cpg is not the same as the filepath.

Args:
    cpg_filepath (str): The path to the CPG file, the filepath is absolute path.

Returns:
    str: True if the CPG is loaded successfully, False otherwise.

Inputs: cpg_filepath (required).

pingA

Checks if the Joern server is running and responsive by querying its version

@return: The Joern server version if successful, 'Query Failed' if the server is not responding

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 18 tools

    Disambiguation3/5

    The tools have clear purposes but significant overlap exists. For example, get_method_code_by_full_name, get_method_code_by_class_full_name_and_method_name, and get_method_code_by_id all retrieve method code with different input parameters, which could confuse agents about which to use. However, descriptions help clarify the distinctions, preventing complete ambiguity.

    Naming Consistency4/5

    Most tools follow a consistent verb_noun pattern (e.g., get_call_code_by_id, get_method_by_call_id), with minor deviations like check_connection and ping (which are simpler verbs). The naming is generally predictable and readable, though not perfectly uniform across all tools.

    Tool Count4/5

    With 18 tools, the count is slightly high but reasonable for a code analysis server like Joern, which needs to handle various CPG queries. It covers multiple aspects (methods, classes, calls, loading), though it might feel a bit heavy compared to more focused servers.

    Completeness5/5

    The tool set provides comprehensive coverage for querying a CPG, including loading, checking connections, and retrieving details on calls, methods, and classes with full lifecycle support (e.g., get, list, derive, parent). No obvious gaps are present for its intended domain of static code analysis.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables AI agents and LLMs to build Joern Code Property Graphs from repositories, paths, or snippets and query them over MCP for CPGQL queries, data-flow and taint tracing, program slicing, and vulnerability hunting across many languages. It scales to large analysis batches with per-CPG worker pools, memory-aware scheduling, and a Postgres/Redis backend.
      -
    • F
      license
      Not graded
      quality
      A
      maintenance
      A containerized MCP server that enables AI agents and LLMs to build and query Joern Code Property Graphs from Git repositories, local paths, or pasted snippets, exposing CPGQL queries, data-flow and taint tracing, program slicing, and vulnerability hunting across many languages. It scales to large analysis batches with worker pools, memory-aware scheduling, and a Postgres/Redis backend.
      -
    • F
      license
      Not graded
      quality
      A
      maintenance
      This MCP server builds Joern Code Property Graphs from a Git repository, local path, or pasted snippet and exposes them over MCP, letting AI agents run CPGQL queries, trace data flow and taint, slice programs, and hunt for vulnerabilities across many languages.
      -
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables AI agents and LLMs to build Joern Code Property Graphs from repositories, local paths, or snippets and query them over MCP for program analysis, data-flow and taint tracing, program slicing, and vulnerability hunting across many languages.
      -