You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add an MCP (Model Context Protocol) server inside the eudsl-llvmpy package (not a separate distribution), modeled on the existing projects/mlir-python-mcp/. It would give an LLM a persistent LLVM Python REPL so it can manipulate LLVM IR at the API level (build/inspect/transform via the bindings, run pass pipelines, JIT-execute) instead of doing textual .ll edits. This mirrors what mlir-python-mcp does for MLIR, reusing the same server shape but targeting the llvm.* API surface.
Packaging (in-package, not a sibling project)
The server ships as a submodule of the existing llvm package, alongside ast/ and dsl/:
Code under projects/eudsl-llvmpy/src/llvm/mcp/ (e.g. server.py, session.py, helpers.py), importable as llvm.mcp.
Console script wired in eudsl-llvmpy's own pyproject.toml, e.g.:
[project.scripts]
llvmpy-mcp = "llvm.mcp:main"
The mcp runtime dependency is added as an optional extra so the core bindings stay dependency-light:
installed via pip install eudsl-llvmpy[mcp]. (Reuse the same mcp<2 cap as mlir-python-mcp until the low-level decorator API is ported.)
.mcp.json points at the llvmpy-mcp script; no separate wheel to publish — it rides the eudsl-llvmpy release.
Motivation
Textual IR edits are brittle; an API-level REPL lets the model construct/mutate IR with the actual bindings and immediately verify/execute it.
eudsl-llvmpy already exposes everything a useful server needs: llvm.ir (Context/Module/parse_assembly/Value tree), llvm.passmanager (run_passes, run_default_pipeline, run_python_pass_on_module/function, register_python_pass), llvm.jit (LLJIT), llvm.types, llvm.instructions, llvm.intrinsics, and llvm.mir. The MCP server is mostly glue over these, so it belongs in the package rather than as an external consumer.
It also becomes an integration exercise for the bindings (the object-level mutation APIs, the Python-pass registration, and JIT round-trips all get driven end to end).
execute_python — run arbitrary Python in a persistent, pre-loaded namespace.
list_variables, new_session / list_sessions / delete_session — named sessions, each owning its own llvm.ir.Context.
Pipeline workflow
run_pipeline / chain_pipeline — set IR then apply a textual pass pipeline via llvm.passmanager.run_passes (and run_default_pipeline for -On); incremental lowering.
get_current_ir, rewind, history (with diffs), reset.
list_passes — enumerate available pass names (from the PassBuilder registry).
llvmpy-specific:register_python_pass + run it by name — a genuinely differentiating feature vs. MLIR (drive a Python-authored pass from the session).
Discovery
list_ir_apis (classes/functions in llvm.ir), list_type_apis (llvm.types), list_instruction_builders (llvm.instructions), list_intrinsics (llvm.intrinsics).
jit_execute — build an llvm.jit.LLJIT, add the current module, look up a symbol, and call it (the example passes already show the ctypes round-trip). MLIR's server has no direct analogue; this is a strong reason the LLVM REPL is useful.
MIR (optional, later)
llvm.mir tools (build/inspect MachineFunctions) once the core server lands.
Pre-loaded namespace
ir, passmanager, jit, types, instructions, intrinsics, a current ctx, plus helpers (new_module, parse_assembly, run_passes, find_instructions, print_function, get_module_asm, ...). Same convenience shape as the MLIR server's namespace.
Scope / non-goals
Start with IR + passes + JIT; defer MIR tools and any web UI.
Reuse mlir-python-mcp's session/history/rewind design rather than reinventing it.
Keep mcp an optional extra so importing llvm (the bindings) never pulls in the MCP stack.
Same mcp<2 cap until/unless the low-level decorator API is ported (mlir-python-mcp has the same note).
References
projects/mlir-python-mcp/ — the server to mirror (README lists the full tool set; server.py, session.py, helpers.py).
projects/eudsl-llvmpy/src/llvm/ — the package the server lives in and the API surface it wraps (ir.py, passmanager.py, jit.py, types.py, instructions.py, intrinsics.py, mir.py); sits next to the existing ast/ and dsl/ submodules.
Summary
Add an MCP (Model Context Protocol) server inside the
eudsl-llvmpypackage (not a separate distribution), modeled on the existingprojects/mlir-python-mcp/. It would give an LLM a persistent LLVM Python REPL so it can manipulate LLVM IR at the API level (build/inspect/transform via the bindings, run pass pipelines, JIT-execute) instead of doing textual.lledits. This mirrors whatmlir-python-mcpdoes for MLIR, reusing the same server shape but targeting thellvm.*API surface.Packaging (in-package, not a sibling project)
The server ships as a submodule of the existing
llvmpackage, alongsideast/anddsl/:projects/eudsl-llvmpy/src/llvm/mcp/(e.g.server.py,session.py,helpers.py), importable asllvm.mcp.eudsl-llvmpy's ownpyproject.toml, e.g.:mcpruntime dependency is added as an optional extra so the core bindings stay dependency-light:pip install eudsl-llvmpy[mcp]. (Reuse the samemcp<2cap asmlir-python-mcpuntil the low-level decorator API is ported.).mcp.jsonpoints at thellvmpy-mcpscript; no separate wheel to publish — it rides theeudsl-llvmpyrelease.Motivation
eudsl-llvmpyalready exposes everything a useful server needs:llvm.ir(Context/Module/parse_assembly/Value tree),llvm.passmanager(run_passes,run_default_pipeline,run_python_pass_on_module/function,register_python_pass),llvm.jit(LLJIT),llvm.types,llvm.instructions,llvm.intrinsics, andllvm.mir. The MCP server is mostly glue over these, so it belongs in the package rather than as an external consumer.Proposed tools (mapping mlir-python-mcp -> llvmpy)
Core REPL
execute_python— run arbitrary Python in a persistent, pre-loaded namespace.list_variables,new_session/list_sessions/delete_session— named sessions, each owning its ownllvm.ir.Context.Pipeline workflow
run_pipeline/chain_pipeline— set IR then apply a textual pass pipeline viallvm.passmanager.run_passes(andrun_default_pipelinefor-On); incremental lowering.get_current_ir,rewind,history(with diffs),reset.list_passes— enumerate available pass names (from the PassBuilder registry).register_python_pass+ run it by name — a genuinely differentiating feature vs. MLIR (drive a Python-authored pass from the session).Discovery
list_ir_apis(classes/functions inllvm.ir),list_type_apis(llvm.types),list_instruction_builders(llvm.instructions),list_intrinsics(llvm.intrinsics).IR API tools
parse_assembly->ir.Module,get_module_asm,load_ll_file/save_ll_file.walk_instructions(module -> functions -> blocks -> instructions, with an opcode-name filter),get_function_info,get_instruction_info.verify_module,clone_module.set_operand,replace_all_uses,erase_instruction(poison-safe),move_before/insert_before/insert_after,split_basic_block.Execution (llvmpy-specific)
jit_execute— build anllvm.jit.LLJIT, add the current module, look up a symbol, and call it (the example passes already show the ctypes round-trip). MLIR's server has no direct analogue; this is a strong reason the LLVM REPL is useful.MIR (optional, later)
llvm.mirtools (build/inspect MachineFunctions) once the core server lands.Pre-loaded namespace
ir,passmanager,jit,types,instructions,intrinsics, a currentctx, plus helpers (new_module,parse_assembly,run_passes,find_instructions,print_function,get_module_asm, ...). Same convenience shape as the MLIR server's namespace.Scope / non-goals
mlir-python-mcp's session/history/rewind design rather than reinventing it.mcpan optional extra so importingllvm(the bindings) never pulls in the MCP stack.mcp<2cap until/unless the low-level decorator API is ported (mlir-python-mcp has the same note).References
projects/mlir-python-mcp/— the server to mirror (README lists the full tool set;server.py,session.py,helpers.py).projects/eudsl-llvmpy/src/llvm/— the package the server lives in and the API surface it wraps (ir.py,passmanager.py,jit.py,types.py,instructions.py,intrinsics.py,mir.py); sits next to the existingast/anddsl/submodules.