Skip to main content
Glama
sfncat
by sfncat
README.md
[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/sfncat-mcp-joern-badge.png)](https://mseep.ai/app/sfncat-mcp-joern)

# Joern MCP Server

A simple MCP Server for Joern.

<a href="https://glama.ai/mcp/servers/@sfncat/mcp-joern">
  <img width="380" height="200" src="https://glama.ai/mcp/servers/@sfncat/mcp-joern/badge" alt="Joern Server MCP server" />
</a>

## 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.

## Environment Requirements

- Python >= 3.10 (default 3.12) & uv
- Joern

## Installation Steps

1. Clone the project locally:
   ```bash
   git clone https://github.com/sfncat/mcp-joern.git
   cd mcp-joern
   ```

2. Install Python dependencies:
   ```bash
   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:
   ```bash
   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

   ```bash
   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

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

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

ActivityMaintained
ResponsivenessNo issues