Zulip Chat Archive

Stream: general

Topic: LeanRPC: Serve Lean 4 functions as RPC methods over HTTP


Oliver Dressler (Aug 04 2025 at 11:25):

With this library you can mark functions with @[rpc] to expose them as JSON-RPC endpoints via HTTP.

GitHub: https://github.com/oOo0oOo/LeanRPC

Here is an example:

import LeanRPC
import LeanSerde.SnapshotTypes

open LeanRPC.Server

-- Mark functions as RPC methods
@[rpc]
partial def collatzSequence (n : Nat) : IO (Except String (List Nat)) := do
  let rec go n acc :=
    if n == 1 then (1 :: acc).reverse
    else go (if n % 2 == 0 then n / 2 else 3 * n + 1) (n :: acc)
  if n == 0 then pure (.error "Start number must be positive")
  else pure (.ok (go n []))

-- Example for stateful methods: Simple REPL
-- Note: LeanSnapshot requires `supportInterpreter = true` in `lakefile.toml`
initialize replState : IO.Ref (Option LeanSerde.LeanSnapshot)  IO.mkRef none

@[rpc]
def repl_reset (imports : List String) : IO Bool := do
  replState.set (some ( LeanSerde.LeanSnapshot.create imports))
  pure true

@[rpc]
def repl_command (cmd : String) : IO (List String) := do
  match  replState.get with
  | none => throw (IO.userError "REPL not initialized")
  | some snapshot => do
    let snapshot'  snapshot.command cmd
    replState.set (some snapshot')
    snapshot'.goals

@[rpc]
def repl_tactic (tactic : String) : IO (List String) := do
  match  replState.get with
  | none => throw (IO.userError "REPL not initialized")
  | some snapshot => do
    let snapshot'  snapshot.tactic tactic
    replState.set (some snapshot')
    snapshot'.goals

-- Initialize the function registry
init_RPC

def main : IO Unit := do
  IO.println "Interactions to try:"
  IO.println "curl -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"collatzSequence\",\"params\":[50],\"id\":1}' http://localhost:8080\n"
  IO.println "curl -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"repl_reset\",\"params\":[[\"List.cons\", [\"Init\"]]],\"id\":2}' http://localhost:8080\n"
  IO.println "curl -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"repl_command\",\"params\":[\"theorem my_theorem : 1 + 1 = 2 := by sorry\"],\"id\":3}' http://localhost:8080\n"
  IO.println "curl -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"repl_tactic\",\"params\":[\"simp\"],\"id\":4}' http://localhost:8080\n"

  -- Start server (buildRPC is created during init_RPC)
  startRPCServer { port := 8080 } buildRPC

Any feedback, suggestions or contributions welcome!


Last updated: Dec 20 2025 at 21:32 UTC