[ANN] julia-mcp — persistent Julia sessions for AI assistants

I suppose you need some spec file that instructs to not change .julia this way, or at least ask for permission first. For anything other than installing packages possibly. I’m new to agentic coding, and spec files. I suppose people should collaborate on good Julia-specific spec files.

Until then, previous idea: Julia stdlib/Base was made read-only, maybe you can do the same for .julia. Except that would be bad for installing packages…

I don’t know of a good sandboxing for this, and I suppose tools like Claude Code, might also think they need to change to read/write and have that power, same as you do…

I want to try having a depot stack with a read only depot with most packages preinstalled and then a per session depot where the agent can do whatever it wants. In my experience the LLM usually ignore generic instructions if it cycles for long enough.

Here’s a julia-mcp bash script for Linux that automatically Git-clones julia-mcp, downloads uv download and starts it, isolated in a platform-specific directory. (Disclaimer: contains Gemini-generated code.)

#!/bin/bash -e

git_clone_if_missing() {
    local repo_url="$1"
    local target_dir="$2"

    if [[ -z "$repo_url" || -z "$target_dir" ]]; then
        echo "ERROR: Usage: git_clone_or_update <git_url> <target_directory>" >&2
        exit 1
    fi

    if [[ ! -d "$target_dir" ]]; then
        echo "INFO: Directory "$target_dir" does not exist. Cloning \"$repo_url\"." >&2
        git clone "$repo_url" "$target_dir"
    
    else
        echo "INFO: Directory "$target_dir" already exists." >&2
        if [[ ! -d "$target_dir/.git" ]]; then
            echo "ERROR: '$target_dir' exists but is not a git repository." >&2
            exit 1
        fi
    fi
}

install_uv_if_missing() {
    local target_bin_dir="$1"

    if [[ -z "$target_bin_dir" ]]; then
        echo "ERROR: Usage: ensure_uv_installed <bin_directory_path>" >&2
        exit 1
    fi{
	"servers": {
		"julia": {
			"type": "stdio",
			"command": "julia-mcp"
		}
	},
	"inputs": []
}

    local uv_binary="$target_bin_dir/uv"

    if [[ -f "$uv_binary" ]]; then
        echo "INFO: uv installed in \"$target_bin_dir\"." >&2
    else
        echo "INFO: uv not found in \"$target_bin_dir\". Installing..." >&2

        # Ensure the directory exists
        mkdir -p "$target_bin_dir"

        # 3. Install using the official script
        # We set UV_INSTALL_DIR so it installs to the specific target folder.
        # We set INSTALLER_NO_MODIFY_PATH=1 to prevent it from editing your .bashrc/.zshrc
        export UV_INSTALL_DIR="$target_bin_dir"
        export INSTALLER_NO_MODIFY_PATH=1
        
        if (curl -LsSf https://astral.sh/uv/install.sh | sh  >&2); then
            echo "INFO: uv successfully installed to \"$target_bin_dir\"." >&2
        else
            echo "ERROR: Failed to install uv." >&2
            exit 1
        fi
    fi
}

JLMCPDIR="$HOME/.julia-mcp-server_`uname -m`"
mkdir -p "$JLMCPDIR" && cd "$JLMCPDIR" || exit 1

git_clone_if_missing "https://github.com/aplavin/julia-mcp.git" "julia-mcp"
install_uv_if_missing "`pwd`/bin"

exec bin/uv run --directory "julia-mcp" python server.py "$@"

If you put this julia-mcp script into ~/.local/bin or so, the VS-Code mcp.json configuration file can then just be

{
	"servers": {
		"julia": {
			"type": "stdio",
			"command": "julia-mcp"
		}
	},
	"inputs": []
}

I installed and have Julia-mcp working in both VS Code and in Raycast. I’m able to call basic function such as x = rand(10). If I try to ask for a package installed, the LLM understands and says it will execute using Pkg; Pkg.add(my_package_name) but it just spins after that. I first tried with Plots, but then an easier package. This happens both with VS Code and Raycast.

Reproducible examples are welcome – something one can just run through command line with julia-mcp, without any LLMs! I might’ve seen something similar (hanging on Pkg operations), but it’s been quite rare, far from every time – so I didn’t spend time understanding if it’s just a transient issue or not.

I first asked using Julia to create 10 random numbers. That worked fine. You could see the thinking that it used julia_mcp.

Then I asked: create a lognormal distribution with mu=12 and sigma=0.5. It started thinking, said it needed to use Julia_mcp, and it needed to add the Distributions package. It just hangs at Running…

I made GitHub - nhz2/SandboxMCPRepl.jl: A Julia repl session manager for AI using Sandbox.jl as a julia app using Sandbox.jl to run each session in a sandbox.

I’ve added an example of using bubblewrap instead of Sandbox.jl to block network access: GitHub - nhz2/SandboxMCPRepl.jl: A Julia repl session manager for AI using Sandbox.jl

This should work with uv as well if you can figure out what directories to bind.

Blocking network access breaks juliaup (Julia fails to launch without network connectivity · Issue #1204 · JuliaLang/juliaup · GitHub) so you will want to install julia manually or using GitHub - abelsiqueira/jill: Command line installer of the Julia Language.

Hi. I just tried julia-mcp (with opencode).
It worked for “simple” things, but when I tried telling my llm “take this script from this file, copy-paste it into the julia repl and run it” it some times tells me that “julia mcp timed out”. I know I can run my script, so how do I debug what’s happening?
(Yes, the project is right, I tell the llm use Pkg.activate(" etc "))

MCP Error -32001: Request timed out

Other times that doesn’t happen, but on the second iteration I get

Thinking: It seems the previous code is still running: Let me restart and try again 

Both, julia-mcp and the coding harnesses have separate time-out rules; whichever is shorter counts. For example, for Codex I changed the following settings: Enhance Codex CLI instructions by scheidan · Pull Request #3 · aplavin/julia-mcp · GitHub

Not sure you have the same problem.

@freeman when I see claude experiencing timeout because it executed some long-running code, it automatically re-runs it and passes a longer timeout to the mcp. Presumably something like this should happen with opencode as well, but it doesn’t?

Hey.

Hm depends. First off, I don’t run Claude, I run Qwen 3.6. Some times it re-tries with a longer timeout, some times it tries other things (for example copy pasting chunks of the script and running the smaller chunks).

But I think there’s a bigger problem. The use case that I had in mind is that I as a human decide on the important part of the Julia session, and then give it narrow instructions within that. For example, if I know that putting the Julia session in place takes 10 minutes to create some big objects, that’s fine. What I wanted is that I do that part and then hand it over to the LLM and tell it “here’s the session, here’s what this objects mean, I would like you to investigate XYZ”. Basically I’d like to use it as a researcher that’s looking at the same objects are me and can create hypothesis and test them. And as it makes partial progress, I would like to observe what it’s doing and simultaneously manipulate the same objects myself. With julia-mcp only the agent has access to the session and I have to be asking it about the session if I want to know something.

Thoughts?

@aplavin once again hitting a home run for me - this package has made Claude Code A LOT more effective for me. Thanks again!

@freeman on timeout: what do you think can be an improvement on the julia-mcp side? It already has a configurable timeout that can be set to arbitrarily long.

On mcp + human sharing the same session: that would definitely be useful! I don’t often wish for this, but sometimes I do.
I just don’t know how to achieve that practically. The key benefit of julia-mcp is that it’s fully automatic, no daemons in the background, no cleanup or lifecycle management. How to make a Julia session one can share under this constraint, keeping everything robust and reliable, and preferably cross-platform?..

Have a look at this conversation: Best Practices for Using Coding Agents with Julia? - #6 by Satvik

I can imagine something which is like your julia-mcp but instead of sending to Julia language server, it sends to tmux.

Alternatively, perhaps keep your julia-mcp exactly as it is, but expose a reference to the LanguageServer so that the user can use the regular julia repl and attach to the LanguageServer (I’m assuming this is a feature)

This seems to be the main design goal of

(I haven’t tried.)

Points to a fork which points to Kaimon.jl :slight_smile:

This space seems to have 20 half-baked attempts at the same idea, but Kaimon seems to be the more polished one. (also I haven’t tried.)

There are quite a few attempts in this field, yes (eg, also Letting AI agents use the VSCode Julia REPL).

But I specifically highlighted the key design consideration of julia-mcp above:

In the vast majority of cases, one doesn’t want any interactive REPL, nor inspect what variables/functions the agent has there. And I want this regime to be as streamlined and smooth as possible: everything is fully automatic, no manual julia REPL startups, no background daemons, etc.

Unless I missed something, none of the linked alternatives have this. Suggestions on how to implement “join a julia-mcp session interactively” are welcome!

Currently there are three tools, julia_eval, julia_restart, and julia_list_sessions. Would it make sense to add julia_eval_script for running a complete script? Following DaemonMode.jl, you could wrap every script in its own module to prevent conflicting function definitions.

What would be the difference of julia_eval_script vs existing julia_eval with code=module MyModule <actual code> end?
I’d prefer to avoid redundancy in julia-mcp unless actually required. This specific scenario seems to be handled best by just telling your LLM in plain text that you prefer to run julia scripts in isolated modules…